/// <summary> /// removes the order passed in from the persistent storage. Also the order detail rows belonging with this order will be /// removed. It is wise to refresh the gui after this action, since collections and other data elements have to refreshed to illustrate the /// change. /// </summary> /// <param name="orderToRemove">Order entity to remove from the persistent storage</param> /// <returns>true if the removal was succesful, false otherwise</returns> private bool RemoveOrder(OrderEntity orderToRemove) { DataAccessAdapter adapter = new DataAccessAdapter(); bool toReturn = false; adapter.StartTransaction(System.Data.IsolationLevel.ReadCommitted, "RemoveOrder"); try { // first remove the orderdetail rows of this order adapter.DeleteEntityCollection(orderToRemove.OrderDetails); // remove the order itself toReturn = adapter.DeleteEntity(orderToRemove); // done adapter.Commit(); } catch { adapter.Rollback(); throw; } finally { adapter.Dispose(); } return(toReturn); }
/// <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 async Task <bool> DeleteForumAsync(int forumId) { // first all threads in this forum have to be removed, then this forum should be removed. Do this in one transaction. using (var adapter = new DataAccessAdapter()) { await adapter.StartTransactionAsync(IsolationLevel.ReadCommitted, "DeleteForum").ConfigureAwait(false); try { await ThreadManager.DeleteAllThreadsInForumAsync(forumId, adapter); // remove all ForumRoleForumActionRight entities for this forum await adapter.DeleteEntitiesDirectlyAsync(typeof(ForumRoleForumActionRightEntity), new RelationPredicateBucket(ForumRoleForumActionRightFields.ForumID.Equal(forumId))) .ConfigureAwait(false); // remove the forum entity. do this by executing a direct delete statement on the database await adapter.DeleteEntitiesDirectlyAsync(typeof(ForumEntity), new RelationPredicateBucket(ForumFields.ForumID.Equal(forumId))).ConfigureAwait(false); adapter.Commit(); return(true); } catch { // exception occured, rollback adapter.Rollback(); throw; } } }
/// <summary> /// Removes the order and the order detail rows of this order from the database. /// </summary> /// <param name="toRemove">order to remove.</param> /// <returns>true if the remove was successful, false otherwise</returns> public bool RemoveOrder(OrderEntity toRemove) { Console.WriteLine("RemoveOrder called"); bool toReturn = false; using (DataAccessAdapter adapter = new DataAccessAdapter()) { adapter.StartTransaction(IsolationLevel.ReadCommitted, "order removal"); try { // LLBLGen Pro doesn't have cascading deletes, as those aren't always possible (multiple paths from A to B), plus // deletes are always explicit in LLBLGen Pro so no surprises which aren't recoverable. // first remove the orderdetail rows of this order adapter.DeleteEntityCollection(toRemove.OrderDetails); // remove the order itself toReturn = adapter.DeleteEntity(toRemove); // done. Commit the work. adapter.Commit(); toReturn = true; } catch { // exception occured. Rollback transaction adapter.Rollback(); // simply rethrow the exception throw; } } return(toReturn); }
private static async Task ConvertMessages() { // display total amount of messages to process int totalNumberOfMessages = await MessageGuiHelper.GetTotalNumberOfMessagesAsync(); Console.WriteLine("Total # of messages to process: {0}. Using batch size: {1}", totalNumberOfMessages, BATCHSIZE); var numberOfBatches = (totalNumberOfMessages / BATCHSIZE) + 1; var qf = new QueryFactory(); var q = qf.Message.OrderBy(MessageFields.MessageID.Ascending()) .Exclude(MessageFields.MessageTextAsHTML); using (var adapter = new DataAccessAdapter()) { await adapter.StartTransactionAsync(IsolationLevel.ReadCommitted, "Converting UBB to Markdown").ConfigureAwait(false); adapter.KeepTrackOfTransactionParticipants = false; try { var messages = new EntityCollection <MessageEntity>(); for (int batchNo = 1; batchNo <= numberOfBatches; batchNo++) { messages.Clear(); Console.WriteLine("Batch {0} of {1}", batchNo, numberOfBatches); q.Page(batchNo, BATCHSIZE); Console.Write("\tFetching messages..."); adapter.FetchQuery(q, messages); Console.WriteLine("DONE. Messages fetched: {0}", messages.Count); Console.Write("\tParsing messages..."); foreach (var message in messages) { string parserLog; string messageAsXml; bool errorsOccurred; string convertedText = TextParser.TransformUBBMessageStringToHTML(message.MessageText, _parserData, out parserLog, out errorsOccurred, out messageAsXml); if (errorsOccurred) { Console.WriteLine("\nERRORS: {0}", parserLog); Console.WriteLine("MessageID: {0}\nMessage as text:\n{1}--------------\n", message.MessageID, message.MessageText); } else { // html decode, so any < etc. are converted back to the regular characters. message.MessageText = HttpUtility.HtmlDecode(convertedText); } } Console.WriteLine("DONE"); Console.Write("\tPersisting batch..."); await adapter.SaveEntityCollectionAsync(messages).ConfigureAwait(false); Console.WriteLine("DONE\n"); } adapter.Commit(); } catch { adapter.Rollback(); throw; } } }
/// <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 async Task <bool> DeleteRoleAsync(int roleId) { var toDelete = await SecurityGuiHelper.GetRoleAsync(roleId); if (toDelete == null) { // not found return(false); } using (var adapter = new DataAccessAdapter()) { await adapter.StartTransactionAsync(IsolationLevel.ReadCommitted, "DeleteRole").ConfigureAwait(false); try { // remove the role - forum - action right entities await adapter.DeleteEntitiesDirectlyAsync(typeof(ForumRoleForumActionRightEntity), new RelationPredicateBucket(ForumRoleForumActionRightFields.RoleID.Equal(roleId))).ConfigureAwait(false); // Remove role-audit action entities await adapter.DeleteEntitiesDirectlyAsync(typeof(RoleAuditActionEntity), new RelationPredicateBucket(RoleAuditActionFields.RoleID.Equal(roleId))).ConfigureAwait(false); ; // remove Role - systemright entities await adapter.DeleteEntitiesDirectlyAsync(typeof(RoleSystemActionRightEntity), new RelationPredicateBucket(RoleSystemActionRightFields.RoleID.Equal(roleId))).ConfigureAwait(false); ; // remove Role - user entities await adapter.DeleteEntitiesDirectlyAsync(typeof(RoleUserEntity), new RelationPredicateBucket(RoleUserFields.RoleID.Equal(roleId))).ConfigureAwait(false); ; // delete the actual role await adapter.DeleteEntityAsync(toDelete).ConfigureAwait(false); ; adapter.Commit(); return(true); } catch { // error occured, rollback adapter.Rollback(); throw; } } }
/// <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. Caller should validate input parameters. It potentially closes the thread if ordered to do so. /// </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="subscribeToThread">if set to <c>true</c> [subscribe to thread].</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> private static async Task <int> CreateNewMessageInThreadAndPotentiallyCloseThread(int threadId, int userId, string messageText, string messageAsHTML, string userIdIPAddress, bool subscribeToThread, Dictionary <string, string> emailData, bool sendReplyNotifications) { var messageId = 0; using (var adapter = new DataAccessAdapter()) { await adapter.StartTransactionAsync(IsolationLevel.ReadCommitted, "InsertNewMessage").ConfigureAwait(false); try { var postingDate = DateTime.Now; var message = new MessageEntity { MessageText = messageText, MessageTextAsHTML = messageAsHTML, PostedByUserID = userId, PostingDate = postingDate, ThreadID = threadId, PostedFromIP = userIdIPAddress, }; messageId = await adapter.SaveEntityAsync(message).ConfigureAwait(false) ? message.MessageID : 0; if (messageId > 0) { await MessageManager.UpdateStatisticsAfterMessageInsert(threadId, userId, messageId, adapter, postingDate, true, subscribeToThread); } adapter.Commit(); } catch { adapter.Rollback(); throw; } } 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. await ThreadManager.SendThreadReplyNotifications(threadId, userId, emailData).ConfigureAwait(false); } return(messageId); }
/// <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 async Task <bool> SaveForumActionRightsForForumRoleAsync(List <int> actionRightIDs, int roleId, int forumId) { var forumRightsPerRole = new EntityCollection <ForumRoleForumActionRightEntity>(); foreach (var actionRightId in actionRightIDs) { var newForumRightPerRole = new ForumRoleForumActionRightEntity { ActionRightID = actionRightId, ForumID = forumId, RoleID = roleId }; forumRightsPerRole.Add(newForumRightPerRole); } using (var adapter = new DataAccessAdapter()) { await adapter.StartTransactionAsync(IsolationLevel.ReadCommitted, "SaveForumActionRights").ConfigureAwait(false); try { // first remove the existing rows for the role. Do this by a query directly on the database. await adapter.DeleteEntitiesDirectlyAsync(typeof(ForumRoleForumActionRightEntity), new RelationPredicateBucket((ForumRoleForumActionRightFields.RoleID.Equal(roleId)) .And(ForumRoleForumActionRightFields.ForumID.Equal(forumId)))) .ConfigureAwait(false); // then save the new entities await adapter.SaveEntityCollectionAsync(forumRightsPerRole).ConfigureAwait(false); // all done, commit transaction adapter.Commit(); return(true); } catch { // failed, rollback transaction adapter.Rollback(); throw; } } }
/// <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> /// <param name="threadId">The id of the thread the message is part of</param> /// <returns>True if succeeded, false otherwise</returns> public static async Task <bool> DeleteMessageAsync(int messageId, int threadId) { using (var adapter = new DataAccessAdapter()) { // if the message was the last message in the thread, we have first to update the statistics entity with the message that's semi-last. // we do that by simply fetching the last two messages of the thread. if the last message of these 2 is the one to delete, we update // the statistics entity with the one that's semi-last. var qf = new QueryFactory(); var q = qf.Message .Where(MessageFields.ThreadID.Equal(threadId)) .OrderBy(MessageFields.PostingDate.Descending()) .Limit(2) .Select(() => MessageFields.MessageID.ToValue <int>()); var lastTwoMessageIdsInThread = await adapter.FetchQueryAsync(q).ConfigureAwait(false); await adapter.StartTransactionAsync(IsolationLevel.ReadCommitted, "DeleteMessage").ConfigureAwait(false); try { var threadStatisticsUpdater = new ThreadStatisticsEntity(); threadStatisticsUpdater.Fields[(int)ThreadStatisticsFieldIndex.NumberOfMessages].ExpressionToApply = (ThreadStatisticsFields.NumberOfMessages - 1); if (lastTwoMessageIdsInThread.Count == 2 && lastTwoMessageIdsInThread[0] == messageId) { // message is the last one in the thread, update statistics row with the new last one threadStatisticsUpdater.LastMessageID = lastTwoMessageIdsInThread[1]; await adapter.UpdateEntitiesDirectlyAsync(threadStatisticsUpdater, new RelationPredicateBucket(ThreadStatisticsFields.ThreadID.Equal(threadId))) .ConfigureAwait(false); } await DeleteMessagesAsync(MessageFields.MessageID.Equal(messageId), adapter); adapter.Commit(); return(true); } catch { adapter.Rollback(); throw; } } }
/// <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 async Task <bool> DeleteSupportQueueAsync(int queueId) { using (var adapter = new DataAccessAdapter()) { // we'll do several actions in one atomic transaction, so start a transaction first. await adapter.StartTransactionAsync(IsolationLevel.ReadCommitted, "DeleteSupportQ").ConfigureAwait(false); try { // first reset all the FKs in Forum to NULL if they point to this queue. await adapter.UpdateEntitiesDirectlyAsync(new ForumEntity() { DefaultSupportQueueID = null }, new RelationPredicateBucket(ForumFields.DefaultSupportQueueID.Equal(queueId))).ConfigureAwait(false); ; // delete all SupportQueueThread entities which refer to this queue. This will make all threads which are in this queue become queue-less. await adapter.DeleteEntitiesDirectlyAsync(typeof(SupportQueueThreadEntity), new RelationPredicateBucket(SupportQueueThreadFields.QueueID.Equal(queueId))).ConfigureAwait(false); ; // it's now time to delete the actual supportqueue entity. var result = await adapter.DeleteEntitiesDirectlyAsync(typeof(SupportQueueEntity), new RelationPredicateBucket(SupportQueueFields.QueueID.Equal(queueId))).ConfigureAwait(false); ; // done so commit the transaction. adapter.Commit(); return(result > 0); } catch { adapter.Rollback(); throw; } } }
public async Task UpdateManagersAndEmployees(ManagerEntity manager, EmployeeEntity employee) { using (var adapter = new DataAccessAdapter()){ adapter.StartTransaction(IsolationLevel.ReadCommitted, "FirstTransaction"); try{ manager.IsNew = false; employee.IsNew = false; await adapter.SaveEntityAsync(manager); await adapter.SaveEntityAsync(employee); adapter.Commit(); } catch (Exception e) { adapter.Rollback(); throw new Exception("Transaction rollbacked {0}", e); } } }
/// <summary> /// Deletes the given Thread from the system, including <b>all</b> messages and related data in this Thread. /// </summary> /// <param name="threadId">Thread to delete.</param> /// <returns>True if succeeded, false otherwise</returns> public static async Task <bool> DeleteThreadAsync(int threadId) { using (var adapter = new DataAccessAdapter()) { // we'll use the delete threads feature as deleting a thread requires updating more data than just deleting a single thread object. await adapter.StartTransactionAsync(IsolationLevel.ReadCommitted, "DeleteThread").ConfigureAwait(false); try { await ThreadManager.DeleteThreadsAsync(new PredicateExpression(ThreadFields.ThreadID.Equal(threadId)), adapter); adapter.Commit(); return(true); } catch { adapter.Rollback(); throw; } } }
/// <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; } } }
public int CreateWithIsolationLevel(EmployeeClassificationEntity classification, bool shouldRollBack, IsolationLevel isolationLevel) { if (classification == null) { throw new ArgumentNullException(nameof(classification), $"{nameof(classification)} is null."); } using (var adapter = new DataAccessAdapter()) { adapter.StartTransaction(isolationLevel, null); adapter.SaveEntity(classification, true, recurse: false); var result = classification.EmployeeClassificationKey; if (shouldRollBack) { adapter.Rollback(); } else { adapter.Commit(); } return(result); } }
/// <summary> /// Handler of the Submit button /// Persists changes to the database /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnSubmit_Click(object sender, EventArgs e) { int savedCount = 0; int deletedCount = 0; // A using statement makes sure the Adapter is Dispose. using (DataAccessAdapter adapter = new DataAccessAdapter()) { // Start a Transaction adapter.StartTransaction(IsolationLevel.ReadCommitted, "CustomersActions"); try { // Save changes of the bound collection to the database. (Inserts/Updates) savedCount = adapter.SaveEntityCollection(_entities, true, false); // Delete entities removed from the bound collection. if (_entitiesToDelete.Count > 0) { deletedCount = adapter.DeleteEntityCollection(_entitiesToDelete); _entitiesToDelete.Clear(); } // Commit the Transaction adapter.Commit(); } catch { // Rollback the Transaction. adapter.Rollback(); throw; } } // Show a feedback message to the user. MessageBox.Show("Number of saved records = " + savedCount.ToString() + "\r\nNumber of deleted records = " + deletedCount.ToString()); }
/// <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 async Task <bool> DeleteUserAsync(int userId) { if (userId <= 1) { // can't delete the Anonymous user nor the admin user return(false); } var toDelete = await UserGuiHelper.GetUserAsync(userId); if (toDelete == null) { // user doesn't exist return(false); } if (toDelete.NickName == "Admin") { // can't delete admin return(false); } using (var adapter = new DataAccessAdapter()) { await adapter.StartTransactionAsync(IsolationLevel.ReadCommitted, "DeleteUser").ConfigureAwait(false); try { // we'll first update all PostedByUserId fields of all messages which are posted by the user to delete. var messageUpdater = new MessageEntity { PostedByUserID = 0 }; // reset to AC. await adapter.UpdateEntitiesDirectlyAsync(messageUpdater, new RelationPredicateBucket(MessageFields.PostedByUserID.Equal(userId))) .ConfigureAwait(false); // set the startuser of threads started by this user to 0 var threadUpdater = new ThreadEntity { StartedByUserID = 0 }; await adapter.UpdateEntitiesDirectlyAsync(threadUpdater, new RelationPredicateBucket(ThreadFields.StartedByUserID.Equal(userId))) .ConfigureAwait(false); // remove the user from the UserRoles set, as the user shouldn't be in any roles. await adapter.DeleteEntitiesDirectlyAsync(typeof(RoleUserEntity), new RelationPredicateBucket(RoleUserFields.UserID.Equal(userId))) .ConfigureAwait(false); // delete all bookmarks of user await adapter.DeleteEntitiesDirectlyAsync(typeof(BookmarkEntity), new RelationPredicateBucket(BookmarkFields.UserID.Equal(userId))) .ConfigureAwait(false); // delete all audit data // 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. var auditData = await adapter.FetchQueryAsync(new QueryFactory().User.Where(UserFields.UserID.Equal(userId))).ConfigureAwait(false); await adapter.DeleteEntityCollectionAsync(auditData).ConfigureAwait(false); // set IP bans set by this user to userid 0 var ipbanUpdater = new IPBanEntity { IPBanSetByUserID = 0 }; await adapter.UpdateEntitiesDirectlyAsync(ipbanUpdater, new RelationPredicateBucket(IPBanFields.IPBanSetByUserID.Equal(userId))) .ConfigureAwait(false); // delete threadsubscriptions await adapter.DeleteEntitiesDirectlyAsync(typeof(ThreadSubscriptionEntity), new RelationPredicateBucket(ThreadSubscriptionFields.UserID.Equal(userId))) .ConfigureAwait(false); // remove supportqueuethread claims await adapter.DeleteEntitiesDirectlyAsync(typeof(SupportQueueThreadEntity), new RelationPredicateBucket(SupportQueueThreadFields.ClaimedByUserID.Equal(userId))) .ConfigureAwait(false); // set all placed in queue references to userid 0, so the threads stay in the queues. var supportQueueThreadUpdater = new SupportQueueThreadEntity { PlacedInQueueByUserID = 0 }; await adapter.UpdateEntitiesDirectlyAsync(supportQueueThreadUpdater, new RelationPredicateBucket(SupportQueueThreadFields.PlacedInQueueByUserID.Equal(userId))) .ConfigureAwait(false); // now delete the actual user entity await adapter.DeleteEntityAsync(toDelete).ConfigureAwait(false); adapter.Commit(); return(true); } catch { adapter.Rollback(); throw; } } }
/// <summary> /// Updates the given user's profile data using the values of the properties of this class. /// </summary> /// <param name="userId">The user ID.</param> /// <param name="dateOfBirth">The date of birth.</param> /// <param name="emailAddress">The email address.</param> /// <param name="emailAddressIsPublic">flag to signal if the emailaddress is visible for everyone or not</param> /// <param name="iconUrl">The icon URL.</param> /// <param name="location">The location.</param> /// <param name="occupation">The occupation.</param> /// <param name="password">The password.</param> /// <param name="signature">The signature.</param> /// <param name="website">The website.</param> /// <param name="userTitleId">The user title ID.</param> /// <param name="autoSubscribeThreads">Default value when user creates new threads.</param> /// <param name="defaultMessagesPerPage">Messages per page to display</param> /// <param name="isBanned">flag whether the user is banned or not. Can be null, in which case the value is left untouched</param> /// <param name="roleIds">The RoleIDs of the roles the user is in. Can be null, in which case no roles are updated</param> /// <returns>true if succeeded, false otherwise</returns> public static async Task <bool> UpdateUserProfileAsync(int userId, DateTime?dateOfBirth, string emailAddress, bool emailAddressIsPublic, string iconUrl, string location, string occupation, string password, string signature, string website, int userTitleId, bool autoSubscribeThreads, short defaultMessagesPerPage, bool?isBanned = null, List <int> roleIds = null) { var user = await UserGuiHelper.GetUserAsync(userId); if (user == null) { // not found return(false); } user.DateOfBirth = dateOfBirth; user.EmailAddress = emailAddress; user.EmailAddressIsPublic = emailAddressIsPublic; user.IconURL = iconUrl; user.Location = location; user.Occupation = occupation; user.UserTitleID = userTitleId; if (isBanned.HasValue) { user.IsBanned = isBanned.Value; } if (!string.IsNullOrWhiteSpace(password)) { user.Password = HnDGeneralUtils.HashPassword(password, performPreMD5Hashing: true); } user.Signature = signature; user.Website = website; //Preferences user.AutoSubscribeToThread = autoSubscribeThreads; user.DefaultNumberOfMessagesPerPage = defaultMessagesPerPage; // first encode fields which could lead to cross-site-scripting attacks EncodeUserTextFields(user); if (roleIds != null) { // Add new entities for the user for all roleid's in the list specified. We'll first delete the ones the user is already in below directly foreach (var roleId in roleIds) { user.RoleUser.Add(new RoleUserEntity() { RoleID = roleId }); } } using (var adapter = new DataAccessAdapter()) { await adapter.StartTransactionAsync(IsolationLevel.ReadCommitted, "Update User Info").ConfigureAwait(false); try { if (roleIds != null) { // first remove the user from all roles, we'll do that directly. await adapter.DeleteEntitiesDirectlyAsync(typeof(RoleUserEntity), new RelationPredicateBucket(RoleUserFields.UserID.Equal(userId))) .ConfigureAwait(false); } // then save everything in one go. var toReturn = await adapter.SaveEntityAsync(user).ConfigureAwait(false); adapter.Commit(); return(toReturn); } catch { adapter.Rollback(); throw; } } }
/// <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="subscribeToThread">If true, the user with userid is automatically subscribed to the new thread created</param> /// <returns>tuple with ThreadID and messageid. ThreadId, if succeeded, is set to the threadid of the new thread, or 0 if failed. /// The message ID is the id of the new message, which is the start message in the thread.</returns> public static async Task <(int threadId, int messageId)> CreateNewThreadInForumAsync(int forumId, int userId, string subject, string messageText, string messageAsHTML, bool isSticky, string userIdIPAddress, int?defaultSupportQueueId, bool subscribeToThread) { var newThread = new ThreadEntity { ForumID = forumId, IsClosed = false, IsSticky = isSticky, StartedByUserID = userId, Subject = subject, }; 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. newThread.SupportQueueThread = new SupportQueueThreadEntity { QueueID = defaultSupportQueueId.Value, PlacedInQueueByUserID = userId, PlacedInQueueOn = DateTime.Now, // No need to set the Thread property, as it's auto-assigned due to the assignment of newThread.SupportQueueThread. }; } var newMessage = new MessageEntity { MessageText = messageText, MessageTextAsHTML = messageAsHTML, PostedByUserID = userId, PostingDate = DateTime.Now, PostedFromIP = userIdIPAddress, Thread = newThread }; // Assign a new statistics entity so we can track what the last message is. newThread.Statistics = new ThreadStatisticsEntity() { LastMessage = newMessage, NumberOfMessages = 1, NumberOfViews = 1 }; using (var adapter = new DataAccessAdapter()) { await adapter.StartTransactionAsync(IsolationLevel.ReadCommitted, "NewThread").ConfigureAwait(false); try { // save the complete graph await adapter.SaveEntityAsync(newMessage, true).ConfigureAwait(false); var messageId = newMessage.MessageID; var threadId = newMessage.ThreadID; // update thread statistics, this is the task for the message manager, and we pass the adapter so the actions will run in // the same transaction. Pass -1 as newMessageId as we already have inserted this. await MessageManager.UpdateStatisticsAfterMessageInsert(threadId, userId, -1, adapter, DateTime.Now, false, subscribeToThread); adapter.Commit(); return(newThread.ThreadID, messageId); } catch { adapter.Rollback(); throw; } } }
private static void ConvertThreadMemos() { Console.WriteLine("Converting thread memos. "); var qf = new QueryFactory(); using (var adapter = new DataAccessAdapter()) { var totalNumberOfThreads = adapter.FetchScalar <int>(qf.Thread.Select(Functions.CountRow())); var numberOfBatches = (totalNumberOfThreads / BATCHSIZE) + 1; Console.WriteLine("Total # of threads to process: {0}. Using batch size: {1}", numberOfBatches, BATCHSIZE); var q = qf.Thread.OrderBy(ThreadFields.ThreadID.Ascending()); adapter.StartTransaction(IsolationLevel.ReadCommitted, "Converting UBB to Markdown"); adapter.KeepTrackOfTransactionParticipants = false; try { var threads = new EntityCollection <ThreadEntity>(); for (int batchNo = 1; batchNo <= numberOfBatches; batchNo++) { threads.Clear(); Console.WriteLine("Batch {0} of {1}", batchNo, numberOfBatches); q.Page(batchNo, BATCHSIZE); Console.Write("\tFetching threads..."); adapter.FetchQuery(q, threads); Console.WriteLine("DONE. Threads fetched: {0}", threads.Count); Console.Write("\tParsing memos on threads..."); foreach (var thread in threads) { var toConvert = thread.Memo; if (string.IsNullOrWhiteSpace(toConvert)) { continue; } // replace CRLF with <space><space>CRLF, as the markdown parser will otherwise collide it with the previous lines which we don't want toConvert = toConvert.Replace(Environment.NewLine, " " + Environment.NewLine); string parserLog; string messageAsXml; bool errorsOccurred; string convertedText = TextParser.TransformUBBMessageStringToHTML(toConvert, _parserData, out parserLog, out errorsOccurred, out messageAsXml); if (errorsOccurred) { Console.WriteLine("\nERRORS: {0}", parserLog); Console.WriteLine("ThreadID: {0}\nThread memo as text:\n{1}--------------\n", thread.ThreadID, thread.Memo); } else { // html decode, so any < etc. are converted back to the regular characters. thread.Memo = HttpUtility.HtmlDecode(convertedText); } } Console.WriteLine("DONE"); Console.Write("\tPersisting batch..."); adapter.SaveEntityCollection(threads); Console.WriteLine("DONE\n"); } adapter.Commit(); } catch { adapter.Rollback(); throw; } } }
/// <summary> /// Updates the role entity with the id specified, with the role description and system action rights set /// 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="roleId">the id of the role</param> /// <param name="roleDescription">the new description of the role</param> /// <param name="systemActionRightsSet">the system action rights to assign to the role</param> /// <param name="auditActionsSet">the ids of the audit actions set for the role</param> /// <returns></returns> public static async Task <bool> ModifyRoleAsync(int roleId, string roleDescription, List <int> systemActionRightsSet, List <int> auditActionsSet) { using (var adapter = new DataAccessAdapter()) { var q = new QueryFactory().Role.Where(RoleFields.RoleID.Equal(roleId)); var role = await adapter.FetchFirstAsync(q).ConfigureAwait(false); if (role == null) { 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 role.RoleDescription = roleDescription; if (role.Fields.GetIsChanged((int)RoleFieldIndex.RoleID)) { if (await CheckIfRoleDescriptionIsPresentAsync(roleDescription)) { // new description, is already present, fail return(false); } } foreach (var actionRightId in systemActionRightsSet) { role.RoleSystemActionRights.Add(new RoleSystemActionRightEntity { ActionRightID = actionRightId }); } foreach (var auditActionId in auditActionsSet) { role.RoleAuditAction.Add(new RoleAuditActionEntity() { AuditActionID = auditActionId }); } // 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. await adapter.StartTransactionAsync(IsolationLevel.ReadCommitted, "ModifyRole").ConfigureAwait(false); try { await adapter.DeleteEntitiesDirectlyAsync(typeof(RoleSystemActionRightEntity), new RelationPredicateBucket(RoleSystemActionRightFields.RoleID.Equal(roleId))); await adapter.DeleteEntitiesDirectlyAsync(typeof(RoleAuditActionEntity), new RelationPredicateBucket(RoleAuditActionFields.RoleID.Equal(roleId))); await adapter.SaveEntityAsync(role).ConfigureAwait(false); // all done, commit the transaction adapter.Commit(); return(true); } catch { // failed, roll back transaction. adapter.Rollback(); throw; } } }