/// <summary> /// Deletes the support queue with the ID specified. /// </summary> /// <param name="queueID">The queue ID of the queue to delete.</param> /// <returns>true if succeeded, false otherwise</returns> /// <remarks>All threads in the queue are automatically de-queued and not in a queue anymore. The Default support queue /// for forums which have this queue as the default support queue is reset to null.</remarks> public static bool DeleteSupportQueue(int queueID) { // we'll do several actions in one atomic transaction, so start a transaction first. Transaction trans = new Transaction(IsolationLevel.ReadCommitted, "DeleteSupportQ"); try { // first reset all the FKs in Forum to NULL if they point to this queue. ForumEntity forumUpdater = new ForumEntity(); // set the field to NULL. This is a nullable field, so we can just set the field to 'null', thanks to nullable types. forumUpdater.DefaultSupportQueueID = null; // update the entities directly in the db, use a forum collection for that ForumCollection forums = new ForumCollection(); trans.Add(forums); // specify a filter that only the forums which have this queue as the default queue are updated and have their FK field set to NULL. forums.UpdateMulti(forumUpdater, (ForumFields.DefaultSupportQueueID == queueID)); // delete all SupportQueueThread entities which refer to this queue. This will make all threads which are in this queue become queue-less. SupportQueueThreadCollection supportQueueThreads = new SupportQueueThreadCollection(); trans.Add(supportQueueThreads); // delete them directly from the db. supportQueueThreads.DeleteMulti((SupportQueueThreadFields.QueueID == queueID)); // it's now time to delete the actual supportqueue entity. SupportQueueCollection supportQueues = new SupportQueueCollection(); trans.Add(supportQueues); // delete it directly from the db. int numberOfQueuesDeleted = supportQueues.DeleteMulti((SupportQueueFields.QueueID == queueID)); // done so commit the transaction. trans.Commit(); return (numberOfQueuesDeleted > 0); } catch { // first roll back the transaction trans.Rollback(); // then bubble up the exception throw; } finally { trans.Dispose(); } }
/// <summary> /// Marks the thread as un-done, and add it to the default queue of the forum. /// </summary> /// <param name="threadID">Thread ID</param> /// <returns></returns> public static bool UnMarkThreadAsDone(int threadID, int userID) { // load the entity from the database ThreadEntity thread = ThreadGuiHelper.GetThread(threadID); if (thread == null) { // not found return false; } thread.MarkedAsDone = false; ForumEntity forum = new ForumEntity(thread.ForumID); // Save the thread and add it to the default queue of the forum. Transaction trans = new Transaction(IsolationLevel.ReadCommitted, "MarkThreadUnDone"); trans.Add(thread); try { thread.Save(); if ((forum.Fields.State == EntityState.Fetched) && (forum.DefaultSupportQueueID.HasValue)) { // not in a queue, and the forum has a default queue. Add the thread to the queue of the forum SupportQueueManager.AddThreadToQueue(threadID, forum.DefaultSupportQueueID.Value, userID, trans); } trans.Commit(); return true; } catch { // rollback transaction trans.Rollback(); throw; } finally { trans.Dispose(); } }
/// <summary> /// Creates a new message in the given thread /// Caller should validate input parameters. /// </summary> /// <param name="threadID">Thread wherein the new message will be placed</param> /// <param name="userID">User who posted this message</param> /// <param name="messageText">Message text</param> /// <param name="messageAsHTML">Message text as HTML</param> /// <param name="userIDIPAddress">IP address of user calling this method</param> /// <param name="messageAsXML">Message text as XML, which is the result of the parse action on MessageText.</param> /// <param name="subscribeToThread">if set to <c>true</c> [subscribe to thread].</param> /// <param name="threadUpdatedNotificationTemplate">The thread updated notification template.</param> /// <param name="emailData">The email data.</param> /// <param name="sendReplyNotifications">Flag to signal to send reply notifications. If set to false no notifications are mailed, /// otherwise a notification is mailed to all subscribers to the thread the new message is posted in</param> /// <returns>MessageID if succeeded, 0 if not.</returns> public static int CreateNewMessageInThread(int threadID, int userID, string messageText, string messageAsHTML, string userIDIPAddress, string messageAsXML, bool subscribeToThread, string threadUpdatedNotificationTemplate, Dictionary<string,string> emailData, bool sendReplyNotifications) { Transaction trans = new Transaction(IsolationLevel.ReadCommitted, "InsertNewMessage"); int messageID = 0; try { DateTime postingDate = DateTime.Now; messageID = InsertNewMessage(threadID, userID, messageText, messageAsHTML, userIDIPAddress, messageAsXML, trans, postingDate); MessageManager.UpdateStatisticsAfterMessageInsert(threadID, userID, trans, postingDate, true, subscribeToThread); trans.Commit(); } catch(Exception) { trans.Rollback(); throw; } finally { trans.Dispose(); } if(sendReplyNotifications) { // send notification email to all subscribers. Do this outside the transaction so a failed email send action doesn't terminate the save process // of the message. ThreadManager.SendThreadReplyNotifications(threadID, userID, threadUpdatedNotificationTemplate, emailData); } return messageID; }
/// <summary> /// Deletes the given Thread from the system, including <b>all</b> messages and related data in this Thread. /// </summary> /// <param name="ID">Thread to delete.</param> /// <returns>True if succeeded, false otherwise</returns> public static bool DeleteThread(int threadID) { // trying to delete the entity directly from the database without first loading it. // for that we use an entity collection and use the DeleteMulti method with a filter on the PK. PredicateExpression threadFilter = new PredicateExpression(ThreadFields.ThreadID == threadID); Transaction trans = new Transaction(IsolationLevel.ReadCommitted, "DeleteThread"); try { DeleteThreads(threadFilter, trans); trans.Commit(); return true; } catch { // error occured trans.Rollback(); throw; } finally { trans.Dispose(); } }
/// <summary> /// Marks the thread as done. /// </summary> /// <param name="threadID">Thread ID.</param> /// <returns></returns> public static bool MarkThreadAsDone(int threadID) { // load the entity from the database ThreadEntity thread = ThreadGuiHelper.GetThread(threadID); if(thread == null) { // not found return false; } // get the support queue the thread is in (if any) SupportQueueEntity containingSupportQueue = SupportQueueGuiHelper.GetQueueOfThread(threadID); thread.MarkedAsDone = true; // if the thread is in a support queue, the thread has to be removed from that queue. This is a multi-entity action and therefore we've to start a // transaction if that's the case. If not, we can use the easy route and simply save the thread and be done with it. if(containingSupportQueue == null) { // not in a queue, simply save the thread. return thread.Save(); } // in a queue, so remove from the queue and save the entity. Transaction trans = new Transaction(IsolationLevel.ReadCommitted, "MarkThreadDone"); trans.Add(thread); try { // save the thread bool result = thread.Save(); if(result) { // save succeeded, so remove from queue, pass the current transaction to the method so the action takes place inside this transaction. SupportQueueManager.RemoveThreadFromQueue(threadID, trans); } trans.Commit(); return true; } catch { // rollback transaction trans.Rollback(); throw; } finally { trans.Dispose(); } }
/// <summary> /// Deletes the user with the ID passed in. Will reset all posts made by the user to the userid 0. /// </summary> /// <param name="userID">The user ID.</param> /// <remarks>Can't delete user 0</remarks> /// <returns>true if succeeded, false otherwise</returns> public static bool DeleteUser(int userID) { if(userID == 0) { // can't delete the Anonymous coward user. return false; } UserEntity toDelete = UserGuiHelper.GetUser(userID); if(toDelete==null) { // user doesn't exist return false; } // all actions have to take place in a transaction. Transaction trans = new Transaction(IsolationLevel.ReadCommitted, "DeleteUser"); try { // we'll first update all PostedByUserId fields of all messages which are posted by the user to delete. MessageEntity messageUpdater = new MessageEntity(); messageUpdater.PostedByUserID = 0; // reset to AC. MessageCollection messages = new MessageCollection(); trans.Add(messages); // add to the transaction // update all entities directly in the DB, which match the following filter and update them with the new values set in messageUpdater. messages.UpdateMulti(messageUpdater, (MessageFields.PostedByUserID == userID)); // set the startuser of threads started by this user to 0 ThreadEntity threadUpdater = new ThreadEntity(); threadUpdater.StartedByUserID = 0; ThreadCollection threads = new ThreadCollection(); trans.Add(threads); threads.UpdateMulti(threadUpdater, (ThreadFields.StartedByUserID == userID)); // remove the user from the UserRoles set, as the user shouldn't be in any roles. RoleUserCollection roleUsersDeleter = new RoleUserCollection(); trans.Add(roleUsersDeleter); // delete all entities directly from the DB which match the following filter. roleUsersDeleter.DeleteMulti(RoleUserFields.UserID == userID); // delete all bookmarks of user BookmarkCollection bookmarkDeleter = new BookmarkCollection(); trans.Add(bookmarkDeleter); // delete all bookmarks for this user directly from the DB using the following filter. bookmarkDeleter.DeleteMulti(BookmarkFields.UserID == userID); // delete all audit data AuditDataCoreCollection auditDataDeleter = new AuditDataCoreCollection(); // first fetch it, then delete all entities from the collection, as the audit data is in an inheritance hierarchy of TargetPerEntity which can't // be deleted directly from the db. trans.Add(auditDataDeleter); auditDataDeleter.GetMulti(AuditDataCoreFields.UserID == userID); auditDataDeleter.DeleteMulti(); // set IP bans set by this user to userid 0 IPBanEntity ipbanUpdater = new IPBanEntity(); ipbanUpdater.IPBanSetByUserID = 0; IPBanCollection ipBans = new IPBanCollection(); trans.Add(ipBans); ipBans.UpdateMulti(ipbanUpdater, (IPBanFields.IPBanSetByUserID == userID)); // delete threadsubscriptions ThreadSubscriptionCollection threadSubscriptionsDeleter = new ThreadSubscriptionCollection(); trans.Add(threadSubscriptionsDeleter); threadSubscriptionsDeleter.DeleteMulti(ThreadSubscriptionFields.UserID == userID); // remove supportqueuethread claims SupportQueueThreadCollection supportQueueThreads = new SupportQueueThreadCollection(); trans.Add(supportQueueThreads); supportQueueThreads.DeleteMulti(SupportQueueThreadFields.ClaimedByUserID == userID); // set all placed in queue references to userid 0, so the threads stay in the queues. SupportQueueThreadEntity supportQueueThreadUpdater = new SupportQueueThreadEntity(); supportQueueThreadUpdater.PlacedInQueueByUserID=0; supportQueueThreads.UpdateMulti(supportQueueThreadUpdater, (SupportQueueThreadFields.PlacedInQueueByUserID == userID)); // now delete the actual user entity trans.Add(toDelete); toDelete.Delete(); // all done trans.Commit(); return true; } catch { trans.Rollback(); throw; } finally { trans.Dispose(); } }
/// <summary> /// Creates a new message in the given thread and closes the thread right after the addition of the message, /// which makes the just added message the 'close' message of the thread. Close messages are handy when the /// closure of a thread is not obvious. /// Caller should validate input parameters. /// </summary> /// <param name="threadID">Thread wherein the new message will be placed</param> /// <param name="userID">User who posted this message</param> /// <param name="messageText">Message text</param> /// <param name="messageAsHTML">Message text as HTML</param> /// <param name="userIDIPAddress">IP address of user calling this method</param> /// <param name="messageAsXML">Message text as XML, which is the result of the parse action on MessageText.</param> /// <param name="threadUpdatedNotificationTemplate">The thread updated notification template.</param> /// <param name="emailData">The email data.</param> /// <param name="sendReplyNotifications">Flag to signal to send reply notifications. If set to false no notifications are mailed, /// otherwise a notification is mailed to all subscribers to the thread the new message is posted in</param> /// <returns>MessageID if succeeded, 0 if not.</returns> public static int CreateNewMessageInThreadAndCloseThread(int threadID, int userID, string messageText, string messageAsHTML, string userIDIPAddress, string messageAsXML, string threadUpdatedNotificationTemplate, Dictionary<string, string> emailData, bool sendReplyNotifications) { Transaction trans = new Transaction(IsolationLevel.ReadCommitted, "InsertNewMessage"); int messageID = 0; try { DateTime postingDate = DateTime.Now; messageID = InsertNewMessage(threadID, userID, messageText, messageAsHTML, userIDIPAddress, messageAsXML, trans, postingDate); MessageManager.UpdateStatisticsAfterMessageInsert(threadID, userID, trans, postingDate, false, false); ThreadEntity thread = new ThreadEntity(); trans.Add(thread); thread.FetchUsingPK(threadID); thread.IsClosed=true; thread.IsSticky=false; thread.MarkedAsDone = true; bool result = thread.Save(); if(result) { // save succeeded, so remove from queue, pass the current transaction to the method so the action takes place inside this transaction. SupportQueueManager.RemoveThreadFromQueue(threadID, trans); } trans.Commit(); } catch(Exception) { trans.Rollback(); throw; } finally { trans.Dispose(); } if(sendReplyNotifications) { // send notification email to all subscribers. Do this outside the transaction so a failed email send action doesn't terminate the save process // of the message. ThreadManager.SendThreadReplyNotifications(threadID, userID, threadUpdatedNotificationTemplate, emailData); } return messageID; }
/// <summary> /// Creates a new thread in the given forum and places the passed in message as the first message in the thread. /// Caller should validate input parameters. /// </summary> /// <param name="forumID">Forum wherein the new thread will be placed</param> /// <param name="userID">User who started this thread</param> /// <param name="subject">Subject of the thread</param> /// <param name="messageText">First message of the thread</param> /// <param name="messageAsHTML">Message text as HTML</param> /// <param name="isSticky">Flag if the thread is sticky / pinned (true) or not (false)</param> /// <param name="userIDIPAddress">IP address of user calling this method</param> /// <param name="defaultSupportQueueID">The ID of the default support queue for this forum. If not null, the thread created will be /// added to the support queue with the ID specified.</param> /// <param name="messageID">The message ID of the new message, which is the start message in the thread.</param> /// <returns>ThreadID if succeeded, 0 if not.</returns> public static int CreateNewThreadInForum(int forumID, int userID, string subject, string messageText, string messageAsHTML, bool isSticky, string userIDIPAddress, int? defaultSupportQueueID, bool subscribeToThread, out int messageID) { Transaction trans = new Transaction(IsolationLevel.ReadCommitted, "NewThread"); try { DateTime postDate = DateTime.Now; ThreadEntity newThread = new ThreadEntity(); newThread.ForumID = forumID; newThread.IsClosed = false; newThread.IsSticky = isSticky; newThread.StartedByUserID = userID; newThread.Subject = subject; newThread.ThreadLastPostingDate = postDate; if(defaultSupportQueueID.HasValue) { // a support queue has been specified as the default support queue for this forum. Add the new thread to this support queue. SupportQueueThreadEntity supportQueueThread = new SupportQueueThreadEntity(); supportQueueThread.QueueID = defaultSupportQueueID.Value; supportQueueThread.PlacedInQueueByUserID = userID; supportQueueThread.PlacedInQueueOn = DateTime.Now; // assign the Thread property to the newly created thread entity, so this supportqueuethreadentity will be part of the graph // of objects which will be saved. supportQueueThread.Thread = newThread; } DateTime postingDate = DateTime.Now; MessageEntity newMessage = new MessageEntity(); newMessage.MessageText = messageText; newMessage.MessageTextAsHTML = messageAsHTML; newMessage.PostedByUserID = userID; newMessage.PostingDate = postingDate; newMessage.PostedFromIP = userIDIPAddress; newMessage.Thread = newThread; // add the newMessage entity to the transaction object. All entities saved recursively will be added automatically trans.Add(newMessage); // save the complete graph newMessage.Save(true); messageID = newMessage.MessageID; int threadID = newMessage.ThreadID; // update thread statistics, this is the task for the message manager, and we pass the transaction object so the actions will run in // the same transaction. MessageManager.UpdateStatisticsAfterMessageInsert(threadID, userID, trans, postingDate, false, subscribeToThread); trans.Commit(); return newThread.ThreadID; } catch(Exception) { trans.Rollback(); throw; } finally { trans.Dispose(); } }
/// <summary> /// Deletes the given forum from the system, including <b>all</b> threads in this forum and messages in those threads. /// </summary> /// <param name="forumID">Forum ID.</param> /// <returns>True if succeeded, false otherwise</returns> public static bool DeleteForum(int forumID) { // first all threads in this forum have to be removed, then this forum should be removed. Do this in one transaction. Transaction trans = new Transaction(IsolationLevel.ReadCommitted, "DeleteForum"); try { PredicateExpression forumFilter = new PredicateExpression(); forumFilter.Add((ForumFields.ForumID == forumID)); // remove all threads in this forum ThreadManager.DeleteAllThreadsInForum(forumID, trans); // remove all ForumRoleForumActionRight entities for this forum ForumRoleForumActionRightCollection forumRoleActionRights = new ForumRoleForumActionRightCollection(); trans.Add(forumRoleActionRights); forumRoleActionRights.DeleteMulti(ForumRoleForumActionRightFields.ForumID == forumID); // remove the forum entity. do this by executing a direct delete statement on the database ForumCollection forums = new ForumCollection(); trans.Add(forums); forums.DeleteMulti(forumFilter); trans.Commit(); return true; } catch { // exception occured, rollback trans.Rollback(); throw; } finally { trans.Dispose(); } }
/// <summary> /// Deletes the given message from the database and the complete logged history. /// </summary> /// <param name="messageID">The ID of the message to delete</param> /// <returns>True if succeeded, false otherwise</returns> public static bool DeleteMessage(int messageID) { Transaction trans = new Transaction(IsolationLevel.ReadCommitted, "DeleteMessage"); try { // formulate a filter so we can re-use the delete routine for all messages in threads matching a filter. PredicateExpression messageFilter = new PredicateExpression(MessageFields.MessageID == messageID); // call the routine which is used to delete 1 or more messages and related data from the db. DeleteMessages(messageFilter, trans); trans.Commit(); return true; } catch(Exception) { trans.Rollback(); throw; } finally { trans.Dispose(); } }
/// <summary> /// Saves the given set of actionrights as the set of forum action rights for the given forum / role combination. /// It first removes all current action rights for that combination. /// </summary> /// <param name="actionRightIDs">List of actionrights to set of this role</param> /// <param name="roleID">Role to use</param> /// <param name="forumID">Forum to use</param> /// <returns>true if succeeded, false otherwise</returns> public static bool SaveForumActionRightsForForumRole(List<int> actionRightIDs, int roleID, int forumID) { ForumRoleForumActionRightCollection forumRightsPerRole = new ForumRoleForumActionRightCollection(); Transaction trans = new Transaction(IsolationLevel.ReadCommitted, "SaveForumActionRights"); // add this collection to the transaction so all actions executed through this collection will be inside the transaction trans.Add(forumRightsPerRole); try { // first remove the existing rows for the role forumRightsPerRole.DeleteMulti((ForumRoleForumActionRightFields.RoleID == roleID).And(ForumRoleForumActionRightFields.ForumID == forumID)); // THEN add new ones foreach(int actionRightID in actionRightIDs) { ForumRoleForumActionRightEntity newForumRightPerRole = new ForumRoleForumActionRightEntity(); newForumRightPerRole.ActionRightID = actionRightID; newForumRightPerRole.ForumID = forumID; newForumRightPerRole.RoleID = roleID; forumRightsPerRole.Add(newForumRightPerRole); } // save the new entities forumRightsPerRole.SaveMulti(); // all done, commit transaction trans.Commit(); return true; } catch { // failed, rollback transaction trans.Rollback(); throw; } finally { trans.Dispose(); } }
/// <summary> /// Saves the audit actions for role specified. First removes all present rows for the roleid /// </summary> /// <param name="auditActionIDs">Audit action IDs.</param> /// <param name="roleID">Role ID.</param> /// <returns>true if the save action succeeded, false otherwise</returns> public static bool SaveAuditActionsForRole(List<int> auditActionIDs, int roleID) { RoleAuditActionCollection roleAuditActions = new RoleAuditActionCollection(); Transaction trans = new Transaction(IsolationLevel.ReadCommitted, "SaveAuditActionsForRole"); // add this collection to the transaction so all actions executed through this collection will be inside the transaction trans.Add(roleAuditActions); try { // first remove the existing rows for the role roleAuditActions.DeleteMulti((RoleAuditActionFields.RoleID == roleID)); // THEN add new ones to the same collection. foreach(int auditActionID in auditActionIDs) { RoleAuditActionEntity newRoleAuditAction = new RoleAuditActionEntity(); newRoleAuditAction.AuditActionID = auditActionID; newRoleAuditAction.RoleID = roleID; roleAuditActions.Add(newRoleAuditAction); } // save all new entities roleAuditActions.SaveMulti(); // succeeded, commit transaction trans.Commit(); return true; } catch { // failed, rollback transaction trans.Rollback(); throw; } finally { trans.Dispose(); } }
/// <summary> /// Modifies the given role: it resets the system action rights for the given role to the given set of action rights and it modifies /// the role description for the given role. If the user specified a role description that is already available, false will be returned to signal /// that the save failed. /// </summary> /// <param name="actionRightIDs">The action rights.</param> /// <param name="roleID">The role ID.</param> /// <param name="roleDescription">The role description.</param> /// <returns>true if succeeded, false otherwise</returns> public static bool ModifyRole(List<int> actionRightIDs, int roleID, string roleDescription) { // read the existing role entity from the database. RoleEntity roleToModify = new RoleEntity(roleID); if(roleToModify.IsNew) { // not found return false; } // check if the description is different. If so, we've to check if the new roledescription is already present. If so, we'll // abort the save if(roleToModify.RoleDescription != roleDescription) { if(CheckIfRoleDescriptionIsPresent(roleDescription)) { // new description, is already present, fail return false; } } // all set. We're going to delete all Role - SystemAction Rights combinations first, as we're going to re-insert them later on. // We'll use a transaction to be able to roll back all our changes if something fails. Transaction trans = new Transaction(IsolationLevel.ReadCommitted, "ModifyRole"); try { RoleSystemActionRightCollection roleActionRights = new RoleSystemActionRightCollection(); // add this collection to the transaction so all actions executed through this collection will be inside the transaction trans.Add(roleActionRights); // delete all role-systemactionright combinations directly from the database, by issuing a direct delete on the database, using a filter // on roleid roleActionRights.DeleteMulti(RoleSystemActionRightFields.RoleID == roleID); // add new role-systemactionright entities which we'll save to the database after that foreach(int actionRightID in actionRightIDs) { RoleSystemActionRightEntity toAdd = new RoleSystemActionRightEntity(); toAdd.ActionRightID = actionRightID; toAdd.RoleID = roleID; roleActionRights.Add(toAdd); } // save the new entities to the database roleActionRights.SaveMulti(); // we'll now save the role and the role description, if it's changed. Otherwise the save action will be a no-op. // add it to the transaction trans.Add(roleToModify); roleToModify.RoleDescription = roleDescription; roleToModify.Save(); // all done, commit the transaction trans.Commit(); return true; } catch { // failed, roll back transaction. trans.Rollback(); throw; } finally { trans.Dispose(); } }
/// <summary> /// Deletes the given role from the system. /// </summary> /// <param name="roleID">ID of role to delete</param> /// <returns>true if succeeded, false otherwise</returns> public static bool DeleteRole(int roleID) { RoleEntity toDelete = SecurityGuiHelper.GetRole(roleID); if(toDelete == null) { // not found return false; } Transaction trans = new Transaction(IsolationLevel.ReadCommitted, "DeleteRole"); try { // remove the role - forum - action right entities ForumRoleForumActionRightCollection forumRoleActionRights = new ForumRoleForumActionRightCollection(); trans.Add(forumRoleActionRights); forumRoleActionRights.DeleteMulti(ForumRoleForumActionRightFields.RoleID == roleID); // Remove role-audit action entities RoleAuditActionCollection roleAuditActions = new RoleAuditActionCollection(); trans.Add(roleAuditActions); roleAuditActions.DeleteMulti(RoleAuditActionFields.RoleID == roleID); // remove Role - systemright entities RoleSystemActionRightCollection roleSystemRights = new RoleSystemActionRightCollection(); trans.Add(roleSystemRights); roleSystemRights.DeleteMulti(RoleSystemActionRightFields.RoleID == roleID); // remove Role - user entities RoleUserCollection roleUsers = new RoleUserCollection(); trans.Add(roleUsers); roleUsers.DeleteMulti(RoleUserFields.RoleID == roleID); // delete the actual role trans.Add(toDelete); toDelete.Delete(); trans.Commit(); return true; } catch { // error occured, rollback trans.Rollback(); throw; } finally { trans.Dispose(); } }