/// <summary> /// Updates the user/forum/thread statistics after a message insert. Also makes sure if the thread isn't in a queue and the forum has a default support /// queue that the thread is added to that queue /// </summary> /// <param name="threadID">The thread ID.</param> /// <param name="userID">The user ID.</param> /// <param name="transactionToUse">The transaction to use.</param> /// <param name="postingDate">The posting date.</param> /// <param name="addToQueueIfRequired">if set to true, the thread will be added to the default queue of the forum the thread is in, if the forum /// has a default support queue and the thread isn't already in a queue.</param> /// <remarks>Leaves the passed in transaction open, so it doesn't commit/rollback, it just performs a set of actions inside the /// passed in transaction.</remarks> internal static void UpdateStatisticsAfterMessageInsert(int threadID, int userID, Transaction transactionToUse, DateTime postingDate, bool addToQueueIfRequired, bool subscribeToThread) { // user statistics UserEntity userUpdater = new UserEntity(); // set the amountofpostings field to an expression so it will be increased with 1. userUpdater.Fields[(int)UserFieldIndex.AmountOfPostings].ExpressionToApply = (UserFields.AmountOfPostings + 1); UserCollection users = new UserCollection(); transactionToUse.Add(users); users.UpdateMulti(userUpdater, (UserFields.UserID == userID)); // update directly on the DB. // thread statistics ThreadEntity threadUpdater = new ThreadEntity(); threadUpdater.ThreadLastPostingDate = postingDate; threadUpdater.MarkedAsDone = false; ThreadCollection threads = new ThreadCollection(); transactionToUse.Add(threads); threads.UpdateMulti(threadUpdater, (ThreadFields.ThreadID == threadID)); // forum statistics. Load the forum from the DB, as we need it later on. Use a fieldcompareset predicate to fetch the forum as we don't know the // forumID as we haven't fetched the thread ForumCollection forums = new ForumCollection(); transactionToUse.Add(forums); // use a fieldcompare set predicate to select the forumid based on the thread. This filter is equal to // WHERE ForumID == (SELECT ForumID FROM Thread WHERE ThreadID=@ThreadID) var forumFilter = new FieldCompareSetPredicate( ForumFields.ForumID, ThreadFields.ForumID, SetOperator.Equal, (ThreadFields.ThreadID == threadID)); forums.GetMulti(forumFilter); ForumEntity containingForum = null; if(forums.Count>0) { // forum found. There's just one. containingForum = forums[0]; containingForum.ForumLastPostingDate = postingDate; // save the forum. Just save the collection forums.SaveMulti(); } if(addToQueueIfRequired) { // If the thread involved isn't in a queue, place it in the default queue of the forum (if applicable) SupportQueueEntity containingQueue = SupportQueueGuiHelper.GetQueueOfThread(threadID, transactionToUse); if((containingQueue == null) && (containingForum != null) && (containingForum.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, containingForum.DefaultSupportQueueID.Value, userID, transactionToUse); } } //subscribe to thread if indicated if(subscribeToThread) { UserManager.AddThreadToSubscriptions(threadID, userID, transactionToUse); } }
/// <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> /// Marks the thread as done. /// </summary> /// <param name="threadId">Thread ID.</param> /// <returns></returns> public static async Task <bool> MarkThreadAsDoneAsync(int threadId) { var thread = await ThreadGuiHelper.GetThreadAsync(threadId); if (thread == null) { // not found return(false); } var containingSupportQueue = await SupportQueueGuiHelper.GetQueueOfThreadAsync(threadId); thread.MarkedAsDone = true; using (var adapter = new DataAccessAdapter()) { // 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(await adapter.SaveEntityAsync(thread).ConfigureAwait(false)); } // in a queue, so remove from the queue and save the entity. await adapter.StartTransactionAsync(IsolationLevel.ReadCommitted, "MarkThreadDone").ConfigureAwait(false); try { // save the thread var result = await adapter.SaveEntityAsync(thread).ConfigureAwait(false); if (result) { // save succeeded, so remove from queue, pass the current adapter to the method so the action takes place inside this transaction. await SupportQueueManager.RemoveThreadFromQueueAsync(threadId, adapter); } adapter.Commit(); return(true); } catch { // rollback transaction adapter.Rollback(); throw; } } }
/// <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> /// 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> /// Marks the thread as un-done, and add it to the default queue of the forum. /// </summary> /// <param name="threadId">Thread ID</param> /// <param name="userId">the user adding the thread to a queue by unmarking it as done </param> /// <returns></returns> public static async Task <bool> UnMarkThreadAsDoneAsync(int threadId, int userId) { var thread = await ThreadGuiHelper.GetThreadAsync(threadId); if (thread == null) { // not found return(false); } thread.MarkedAsDone = false; using (var adapter = new DataAccessAdapter()) { // Save the thread and add it to the default queue of the forum. await adapter.StartTransactionAsync(IsolationLevel.ReadCommitted, "MarkThreadUnDone").ConfigureAwait(false); try { await adapter.SaveEntityAsync(thread, true).ConfigureAwait(false); var q = new QueryFactory().Forum.Where(ForumFields.ForumID.Equal(thread.ForumID)); var forum = await adapter.FetchFirstAsync(q).ConfigureAwait(false); if (forum?.DefaultSupportQueueID != null) { // not in a queue, and the forum has a default queue. Add the thread to the queue of the forum await SupportQueueManager.AddThreadToQueueAsync(threadId, forum.DefaultSupportQueueID.Value, userId, adapter); } adapter.Commit(); return(true); } catch { // rollback transaction adapter.Rollback(); throw; } } }
/// <summary> /// Modifies the given properties of the given thread. /// </summary> /// <param name="threadId">The threadID of the thread which properties should be changed</param> /// <param name="subject">The new subject for this thread</param> /// <param name="isSticky">The new value for IsSticky</param> /// <param name="isClosed">The new value for IsClosed</param> public static async Task ModifyThreadPropertiesAsync(int threadId, string subject, bool isSticky, bool isClosed) { var thread = await ThreadGuiHelper.GetThreadAsync(threadId); if (thread == null) { // not found return; } // update the fields with new values thread.Subject = subject; thread.IsSticky = isSticky; thread.IsClosed = isClosed; using (var adapter = new DataAccessAdapter()) { await adapter.StartTransactionAsync(IsolationLevel.ReadCommitted, "ModifyThreadProperties"); try { var result = await adapter.SaveEntityAsync(thread).ConfigureAwait(false); if (result) { // save succeeded, so remove from queue, pass the current transaction to the method so the action takes place inside this transaction. await SupportQueueManager.RemoveThreadFromQueueAsync(threadId, adapter); } adapter.Commit(); } catch { adapter.Rollback(); throw; } } }
/// <summary> /// Updates the user/forum/thread statistics after a message insert. Also makes sure if the thread isn't in a queue and the forum has a default support /// queue that the thread is added to that queue /// </summary> /// <param name="threadId">The thread ID.</param> /// <param name="userId">The user ID.</param> /// <param name="newMessageId">The message id of the new message posted in the thread with threadid. If 0 or lower it's ignored and threadstatistics /// aren't updated. This is the case for when a new thread: the first message insert already inserted a correct threadstatistics object. </param> /// <param name="adapter">The adapter to use, which is assumed to have a live transaction active</param> /// <param name="postingDate">The posting date.</param> /// <param name="addToQueueIfRequired">if set to true, the thread will be added to the default queue of the forum the thread is in, if the forum /// has a default support queue and the thread isn't already in a queue.</param> /// <param name="subscribeToThread">if set to <c>true</c> [subscribe to thread].</param> /// <remarks> /// Leaves the passed in transaction open, so it doesn't commit/rollback, it just performs a set of actions inside the /// passed in transaction. /// </remarks> internal static async Task UpdateStatisticsAfterMessageInsert(int threadId, int userId, int newMessageId, IDataAccessAdapter adapter, DateTime postingDate, bool addToQueueIfRequired, bool subscribeToThread) { // user statistics var userUpdater = new UserEntity(); // set the amountofpostings field to an expression so it will be increased with 1. Update the entity directly in the DB userUpdater.Fields[(int)UserFieldIndex.AmountOfPostings].ExpressionToApply = (UserFields.AmountOfPostings + 1); await adapter.UpdateEntitiesDirectlyAsync(userUpdater, new RelationPredicateBucket(UserFields.UserID.Equal(userId))) .ConfigureAwait(false); if (newMessageId > 0) { // thread statistics. Create a single Update query which updates the messageid and increases the number of messages value with 1 var threadStatisticsUpdater = new ThreadStatisticsEntity { LastMessageID = newMessageId }; threadStatisticsUpdater.Fields[(int)ThreadStatisticsFieldIndex.NumberOfMessages].ExpressionToApply = (ThreadStatisticsFields.NumberOfMessages + 1); await adapter.UpdateEntitiesDirectlyAsync(threadStatisticsUpdater, new RelationPredicateBucket(ThreadStatisticsFields.ThreadID.Equal(threadId))) .ConfigureAwait(false); } // unmark the thread as done if it's done var threadUpdater = new ThreadEntity() { MarkedAsDone = false }; await adapter.UpdateEntitiesDirectlyAsync(threadUpdater, new RelationPredicateBucket(ThreadFields.ThreadID.Equal(threadId))) .ConfigureAwait(false); // forum statistics. Load the forum from the DB, as we need it later on. Use a nested query to fetch the forum as we don't know the // forumID as we haven't fetched the thread var qf = new QueryFactory(); var q = qf.Forum .Where(ForumFields.ForumID.In(qf.Create() .Select(ThreadFields.ForumID) .Where(ThreadFields.ThreadID.Equal(threadId)))); var containingForum = await adapter.FetchFirstAsync(q).ConfigureAwait(false); if (containingForum != null) { containingForum.ForumLastPostingDate = postingDate; // save the forum. await adapter.SaveEntityAsync(containingForum, true).ConfigureAwait(false); if (addToQueueIfRequired && containingForum.DefaultSupportQueueID.HasValue) { // If the thread involved isn't in a queue, place it in the default queue of the forum (if applicable) var containingQueue = await SupportQueueGuiHelper.GetQueueOfThreadAsync(threadId, adapter); if (containingQueue == null) { // not in a queue, and the forum has a default queue. Add the thread to the queue of the forum await SupportQueueManager.AddThreadToQueueAsync(threadId, containingForum.DefaultSupportQueueID.Value, userId, adapter); } } } //subscribe to thread if indicated if (subscribeToThread) { await UserManager.AddThreadToSubscriptionsAsync(threadId, userId, adapter); } }