/// <summary> Removes the sync logic for member _message</summary> /// <param name="signalRelatedEntity">If set to true, it will call the related entity's UnsetRelatedEntity method</param> /// <param name="resetFKFields">if set to true it will also reset the FK fields pointing to the related entity</param> private void DesetupSyncMessage(bool signalRelatedEntity, bool resetFKFields) { this.PerformDesetupSyncRelatedEntity( _message, new PropertyChangedEventHandler( OnMessagePropertyChanged ), "Message", SD.HnD.DAL.RelationClasses.StaticAuditDataMessageRelatedRelations.MessageEntityUsingMessageIDStatic, true, signalRelatedEntity, "AuditDataMessageRelated", resetFKFields, new int[] { (int)AuditDataMessageRelatedFieldIndex.MessageID } ); _message = null; }
/// <summary> setups the sync logic for member _message</summary> /// <param name="relatedEntity">Instance to set as the related entity of type entityType</param> private void SetupSyncMessage(IEntityCore relatedEntity) { if(_message!=relatedEntity) { DesetupSyncMessage(true, true); _message = (MessageEntity)relatedEntity; this.PerformSetupSyncRelatedEntity( _message, new PropertyChangedEventHandler( OnMessagePropertyChanged ), "Message", SD.HnD.DAL.RelationClasses.StaticAuditDataMessageRelatedRelations.MessageEntityUsingMessageIDStatic, true, ref _alreadyFetchedMessage, new string[] { } ); } }
/// <summary>Private CTor for deserialization</summary> /// <param name="info"></param> /// <param name="context"></param> protected AuditDataMessageRelatedEntityBase(SerializationInfo info, StreamingContext context) : base(info, context) { _message = (MessageEntity)info.GetValue("_message", typeof(MessageEntity)); if(_message!=null) { _message.AfterSave+=new EventHandler(OnEntityAfterSave); } _messageReturnsNewIfNotFound = info.GetBoolean("_messageReturnsNewIfNotFound"); _alwaysFetchMessage = info.GetBoolean("_alwaysFetchMessage"); _alreadyFetchedMessage = info.GetBoolean("_alreadyFetchedMessage"); this.FixupDeserialization(FieldInfoProviderSingleton.GetInstance(), PersistenceInfoProviderSingleton.GetInstance()); // __LLBLGENPRO_USER_CODE_REGION_START DeserializationConstructor // __LLBLGENPRO_USER_CODE_REGION_END }
/// <summary> Retrieves the related entity of type 'MessageEntity', using a relation of type 'n:1'</summary> /// <param name="forceFetch">if true, it will discard any changes currently in the currently loaded related entity and will refetch the entity from the persistent storage</param> /// <returns>A fetched entity of type 'MessageEntity' which is related to this entity.</returns> public virtual MessageEntity GetSingleMessage(bool forceFetch) { if( ( !_alreadyFetchedMessage || forceFetch || _alwaysFetchMessage) && !this.IsSerializing && !this.IsDeserializing && !this.InDesignMode) { bool performLazyLoading = this.CheckIfLazyLoadingShouldOccur(Relations.MessageEntityUsingMessageID); MessageEntity newEntity = new MessageEntity(); bool fetchResult = false; if(performLazyLoading) { AddToTransactionIfNecessary(newEntity); fetchResult = newEntity.FetchUsingPK(this.MessageID); } if(fetchResult) { newEntity = (MessageEntity)GetFromActiveContext(newEntity); } else { if(!_messageReturnsNewIfNotFound) { RemoveFromTransactionIfNecessary(newEntity); newEntity = null; } } this.Message = newEntity; _alreadyFetchedMessage = fetchResult; } return _message; }
protected void Page_Load(object sender, EventArgs e) { int messageID = HnDGeneralUtils.TryConvertToInt(Request.QueryString["MessageID"]); _message = MessageGuiHelper.GetMessage(messageID); if(_message == null) { // not found Response.Redirect("default.aspx", true); } _sourceType = HnDGeneralUtils.TryConvertToInt(Request.QueryString["SourceType"]); switch(_sourceType) { case 1: // new message, or message view, for now no action needed break; case 2: // new thread, for now no action needed break; default: // unknown, redirect Response.Redirect("default.aspx", true); break; } // We could have used Lazy loading here, but for the sake of separation, we use the BL method. _thread = ThreadGuiHelper.GetThread(_message.ThreadID); if(_thread == null) { // not found. Orphaned message. Response.Redirect("default.aspx", true); } _forum = CacheManager.GetForum(_thread.ForumID); if(_forum == null) { // not found. Response.Redirect("default.aspx", true); } // check if this forum accepts attachments. if(_forum.MaxNoOfAttachmentsPerMessage <= 0) { // no, so no right to be here nor is the user here via a legitimate route. Response.Redirect("default.aspx", true); } // Check credentials bool userHasAccess = SessionAdapter.CanPerformForumActionRight(_thread.ForumID, ActionRights.AccessForum); if(!userHasAccess) { // doesn't have access to this forum. redirect Response.Redirect("default.aspx", true); } // check if the user can view this thread. If not, don't continue. if((_thread.StartedByUserID != SessionAdapter.GetUserID()) && !SessionAdapter.CanPerformForumActionRight(_thread.ForumID, ActionRights.ViewNormalThreadsStartedByOthers) && !_thread.IsSticky) { // can't view this thread, it isn't visible to the user Response.Redirect("default.aspx", true); } // Check if the current user is allowed to manage attachments of this message, and other rights. _userMayManageAttachments = ((_message.PostedByUserID==SessionAdapter.GetUserID())|| SessionAdapter.CanPerformForumActionRight(_thread.ForumID, ActionRights.ManageOtherUsersAttachments)); _userCanAddAttachments = (((_message.PostedByUserID==SessionAdapter.GetUserID()) || SessionAdapter.CanPerformForumActionRight(_thread.ForumID, ActionRights.ManageOtherUsersAttachments)) && SessionAdapter.CanPerformForumActionRight(_thread.ForumID, ActionRights.AddAttachment)); _userCanApproveAttachments = SessionAdapter.CanPerformForumActionRight(_thread.ForumID, ActionRights.ApproveAttachment); phAttachmentLimits.Visible = _userMayManageAttachments; if(!Page.IsPostBack) { // fill the page's content lnkThreads.Text = HttpUtility.HtmlEncode(_forum.ForumName); lnkThreads.NavigateUrl += "?ForumID=" + _thread.ForumID; lblSectionName.Text = CacheManager.GetSectionName(_forum.SectionID); lnkMessages.NavigateUrl += _message.ThreadID; lnkMessages.Text = HttpUtility.HtmlEncode(_thread.Subject); lblMaxFileSize.Text = String.Format("{0} KB", _forum.MaxAttachmentSize); lblMaxNoOfAttachmentsPerMessage.Text = _forum.MaxNoOfAttachmentsPerMessage.ToString(); lnkMessage.Text += messageID.ToString(); lnkMessage.NavigateUrl += String.Format("MessageID={0}&ThreadID={1}", messageID, _thread.ThreadID); phAddNewAttachment.Visible = _userCanAddAttachments; BindAttachments(); } else { object numberOfAttachments = ViewState["numberOfAttachments"]; if(numberOfAttachments != null) { _numberOfAttachments = (int)numberOfAttachments; } } }
/// <summary> /// Inserts a new message in thread given. All exceptions are passed upwards, caller has full control over transaction. /// </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="transactionToUse">the open transaction to use for saving this message.</param> /// <param name="postingDate">The posting date.</param> /// <returns>new messageid</returns> private static int InsertNewMessage(int threadID, int userID, string messageText, string messageAsHTML, string userIDIPAddress, string messageAsXML, Transaction transactionToUse, DateTime postingDate) { MessageEntity message = new MessageEntity(); message.MessageText = messageText; message.MessageTextAsHTML = messageAsHTML; message.PostedByUserID = userID; message.PostingDate = postingDate; message.ThreadID = threadID; message.PostedFromIP = userIDIPAddress; message.MessageTextAsXml = messageAsXML; transactionToUse.Add(message); bool result = message.Save(); if(result) { return message.MessageID; } else { return 0; } }
/// <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 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> /// Updates the given message with the message passed, and logs the user passed as the changer of this /// message. /// </summary> /// <param name="editorUserID">ID of user who changed the message</param> /// <param name="editedMessageID">ID of message which was changed</param> /// <param name="messageText">Changed message text</param> /// <param name="messageAsHTML">Changed message text in HTML</param> /// <param name="editorUserIDIPAddress">IP address used to make the modification. This IP address is logged with the /// change to keep evidence who made which change from which IP address</param> /// <param name="messageAsXML">Message text as XML, which is the result of the parse action on MessageText.</param> /// <returns>True if succeeded, false otherwise</returns> /// <remarks>This routine is migrated to LLBLGen Pro</remarks> public static bool UpdateEditedMessage(int editorUserID, int editedMessageID, string messageText, string messageAsHTML, string editorUserIDIPAddress, string messageAsXML) { // now save the message. First pull it from the db MessageEntity message = new MessageEntity(editedMessageID); //update the fields with the new passed values message.MessageText = messageText; message.MessageTextAsHTML = messageAsHTML; message.MessageTextAsXml = messageAsXML; return message.Save(); }
/// <summary> /// Handles the Load event of the Page control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param> private void Page_Load(object sender, System.EventArgs e) { _editMessageID=HnDGeneralUtils.TryConvertToInt(Request.QueryString["MessageID"]); _message = MessageGuiHelper.GetMessage(_editMessageID); if(_message==null) { // not found Response.Redirect("default.aspx"); } // We could have used Lazy loading here, but for the sake of separation, we use the BL method. _thread = ThreadGuiHelper.GetThread(_message.ThreadID); if(_thread==null) { // not found. Orphaned message. Response.Redirect("default.aspx"); } // Check credentials bool userHasAccess = SessionAdapter.CanPerformForumActionRight(_thread.ForumID, ActionRights.AccessForum); if(!userHasAccess) { // doesn't have access to this forum. redirect Response.Redirect("default.aspx", true); } // Check if the current user is allowed to edit the message. bool userMayEditMessages=false; if(!_thread.IsClosed) { if(_thread.IsSticky) { userMayEditMessages = SessionAdapter.CanPerformForumActionRight(_thread.ForumID, ActionRights.AddAndEditMessageInSticky); } else { userMayEditMessages = SessionAdapter.CanPerformForumActionRight(_thread.ForumID, ActionRights.AddAndEditMessage); } } // User has the right to generally edit messages. Check if the user has the right to edit other peoples messages // and if not, if the user is the poster of this message. If not, no can do. if(!SessionAdapter.CanPerformForumActionRight(_thread.ForumID, ActionRights.EditDeleteOtherUsersMessages)) { // cannot edit other people's messages. Check if this message is posted by the current user. if(_message.PostedByUserID != SessionAdapter.GetUserID()) { // not allowed userMayEditMessages=false; } } if(!userMayEditMessages) { // is not allowed to edit the message Response.Redirect("Messages.aspx?ThreadID=" + _message.ThreadID, true); } // use BL class. We could have used Lazy loading, though for the sake of separation, we'll call into the BL class. ForumEntity forum = CacheManager.GetForum(_thread.ForumID); if(forum == null) { // orphaned thread Response.Redirect("default.aspx"); } // check if the user can view the thread the message is in. If not, don't continue. if((_thread.StartedByUserID != SessionAdapter.GetUserID()) && !SessionAdapter.CanPerformForumActionRight(_thread.ForumID, ActionRights.ViewNormalThreadsStartedByOthers)) { // can't edit this message, it's in a thread which isn't visible to the user Response.Redirect("default.aspx", true); } _startAtMessageIndex = HnDGeneralUtils.TryConvertToInt(Request.QueryString["StartAtMessage"]); // User may edit current message. if(!Page.IsPostBack) { // fill the page's content lnkThreads.Text = HttpUtility.HtmlEncode(forum.ForumName); lnkThreads.NavigateUrl += "?ForumID=" + _thread.ForumID; meMessageEditor.ForumName = forum.ForumName; meMessageEditor.ThreadSubject = _thread.Subject; lblSectionName.Text = CacheManager.GetSectionName(forum.SectionID); lnkMessages.NavigateUrl+=_message.ThreadID; lnkMessages.Text = HttpUtility.HtmlEncode(_thread.Subject); meMessageEditor.OriginalMessageText = _message.MessageText; } }
/// <summary> /// Re-parses all messages from start date till now or when amountToIndex is reached. This routine will read messagetext for a message, /// parse it, and update the MessageTextAsXML field with the parse result. /// </summary> /// <param name="amountToParse">Amount to parse.</param> /// <param name="startDate">Start date.</param> /// <param name="reGenerateHTML">If true, the HTML is also re-generated and saved.</param> /// <returns>the amount of messages re-parsed</returns> public static int ReParseMessages(int amountToParse, DateTime startDate, bool reGenerateHTML, ParserData parserData) { // index is blocks of 100 messages. var qf = new QueryFactory(); var q = qf.Create() .Select(MessageFields.MessageID, MessageFields.MessageText) .Where(MessageFields.PostingDate >= new DateTime(startDate.Year, startDate.Month, startDate.Day, 0, 0, 0, 0)); if(amountToParse <= 0) { // If we don't have a specific amount of messages to parse, then parse all messages posted till Now. q.AndWhere(MessageFields.PostingDate <= DateTime.Now); } TypedListDAO dao = new TypedListDAO(); bool parsingFinished = false; int amountProcessed = 0; int pageSize = 100; int pageNo = 1; while(!parsingFinished) { q.Page(pageNo, pageSize); DataTable messagesToParse = dao.FetchAsDataTable(q); parsingFinished = (messagesToParse.Rows.Count <= 0); if(!parsingFinished) { foreach(DataRow row in messagesToParse.Rows) { MessageEntity directUpdater = new MessageEntity(); directUpdater.IsNew = false; string messageXML = string.Empty; string messageHTML = string.Empty; TextParser.ReParseMessage((string)row["MessageText"], reGenerateHTML, parserData, out messageXML, out messageHTML); // use the directupdater entity to create an update query without fetching the entity first. directUpdater.Fields[(int)MessageFieldIndex.MessageID].ForcedCurrentValueWrite((int)row["MessageID"]); directUpdater.MessageTextAsXml = messageXML; if(reGenerateHTML) { directUpdater.MessageTextAsHTML=messageHTML; } directUpdater.Fields.IsDirty=true; // no transactional update. directUpdater.Save(); } amountProcessed += messagesToParse.Rows.Count; pageNo++; if(amountToParse > 0) { parsingFinished = (amountToParse <= amountProcessed); } } } return amountProcessed; }
/// <summary>Creates a new, empty MessageEntity object.</summary> /// <returns>A new, empty MessageEntity object.</returns> public override IEntity Create() { IEntity toReturn = new MessageEntity(); // __LLBLGENPRO_USER_CODE_REGION_START CreateNewMessage // __LLBLGENPRO_USER_CODE_REGION_END return toReturn; }
/// <summary> setups the sync logic for member _belongsToMessage</summary> /// <param name="relatedEntity">Instance to set as the related entity of type entityType</param> private void SetupSyncBelongsToMessage(IEntityCore relatedEntity) { if(_belongsToMessage!=relatedEntity) { DesetupSyncBelongsToMessage(true, true); _belongsToMessage = (MessageEntity)relatedEntity; this.PerformSetupSyncRelatedEntity( _belongsToMessage, new PropertyChangedEventHandler( OnBelongsToMessagePropertyChanged ), "BelongsToMessage", SD.HnD.DAL.RelationClasses.StaticAttachmentRelations.MessageEntityUsingMessageIDStatic, true, ref _alreadyFetchedBelongsToMessage, new string[] { } ); } }
/// <summary> Removes the sync logic for member _belongsToMessage</summary> /// <param name="signalRelatedEntity">If set to true, it will call the related entity's UnsetRelatedEntity method</param> /// <param name="resetFKFields">if set to true it will also reset the FK fields pointing to the related entity</param> private void DesetupSyncBelongsToMessage(bool signalRelatedEntity, bool resetFKFields) { this.PerformDesetupSyncRelatedEntity( _belongsToMessage, new PropertyChangedEventHandler( OnBelongsToMessagePropertyChanged ), "BelongsToMessage", SD.HnD.DAL.RelationClasses.StaticAttachmentRelations.MessageEntityUsingMessageIDStatic, true, signalRelatedEntity, "Attachments", resetFKFields, new int[] { (int)AttachmentFieldIndex.MessageID } ); _belongsToMessage = null; }
/// <summary> Removes the sync logic for member _belongsToMessage</summary> /// <param name="signalRelatedEntity">If set to true, it will call the related entity's UnsetRelatedEntity method</param> /// <param name="resetFKFields">if set to true it will also reset the FK fields pointing to the related entity</param> private void DesetupSyncBelongsToMessage(bool signalRelatedEntity, bool resetFKFields) { this.PerformDesetupSyncRelatedEntity(_belongsToMessage, new PropertyChangedEventHandler(OnBelongsToMessagePropertyChanged), "BelongsToMessage", SD.HnD.DAL.RelationClasses.StaticAttachmentRelations.MessageEntityUsingMessageIDStatic, true, signalRelatedEntity, "Attachments", resetFKFields, new int[] { (int)AttachmentFieldIndex.MessageID }); _belongsToMessage = null; }