/// <summary> /// Execute a transaction (list of requests) from a client /// </summary> /// <param name="requestId"></param> /// <param name="label"></param> /// <param name="requests"></param> /// <param name="transaction"></param> /// <param name="notify">true if the notification must be sent to the caller</param> /// <returns>RequestId, Error, Record</returns> private JObject ExecuteTransaction(int requestId, JObject label, JObject[] requests, bool transaction, bool notify) { int index = 0; if (!Context.Request.User.Identity.IsAuthenticated) { // Lost the session for unconnecting period ... all changes into the client is definitively lost ... reload the page Error($"The user is not authenticated ... Reload the page!"); return(MakeErrorResult("EN", "ERR_UNAUTHENTICATED")); } try { // nothing to execute => Throw an error if (requests == null || requests.Length == 0) { Error("No requests to execute"); throw new ExceptionDefinitionRecord("ERR_REQUEST_UNKNOWN"); } Info($"Executing the transaction [{requestId} - '{label.ToString(Formatting.None)}'] containing {requests.Length} requests ..."); if (IsDebug()) { foreach (JObject request in requests) { Debug($"Executing the request: {request.ToString(Formatting.None)} ..."); } } // Check if the request is correctly formatted index = 0; foreach (JObject request in requests) { // convert the request property string table = null; if (request["table"] != null && request["table"].Type == JTokenType.String) { table = request["table"].ToObject <string>(); } string action = null; if (request["action"] != null && request["action"].Type == JTokenType.String) { action = request["action"].ToObject <string>(); } JObject identity = request["identity"] as JObject; if (table == null || action == null || !(request["record"] is JObject record) || action == null) { Error($"The request[{index}] isn't correctly formatted!"); throw new ExceptionDefinitionRecord("ERR_UNAUTHORIZED"); } index++; } // From the current user, check if the user can update database using (DatabaseManager requester = Syncytium.Managers.DatabaseManager.CreateDatabase(Context.ConnectionId, int.Parse(Context.Request.User.Identity.Name))) { // Get the current connection properties ConnectionRecord currentConnection = requester.Database._Connection.FirstOrDefault(c => c.ConnectionId.Equals(Context.ConnectionId) && c.Machine.Equals(Environment.MachineName)); if (currentConnection == null) { Error($"The connection '{Context.ConnectionId}' doesn't exist!"); throw new ExceptionDefinitionRecord("ERR_CONNECTION"); } // Is this connection authorized to start the dialog ? if (!currentConnection.Allow || !currentConnection.Status) { Error("Not allowed!"); throw new ExceptionDefinitionRecord("ERR_UNAUTHORIZED"); } // check if the user has the rights to execute this request if (String.IsNullOrWhiteSpace(currentConnection.Area)) { Error("No area defined for the user"); throw new ExceptionDefinitionRecord("ERR_UNAUTHORIZED"); } if (ConfigurationManager.Schemas[currentConnection.Area] == null) { Error($"The schema of the module '{currentConnection.Area}' doesn't exist!"); throw new ExceptionDefinitionRecord("ERR_SCHEMA"); } // Retrieve the last requestId of this user RequestIdRecord requestIdRecord = requester.Database._RequestId.FirstOrDefault(r => r.UserId == currentConnection.UserId); if (requestIdRecord == null) { requestIdRecord = new RequestIdRecord { UserId = currentConnection.UserId, RequestId = 0, Date = DateTime.Now }; requestIdRecord = requester.Database._RequestId.Add(requestIdRecord); } if (requestId < requestIdRecord.RequestId) { Warn($"The request '{requestId}' has already been executed!"); throw new ExceptionDefinitionRecord("ERR_REQUEST_ALREADY_EXECUTED"); } if (requestId > requestIdRecord.RequestId) { Warn($"The request id expected is '{requestIdRecord.RequestId}' (your request id is '{requestId}')!"); throw new ExceptionDefinitionRecord("ERR_SYNCHRONIZED"); } if (IsVerbose()) { Verbose($"The request Id '{requestId}' is expected"); } // Post the event into the event queue DatabaseQueue.Instance.Produce(currentConnection, requestId, label, requests, transaction, notify); // Update last connection date and the last requestId of the user requestIdRecord.RequestId++; currentConnection.ConnectionLast = DateTime.Now; try { requester.Database.SaveChanges(); } catch (System.Data.Entity.Infrastructure.DbUpdateConcurrencyException) { Warn("An exception occurs on saving the last connection due to the disconnection of the user ..."); } catch (System.Data.Entity.Infrastructure.DbUpdateException) { Warn("An exception occurs on saving the last connection due to the concurrency update ..."); } JObject result = null; if (transaction) { result = new JObject { ["RequestId"] = requestId, ["Transaction"] = new JArray(requests) }; } else { result = new JObject { ["RequestId"] = requestId, ["Record"] = requests[0]["record"] }; } return(result); } } catch (ExceptionDefinitionRecord ex) { Error($"The transaction '{requestId}' can't be executed due to some errors ({JsonConvert.SerializeObject(ex.Errors)})"); return(MakeErrorResult(requestId, ex.Errors)); } catch (System.Exception ex) { Exception("An exception occurs on executing the transaction", ex); return(MakeErrorResult(requestId, "ERR_EXCEPTION_UNEXPECTED")); } }
/// <summary> /// The client starts the initialization process and has to declare its area /// </summary> /// <param name="area"></param> /// <param name="moduleId"></param> /// <returns>the database schema correspnding to the user's profile and its area: /// Version = database version /// Schema = database schema /// DefaultLanguage = default language (user's language or default language of the application) /// User = user's profile /// LastRequestId = last request id of the user /// </returns> public JObject Initialize(string area, int moduleId) { string defaultLanguage = "EN"; int versionDatabase = 0; int lastRequestId = 0; IUser user = null; IModule module = null; Info($"Initializing connection within the area '{area}' ({moduleId}) ..."); if (_userManager == null) { Error("Unable to open the connection. UserManager is undefined!"); throw new ExceptionDefinitionRecord("ERR_CONNECTION"); } // Retrieve database information defaultLanguage = ConfigurationManager.DefaultLanguage; ParameterRecord parameterVersion = Database._Parameter.FirstOrDefault(p => p.Key.Equals("Database.Version")); if (parameterVersion != null) { versionDatabase = int.Parse(parameterVersion.Value); } // Retrieve the current user and its language user = _userManager.GetById(_userId); if (user == null) { Warn("The user doesn't exist!"); throw new ExceptionDefinitionRecord("ERR_CONNECTION"); } module = _userManager.GetModule(user, moduleId); if (module == null) { Warn("The module doesn't exist!"); throw new ExceptionDefinitionRecord("ERR_CONNECTION"); } // Retrieve the connection ConnectionRecord currentConnection = Database._Connection.FirstOrDefault(c => c.ConnectionId.Equals(_connectionId) && c.Machine.Equals(Environment.MachineName)); if (currentConnection == null) { Warn("The connection doesn't exist. Open the new connection!"); throw new ExceptionDefinitionRecord("ERR_CONNECTION"); } // Retrieve the database schema DSSchema.DSDatabase schema = ConfigurationManager.Schemas[area]; if (schema == null) { Error("No schema available!"); throw new ExceptionDefinitionRecord("ERR_SCHEMA"); } // Is this connection authorized to start the dialog ? if (!currentConnection.Allow) { Error("Not allowed!"); throw new ExceptionDefinitionRecord("ERR_UNAUTHORIZED"); } // Retrieve the last requestId of this user RequestIdRecord requestId = Database._RequestId.FirstOrDefault(r => r.UserId == _userId); if (requestId != null) { lastRequestId = requestId.RequestId; } // Set the area of the connection and notify that the connection is initialized currentConnection.Area = area; currentConnection.ModuleId = module.Id; currentConnection.Profile = module.Profile; currentConnection.Status = true; currentConnection.ConnectionLast = DateTime.Now; Database.SaveChanges(); Info($"The connection '{currentConnection}' is linked to the area '{area}'"); // define the response JObject result = new JObject { ["Version"] = versionDatabase, ["Schema"] = schema.ToJSON(area, currentConnection.Profile, Database.GetCache(schema)), ["DefaultLanguage"] = defaultLanguage, ["CurrentUserId"] = user == null ? -1 : user.Id, ["CurrentModuleId"] = moduleId, ["LastRequestId"] = lastRequestId }; JObject settings = new JObject(); foreach (KeyValuePair <string, string> setting in ConfigurationManager.Settings) { if (!setting.Key.StartsWith("Syncytium.Client.")) { continue; } settings[setting.Key.Substring("Syncytium.Client.".Length)] = setting.Value; } result["Parameters"] = settings; return(result); }