public static bool Export(string connectionString, string filename, string username) { var context = new UserStorageContext(connectionString); var user = context.Users.FirstOrDefault(u => u.Name == username); if (user == null) { Console.WriteLine(String.Format("Export: user {0} not found", username)); return false; } var userDataModel = new UserDataModel(context, user); try { filename = filename ?? @"userdata.json"; using (var stream = File.Create(filename)) using (var writer = new StreamWriter(stream)) { writer.WriteLine(userDataModel.JsonUserData); writer.Flush(); } } catch (Exception ex) { Console.WriteLine("Export: write failed; ex: ", ex.Message); return false; } return true; }
// OBSOLETE! Stamping of CompletedOn field is being done on each client to get proper timezone and immediate response. // should only be called if newItem.Complete value is true public static bool ProcessUpdateCompletedOn(UserStorageContext userContext, Item oldItem, Item newItem) { var wasComplete = oldItem.GetFieldValue(FieldNames.Complete); if (wasComplete == null || !wasComplete.Value.Equals("true", StringComparison.OrdinalIgnoreCase)) { // timestamp the CompletedOn field newItem.GetFieldValue(FieldNames.CompletedOn, true).Value = DateTime.UtcNow.ToString(); } return false; }
// OBSOLETE! Stamping of CompletedOn field is being done on each client to get proper timezone and immediate response. // should only be called if newItem.Complete value is true public static bool ProcessUpdateCompletedOn(UserStorageContext userContext, Item oldItem, Item newItem) { var wasComplete = oldItem.GetFieldValue(FieldNames.Complete); if (wasComplete == null || !wasComplete.Value.Equals("true", StringComparison.OrdinalIgnoreCase)) { // timestamp the CompletedOn field newItem.GetFieldValue(FieldNames.CompletedOn, true).Value = DateTime.UtcNow.ToString(); } return(false); }
// Factory method to create a new item processor based on the item type public static ItemProcessor Create(User user, UserStorageContext storage, Guid itemTypeID) { if (itemTypeID == SystemItemTypes.Task) return new TaskProcessor(user, storage); if (itemTypeID == SystemItemTypes.Appointment) return new AppointmentProcessor(user, storage); if (itemTypeID == SystemItemTypes.Grocery) return new GroceryProcessor(user, storage); if (itemTypeID == SystemItemTypes.Contact) return new ContactProcessor(user, storage); return null; }
public GoogleClient(User user, UserStorageContext storage) { // for using existing access token with renewal this.user = user; this.storage = storage; if (user.UserCredentials == null || user.UserCredentials.Count == 0) { // ensure UserCredentials are present this.user = storage.GetUser(user.ID, true); } UserCredential googleConsent = this.user.GetCredential(UserCredential.GoogleConsent); if (googleConsent != null) { this.googleAuthenticator = CreateGoogleAuthenticator(GetAccessToken); } }
public static bool DeleteItemChildrenRecursively(UserStorageContext storageContext, Item item) { var children = storageContext.Items.Where(i => i.ParentID == item.ID).ToList(); bool commit = false; foreach (var c in children) { DeleteItemChildrenRecursively(storageContext, c); storageContext.Items.Remove(c); commit = true; } // commit deletion of all children at the same layer together if (commit) { storageContext.SaveChanges(); } return commit; }
public static bool DeleteItemReferences(User currentUser, UserStorageContext storageContext, Item item) { string itemID = item.ID.ToString(); var itemRefs = storageContext.Items.Include("FieldValues"). Where(i => i.UserID == currentUser.ID && i.ItemTypeID == SystemItemTypes.Reference && i.FieldValues.Any(fv => fv.FieldName == FieldNames.EntityRef && fv.Value == itemID)).ToList(); bool commit = false; foreach (var itemRef in itemRefs) { storageContext.Items.Remove(itemRef); commit = true; } // commit deletion of References if (commit) { storageContext.SaveChanges(); } return commit; }
// Factory method to create a new item processor based on the item type public static ItemProcessor Create(User user, UserStorageContext storage, Guid itemTypeID) { if (itemTypeID == SystemItemTypes.Task) { return(new TaskProcessor(user, storage)); } if (itemTypeID == SystemItemTypes.Appointment) { return(new AppointmentProcessor(user, storage)); } if (itemTypeID == SystemItemTypes.Grocery) { return(new GroceryProcessor(user, storage)); } if (itemTypeID == SystemItemTypes.Contact) { return(new ContactProcessor(user, storage)); } return(null); }
/// <summary> /// Delete all workflow instances associated with this entity ID (the entity is already deleted) /// </summary> /// <param name="userContext"></param> /// <param name="suggestionsContext"></param> /// <param name="entity"></param> public static void DeleteWorkflows(UserStorageContext userContext, SuggestionsStorageContext suggestionsContext, Guid entityID) { try { // get all the workflow instances for this Item var wis = suggestionsContext.WorkflowInstances.Where(w => w.EntityID == entityID).ToList(); if (wis.Count > 0) { // loop over the workflow instances and dispatch the new message foreach (var instance in wis) { suggestionsContext.WorkflowInstances.Remove(instance); } suggestionsContext.SaveChanges(); } } catch (Exception ex) { TraceLog.TraceException("DeleteWorkflows failed", ex); } }
public static bool DataVersionCheck(out string status) { if (versionCheckStatus == null) { versionCheckStatus = string.Empty; UserStorageContext userStorage = Storage.NewUserContext; var dbSchemaVersion = userStorage.Versions.FirstOrDefault(v => v.VersionType == DatabaseVersion.Schema); var dbConstantsVersion = userStorage.Versions.FirstOrDefault(v => v.VersionType == DatabaseVersion.Constants); if (dbSchemaVersion == null || dbSchemaVersion.VersionString != UserConstants.SchemaVersion) { versionCheckStatus += string.Format("UserSchema version mismatch: Code='{0}' Database='{1}' <br/>", UserConstants.SchemaVersion, dbSchemaVersion == null ? "<none>" : dbSchemaVersion.VersionString); } if (dbConstantsVersion == null || dbConstantsVersion.VersionString != UserConstants.ConstantsVersion) { versionCheckStatus += string.Format("UserConstants version mismatch: Code='{0}' Database='{1}' <br/>", UserConstants.ConstantsVersion, dbConstantsVersion == null ? "<none>" : dbConstantsVersion.VersionString); } SuggestionsStorageContext workflowStorage = Storage.NewSuggestionsContext; dbSchemaVersion = workflowStorage.Versions.FirstOrDefault(v => v.VersionType == DatabaseVersion.Schema); dbConstantsVersion = workflowStorage.Versions.FirstOrDefault(v => v.VersionType == DatabaseVersion.Constants); if (dbSchemaVersion == null || dbSchemaVersion.VersionString != WorkflowConstants.SchemaVersion) { versionCheckStatus += string.Format("WorkflowSchema version mismatch: Code='{0}' Database='{1}' <br/>", WorkflowConstants.SchemaVersion, dbSchemaVersion == null ? "<none>" : dbSchemaVersion.VersionString); } if (dbConstantsVersion == null || dbConstantsVersion.VersionString != WorkflowConstants.ConstantsVersion) { versionCheckStatus += string.Format("WorkflowConstants version mismatch: Code='{0}' Database='{1}' <br/>", WorkflowConstants.ConstantsVersion, dbConstantsVersion == null ? "<none>" : dbConstantsVersion.VersionString); } } status = versionCheckStatus; return(versionCheckStatus.Length == 0); }
// for getting initial access and renewal tokens via OAuth handshake IAuthorizationState GetGoogleTokens(WebServerClient client) { // check if authorization request already is in progress IAuthorizationState state = client.ProcessUserAuthorization(new HttpRequestInfo(System.Web.HttpContext.Current.Request)); if (state != null && (!string.IsNullOrEmpty(state.AccessToken) || !string.IsNullOrEmpty(state.RefreshToken))) { // store refresh token string username = System.Web.HttpContext.Current.User.Identity.Name; UserStorageContext storage = Storage.NewUserContext; User user = storage.Users.Include("UserCredentials").Single <User>(u => u.Name == username); user.AddCredential(UserCredential.GoogleConsent, state.AccessToken, state.AccessTokenExpirationUtc, state.RefreshToken); storage.SaveChanges(); return(state); } // otherwise make a new authorization request OutgoingWebResponse response = client.PrepareRequestUserAuthorization(GoogleClient.Scopes); response.Headers["Location"] += "&access_type=offline&approval_prompt=force"; response.Send(); // will throw a ThreadAbortException to prevent sending another response return(null); }
/// <summary> /// Start a workflow of a certain type, passing it an entity and some instance data to start /// </summary> /// <param name="userContext"></param> /// <param name="suggestionsContext"></param> /// <param name="type">String representing the workflow type</param> /// <param name="entity">Entity to associate with the workflow</param> /// <param name="instanceData">Instance data to pass into the workflow</param> public static void StartWorkflow(UserStorageContext userContext, SuggestionsStorageContext suggestionsContext, string type, ServerEntity entity, string instanceData) { WorkflowInstance instance = null; try { Workflow workflow = null; // get the workflow definition out of the database try { var wt = suggestionsContext.WorkflowTypes.Single(t => t.Type == type); workflow = JsonSerializer.Deserialize<Workflow>(wt.Definition); } catch (Exception ex) { TraceLog.TraceException("Could not find or deserialize workflow definition", ex); return; } // don't start a workflow with no states if (workflow.States.Count == 0) return; // store the database contexts workflow.UserContext = userContext; workflow.SuggestionsContext = suggestionsContext; // create the new workflow instance and store in the workflow DB DateTime now = DateTime.Now; instance = new WorkflowInstance() { ID = Guid.NewGuid(), EntityID = entity.ID, EntityName = entity.Name, WorkflowType = type, State = workflow.States[0].Name, InstanceData = instanceData ?? "{}", Created = now, LastModified = now, LockedBy = WorkflowHost.Me, }; suggestionsContext.WorkflowInstances.Add(instance); suggestionsContext.SaveChanges(); TraceLog.TraceInfo("Starting workflow " + type); // invoke the workflow and process steps until workflow is blocked for user input or is done workflow.Run(instance, entity); // unlock the workflowinstance instance.LockedBy = null; suggestionsContext.SaveChanges(); } catch (Exception ex) { TraceLog.TraceException("StartWorkflow failed", ex); if (instance != null && instance.LockedBy == WorkflowHost.Me) { // unlock the workflowinstance instance.LockedBy = null; suggestionsContext.SaveChanges(); } } }
public AppointmentProcessor(User user, UserStorageContext storage) { this.user = user; this.storage = storage; }
/// <summary> /// Start workflows associated with a change in one or more of the entity's fields /// </summary> /// <param name="userContext"></param> /// <param name="suggestionsContext"></param> /// <param name="entity"></param> /// <param name="oldEntity"></param> public static void StartTriggerWorkflows(UserStorageContext userContext, SuggestionsStorageContext suggestionsContext, ServerEntity entity, ServerEntity oldEntity) { if (entity == null || oldEntity == null) return; // only Item property triggers are supported at this time Item item = entity as Item; Item oldItem = oldEntity as Item; if (item != null) { // go through field by field, and if a field has changed, trigger the appropriate workflow ItemType itemType = userContext.ItemTypes.Include("Fields").Single(it => it.ID == item.ItemTypeID); foreach (var field in itemType.Fields) { object newValue = item.GetFieldValue(field); object oldValue = item.GetFieldValue(field); // skip fields that haven't changed if (newValue == null || newValue.Equals(oldValue)) continue; // do field-specific processing for select fields switch (field.Name) { case FieldNames.Name: //disable for now //RestartWorkflow(userContext, suggestionsContext, item, WorkflowNames.NewTask); break; } } } }
/// <summary> /// Restart the workflows associated with an entity /// </summary> /// <param name="userContext"></param> /// <param name="suggestionsContext"></param> /// <param name="entity"></param> /// <param name="workflowType"></param> public static void RestartWorkflow(UserStorageContext userContext, SuggestionsStorageContext suggestionsContext, ServerEntity entity, string workflowType) { if (entity == null || workflowType == null) return; try { // kill all existing workflows associated with this Item // TODO: also need to mark the suggestions associated with this workflow as stale so that they don't // show up for the item again. var runningWFs = suggestionsContext.WorkflowInstances.Where(wi => wi.EntityID == entity.ID).ToList(); if (runningWFs.Count > 0) { foreach (var wf in runningWFs) suggestionsContext.WorkflowInstances.Remove(wf); suggestionsContext.SaveChanges(); } StartWorkflow(userContext, suggestionsContext, workflowType, entity, null); } catch (Exception) { StartWorkflow(userContext, suggestionsContext, workflowType, entity, null); } }
/// <summary> /// Start NewUser/NewFolder/NewItem workflows based on the entity type /// </summary> /// <param name="userContext"></param> /// <param name="suggestionsContext"></param> /// <param name="entity"></param> public static void StartNewWorkflows(UserStorageContext userContext, SuggestionsStorageContext suggestionsContext, ServerEntity entity) { if (entity == null) return; // figure out what kind of entity this is Item item = entity as Item; Folder folder = entity as Folder; User user = entity as User; // verify there are no workflow instances associated with this item yet var wis = suggestionsContext.WorkflowInstances.Where(wi => wi.EntityID == entity.ID).ToList(); if (wis.Count > 0) return; if (item != null && item.IsList == false) { if (item.ItemTypeID == SystemItemTypes.Task) StartWorkflow(userContext, suggestionsContext, WorkflowNames.NewTask, item, null); // the Contact and Grocery new item processing happens in ItemProcessor now //if (item.ItemTypeID == SystemItemTypes.Contact) // StartWorkflow(userContext, suggestionsContext, WorkflowNames.NewContact, item, null); //if (item.ItemTypeID == SystemItemTypes.Grocery) // Workflow.StartWorkflow(userContext, suggestionsContext, WorkflowNames.NewGrocery, item, null); } if (folder != null) { } if (user != null) { StartWorkflow(userContext, suggestionsContext, WorkflowNames.NewUser, user, null); } }
public ClientUserFolder(UserStorageContext storage) { this.storage = storage; }
/// <summary> /// Process the operation based on the underlying entity type and the operation type /// </summary> /// <param name="userContext"></param> /// <param name="suggestionsContext"></param> /// <param name="operation"></param> /// <returns>true if processed, false if the instance was locked and the operation needs to be replayed</returns> public static bool ProcessOperation(UserStorageContext userContext, SuggestionsStorageContext suggestionsContext, Operation operation) { if (operation == null) return true; if (userContext == null) userContext = Storage.NewUserContext; if (suggestionsContext == null) suggestionsContext = Storage.NewSuggestionsContext; Guid entityID = operation.EntityID; string entityType = operation.EntityType.Trim(); string operationType = operation.OperationType.Trim(); TraceLog.Session = operation.Session; // try to get a strongly-typed entity (item, folder, user...) ServerEntity entity = null, oldEntity = null; bool process = true; // extract the underlying entity unless this is a delete operation (in which case it's already deleted) if (operationType != "DELETE") { try { switch (entityType) { case "Item": Item item = userContext.Items.Include("FieldValues").Single(i => i.ID == entityID); Item oldItem = JsonSerializer.Deserialize<Item>(operation.OldBody); entity = item; oldEntity = oldItem; break; case "Folder": Folder folder = userContext.Folders.Single(i => i.ID == entityID); entity = folder; break; case "User": User user = userContext.Users.Single(i => i.ID == entityID); entity = user; break; case "Suggestion": // if the entity passed in is a suggestion, this is a "meta" request - get the underlying Entity's // ID and type Suggestion suggestion = suggestionsContext.Suggestions.Single(s => s.ID == entityID); entityID = suggestion.EntityID; entityType = suggestion.EntityType; switch (entityType) { case "Item": entity = userContext.Items.Include("FieldValues").Single(i => i.ID == entityID); break; case "Folder": entity = userContext.Folders.Single(i => i.ID == entityID); break; case "User": entity = userContext.Users.Single(i => i.ID == entityID); break; } operationType = "SUGGESTION"; break; default: TraceLog.TraceError("Invalid Entity Type " + entityType); process = false; break; } } catch (Exception ex) { TraceLog.TraceException(String.Format("Could not retrieve {0}", entityType), ex); process = false; } } // launch new workflows based on the changes to the item if (process) { switch (operationType) { case "DELETE": DeleteWorkflows(userContext, suggestionsContext, entityID); return true; case "POST": StartNewWorkflows(userContext, suggestionsContext, entity); return ExecuteWorkflows(userContext, suggestionsContext, entity); case "PUT": StartTriggerWorkflows(userContext, suggestionsContext, entity, oldEntity); return ExecuteWorkflows(userContext, suggestionsContext, entity); case "SUGGESTION": return ExecuteWorkflows(userContext, suggestionsContext, entity); default: TraceLog.TraceError("Invalid Operation Type " + operationType); return true; } } return true; }
public ServerUserFolder(UserStorageContext storage) { this.storage = storage; }
// update constants in User database to current version defined in EntityConstants public bool VersionConstants(string me) { try { bool updateDB = false; if (Versions.Any(v => v.VersionType == DatabaseVersion.Constants && v.VersionString == UserConstants.ConstantsVersion) == false) { // no database - create and lock the new version entry TraceLog.TraceInfo(String.Format("User database version {0} not found", UserConstants.ConstantsVersion)); // remove an existing database version (there should never be more than one) foreach (var existingVersion in Versions.Where(v => v.VersionType == DatabaseVersion.Constants).ToList()) { Versions.Remove(existingVersion); } SaveChanges(); // create the new version entry DatabaseVersion ver = new DatabaseVersion() { VersionType = DatabaseVersion.Constants, VersionString = UserConstants.ConstantsVersion, Status = me }; Versions.Add(ver); SaveChanges(); updateDB = true; } else { var dbVersion = Versions.Single(v => v.VersionType == DatabaseVersion.Constants && v.VersionString == UserConstants.ConstantsVersion); if (dbVersion.Status == DatabaseVersion.Corrupted) { // try to update the database again - take a lock TraceLog.TraceInfo("User database corrupted"); dbVersion.Status = me; SaveChanges(); updateDB = true; } } if (updateDB == false) { TraceLog.TraceInfo(String.Format("User database version {0} is up to date", UserConstants.ConstantsVersion)); return(true); } } catch (Exception ex) { TraceLog.TraceException("Could not find database version", ex); return(false); } // update the default database values DatabaseVersion version = null; UserStorageContext versionContext = Storage.NewUserContext; try { // verify that this unit of execution owns the update lock for the database version version = versionContext.Versions.Single(v => v.VersionType == DatabaseVersion.Constants && v.VersionString == UserConstants.ConstantsVersion); if (version.Status != me) { return(true); } TraceLog.TraceInfo(String.Format("{0} updating User datatbase to version {1}", me, UserConstants.ConstantsVersion)); // update existing action types, add new action types foreach (var entity in UserConstants.DefaultActionTypes()) { if (ActionTypes.Any(e => e.ActionTypeID == entity.ActionTypeID)) { ActionTypes.Single(e => e.ActionTypeID == entity.ActionTypeID).Copy(entity); } else { ActionTypes.Add(entity); } } SaveChanges(); TraceLog.TraceInfo("Replaced action types"); // update existing colors, add new colors foreach (var entity in UserConstants.DefaultColors()) { if (Colors.Any(e => e.ColorID == entity.ColorID)) { Colors.Single(e => e.ColorID == entity.ColorID).Copy(entity); } else { Colors.Add(entity); } } SaveChanges(); TraceLog.TraceInfo("Replaced colors"); // update existing permissions, add new permissions foreach (var entity in UserConstants.DefaultPermissions()) { if (Permissions.Any(e => e.PermissionID == entity.PermissionID)) { Permissions.Single(e => e.PermissionID == entity.PermissionID).Copy(entity); } else { Permissions.Add(entity); } } SaveChanges(); TraceLog.TraceInfo("Replaced permissions"); // update existing priorities, add new priorities foreach (var entity in UserConstants.DefaultPriorities()) { if (Priorities.Any(e => e.PriorityID == entity.PriorityID)) { Priorities.Single(e => e.PriorityID == entity.PriorityID).Copy(entity); } else { Priorities.Add(entity); } } SaveChanges(); TraceLog.TraceInfo("Replaced priorities"); // update existing or add new built-in users foreach (var user in UserConstants.DefaultUsers()) { if (Users.Any(u => u.ID == user.ID)) { var existing = Users.Single(u => u.ID == user.ID); existing.Name = user.Name; existing.Email = user.Email; existing.CreateDate = user.CreateDate; } else { Users.Add(user); } } SaveChanges(); TraceLog.TraceInfo("Replaced users"); // update existing or add new built-in itemtypes and fields foreach (var itemType in UserConstants.DefaultItemTypes()) { if (ItemTypes.Any(it => it.ID == itemType.ID)) { var existing = ItemTypes.Include("Fields").Single(it => it.ID == itemType.ID); existing.Copy(itemType); if (itemType.Fields == null) { continue; } foreach (var field in itemType.Fields) { if (existing.Fields.Any(f => f.ID == field.ID)) { var existingField = existing.Fields.Single(f => f.ID == field.ID); existingField.Copy(field); } else { existing.Fields.Add(field); } } } else { ItemTypes.Add(itemType); } } SaveChanges(); TraceLog.TraceInfo("Replaced item types and fields"); // save the new version number version.Status = DatabaseVersion.OK; versionContext.SaveChanges(); return(true); } catch (Exception ex) { TraceLog.TraceException("VersionConstants failed", ex); // mark the version as corrupted version.Status = DatabaseVersion.Corrupted; versionContext.SaveChanges(); return(false); } }
public UserDataModel(BaseResource resource) { this.storageContext = resource.StorageContext; this.currentUser = resource.CurrentUser; }
public static bool Import(string connectionString, string filename, string username) { var context = new UserStorageContext(connectionString); var user = context.Users. Include("ItemTypes.Fields"). Include("Tags"). FirstOrDefault(u => u.Name == username); if (user == null) { Console.WriteLine(String.Format("Import: user {0} not found", username)); return false; } // get the folders List<Folder> folders = context.Folders. Include("FolderUsers"). Include("Items.ItemTags"). Include("Items.FieldValues"). Where(f => f.UserID == user.ID && f.ItemTypeID != SystemItemTypes.System). ToList(); var userDataModel = new UserDataModel(context, user); try { User jsonUser = null; filename = filename ?? @"userdata.json"; // read the file and deserialize the data into a User class using (var stream = System.IO.File.Open(filename, FileMode.Open, FileAccess.Read)) using (var reader = new StreamReader(stream)) { var json = reader.ReadToEnd(); jsonUser = JsonSerializer.Deserialize<User>(json); } // reorder the folders by item type ID - this is to get locations before contacts before tasks // this heuristic relies on that order so that a task's location and contact references will be live in the DB before the task is imported // likewise, it needs the locations to be live in the DB before a contact (which may point to a location) is imported var jsonFolders = new List<Folder>(); foreach (var jsonFolder in jsonUser.Folders.Where(f => f.ItemTypeID == SystemItemTypes.Location)) jsonFolders.Add(jsonFolder); foreach (var jsonFolder in jsonUser.Folders.Where(f => f.ItemTypeID == SystemItemTypes.Contact)) jsonFolders.Add(jsonFolder); foreach (var jsonFolder in jsonUser.Folders.Where(f => f.ItemTypeID == SystemItemTypes.Grocery)) jsonFolders.Add(jsonFolder); foreach (var jsonFolder in jsonUser.Folders.Where(f => f.ItemTypeID == SystemItemTypes.ListItem)) jsonFolders.Add(jsonFolder); foreach (var jsonFolder in jsonUser.Folders.Where(f => f.ItemTypeID == SystemItemTypes.Task)) jsonFolders.Add(jsonFolder); foreach (var jsonFolder in jsonUser.Folders.Where(f => f.ItemTypeID == SystemItemTypes.Appointment)) jsonFolders.Add(jsonFolder); // process the serialized user folders foreach (var jsonFolder in jsonFolders) { // skip the $PhoneClient folder (currently import does not support merging $PhoneClient) // the difficulty is in merge semantics for individual items which have substructure (like PhoneSettings), // as well as ListMetadata for lists/folders that have the same names, but different ID's, from the lists in the DB // (e.g. Tasks, Groceries) if (jsonFolder.Name == SystemEntities.PhoneClient || jsonFolder.Name == SystemEntities.Client || jsonFolder.Name == SystemEntities.WebClient) continue; // reset some of the fields in the serialized structure to the database values jsonFolder.UserID = user.ID; // find the folder by name var folder = folders.FirstOrDefault(f => f.Name == jsonFolder.Name); if (folder == null) { // folder not found - add it (including all its children) using a new ID (in case the old one still exists in the DB) jsonFolder.ID = Guid.NewGuid(); folder = context.Folders.Add(jsonFolder); context.SaveChanges(); Console.WriteLine("Added folder " + folder.Name); } else { // folder found - don't add it, but process all the children and add as appropriate to the found folder Console.WriteLine("Found folder " + folder.Name); var rootChildren = jsonFolder.Items.Where(i => i.ParentID == null).ToList(); ImportItems(context, folder, jsonFolder, rootChildren, null, 1); } } context.SaveChanges(); Console.WriteLine(); } catch (Exception ex) { Console.WriteLine("DataImporter: import failed; ex: ", ex.Message); return false; } return true; }
static void ImportItems(UserStorageContext context, Folder folder, Folder jsonFolder, List<Item> jsonItems, Guid? parentID, int level) { // process each of the items passed in foreach (var jsonItem in jsonItems) { // reset some of the fields in the serialized structure to the database values jsonItem.UserID = folder.UserID; jsonItem.FolderID = folder.ID; // get the children of the current item from the serialized folder var jsonChildren = jsonFolder.Items.Where(i => i.ParentID == jsonItem.ID).ToList(); if (jsonChildren.Count > 0 || jsonItem.IsList) { // process the item as a list - find the database list by name var list = folder.Items.FirstOrDefault(i => i.Name == jsonItem.Name && i.ParentID == parentID); if (list != null) { // list found in database - change the ID of the serialized list to match the database for (int i = 0; i < level; i++) Console.Write(" "); Console.Write(jsonItem.IsList ? "Found list: " : "Found item: "); Console.WriteLine(jsonItem.Name); jsonItem.ID = list.ID; } else { // list not found in database - add the list to the DB using a new ID (in case the old one still exists in the DB) var id = Guid.NewGuid(); NewID[jsonItem.ID] = id; jsonItem.ID = id; list = context.Items.Add(jsonItem); context.SaveChanges(); for (int i = 0; i < level; i++) Console.Write(" "); Console.Write(jsonItem.IsList ? "Added list: " : "Added item: "); Console.WriteLine(jsonItem.Name); } // fix the parent ID's for all the children foreach (var i in jsonChildren) i.ParentID = jsonItem.ID; // recursively import this list's children ImportItems(context, folder, jsonFolder, jsonChildren, jsonItem.ID, level + 1); // fix any fieldvalues that are pointing to old guids foreach (var fv in jsonItem.FieldValues) { Guid guid; if (Guid.TryParse(fv.Value, out guid)) { Guid newID; if (NewID.TryGetValue(new Guid(fv.Value), out newID)) fv.Value = newID.ToString(); } } context.SaveChanges(); } else { // this is a singleton (not a list) - add it to the DB using a new ID (in case the old one still exists in the DB) var id = Guid.NewGuid(); NewID[jsonItem.ID] = id; // if this is a reference, fix the ref ID if (jsonItem.ItemTypeID == SystemItemTypes.Reference) { var refID = jsonItem.GetFieldValue(FieldNames.EntityRef); if (refID != null && !String.IsNullOrEmpty(refID.Value)) { Guid newID; if (NewID.TryGetValue(new Guid(refID.Value), out newID)) refID.Value = newID.ToString(); } } jsonItem.ID = id; context.Items.Add(jsonItem); context.SaveChanges(); for (int i = 0; i < level; i++) Console.Write(" "); Console.WriteLine("Added item " + jsonItem.Name); } } }
/// <summary> /// Execute the workflow instances associated with this entity /// </summary> /// <param name="entity"></param> /// <param name="userContext"></param> /// <param name="suggestionsContext"></param> /// <returns>true if processing happened (and the operation doesn't need to be processed again), /// false if one the workflow instances was locked (causes the message to be reprocessed)</returns> public static bool ExecuteWorkflows(UserStorageContext userContext, SuggestionsStorageContext suggestionsContext, ServerEntity entity) { if (entity == null) return true; List<WorkflowInstance> wis = null; try { // get all the workflow instances for this Item wis = suggestionsContext.WorkflowInstances.Where(w => w.EntityID == entity.ID).ToList(); if (wis.Count > 0) { // if the instance is locked by someone else, stop processing // otherwise lock each of the workflow instances foreach (var instance in wis) { if (instance.LockedBy != null && instance.LockedBy != Me) return false; instance.LockedBy = Me; } suggestionsContext.SaveChanges(); // reacquire the lock list and verify they were all locked by Me (if not, stop processing) // projecting locks and not workflow instances to ensure that the database's lock values are returned (not from EF's cache) var locks = suggestionsContext.WorkflowInstances.Where(w => w.EntityID == entity.ID).Select(w => w.LockedBy).ToList(); foreach (var lockedby in locks) if (lockedby != Me) return false; // loop over the workflow instances and dispatch the new message foreach (var instance in wis) { Workflow workflow = null; try { var wt = suggestionsContext.WorkflowTypes.Single(t => t.Type == instance.WorkflowType); workflow = JsonSerializer.Deserialize<Workflow>(wt.Definition); } catch (Exception ex) { TraceLog.TraceException("Could not find or deserialize workflow definition", ex); continue; } // set the database contexts workflow.UserContext = userContext; workflow.SuggestionsContext = suggestionsContext; // invoke the workflow and process steps until workflow is blocked for user input or is done workflow.Run(instance, entity); } } return true; } catch (Exception ex) { TraceLog.TraceException("ExecuteWorkflows failed", ex); return true; } finally { // find and unlock all remaining workflow instances that relate to this entity // note that a new context is used for this - to avoid caching problems where the current thread // believes it is the owner but the database says otherwise. var context = Storage.NewSuggestionsContext; wis = context.WorkflowInstances.Where(w => w.EntityID == entity.ID).ToList(); if (wis.Count > 0) { // unlock each of the workflow instances foreach (var instance in wis) if (instance.LockedBy == Me) instance.LockedBy = null; context.SaveChanges(); } } }
public UserDataModel(UserStorageContext storage, User user) { this.storageContext = storage; this.currentUser = user; }
public UserDataModel(BaseController controller) { this.storageContext = controller.StorageContext; this.currentUser = controller.CurrentUser; }
public TaskProcessor(User user, UserStorageContext storage) { this.user = user; this.storage = storage; }
static User LookupUserByName(string username, bool includeCredentials = false, UserStorageContext storage = null) { username = username.ToLower(); if (storage == null) { storage = Storage.NewUserContext; } if (storage.Users.Any<User>(u => u.Name == username)) { if (includeCredentials) { return storage.Users.Include("UserCredentials").Single<User>(u => u.Name == username); } else { return storage.Users.Single<User>(u => u.Name == username); } } return null; }
/// <summary> /// Invoke the workflows for an operation depending on the environment. /// If in Azure, enqueue a message; otherwise, invoke the workflow host directly. /// </summary> /// <param name="userContext"></param> /// <param name="suggestionsContext"></param> /// <param name="operation"></param> public static void InvokeWorkflowForOperation(UserStorageContext userContext, SuggestionsStorageContext suggestionsContext, Operation operation) { if (HostEnvironment.IsAzure) MessageQueue.EnqueueMessage(operation.ID); else ProcessOperation(userContext, suggestionsContext, operation); }