public virtual ResourceBE Delete(ResourceBE resource, PageBE parentPage, uint changeSetId) { //Build the new revision ResourceBE res = BuildRevForRemove(resource, DateTime.UtcNow, changeSetId); //Update db res = SaveResource(res); //Update indexes and parent page's timestamp //TODO MaxM: Changesink needs to accept a resource if (res.ResourceType == ResourceBE.Type.FILE) { DekiContext.Current.Instance.EventSink.AttachmentDelete(DekiContext.Current.Now, res, DekiContext.Current.User); // Recent changes RecentChangeBL.AddFileRecentChange(DekiContext.Current.Now, parentPage, DekiContext.Current.User, DekiResources.FILE_REMOVED(res.Name), changeSetId); } if (parentPage != null) { PageBL.Touch(parentPage, DateTime.UtcNow); } return(res); }
public static void DeleteComment(PageBE page, CommentBE comment) { if (comment.PosterUserId != DekiContext.Current.User.ID) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); } if (!comment.IsCommentMarkedAsDeleted) { comment.DeleteDate = DateTime.UtcNow; comment.DeleterUserId = DekiContext.Current.User.ID; DbUtils.CurrentSession.Comments_Update(comment); PageBL.Touch(page, comment.DeleteDate.Value); RecentChangeBL.AddCommentDeleteRecentChange(comment.DeleteDate.Value, page, DekiContext.Current.User, DekiResources.COMMENT_DELETED(comment.Number), comment); DekiContext.Current.Instance.EventSink.CommentDelete(DekiContext.Current.Now, comment, page, DekiContext.Current.User); } }
public static CommentBE EditExistingComment(PageBE page, CommentBE comment, DreamMessage request, DreamContext context) { if (comment.PosterUserId != DekiContext.Current.User.ID) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); } ValidateCommentText(request.ContentType, request.AsText()); comment.LastEditDate = DateTime.UtcNow; comment.LastEditUserId = DekiContext.Current.User.ID; comment.Content = request.AsText(); comment.ContentMimeType = request.ContentType.ToString(); DbUtils.CurrentSession.Comments_Update(comment); PageBL.Touch(page, comment.LastEditDate.Value); RecentChangeBL.AddCommentUpdateRecentChange(comment.LastEditDate.Value, page, DekiContext.Current.User, DekiResources.COMMENT_EDITED(comment.Number), comment); return(comment); }
public static UserBE CreateNewUser(UserBE newUser) { if (newUser == null) { return(null); } //throw exception if licensing does not allow creation of another user DekiContext.Current.LicenseManager.IsUserCreationAllowed(true); if (newUser.RoleId == 0) { RoleBE defaultRole = PermissionsBL.RetrieveDefaultRoleForNewAccounts(); if (defaultRole != null) { newUser.RoleId = defaultRole.ID; } } ValidateUser(newUser); newUser.CreateTimestamp = DateTime.UtcNow; uint userId = DbUtils.CurrentSession.Users_Insert(newUser); if (userId == 0) { return(null); } newUser.ID = userId; PageBE userHomepage = null; try { // User homepages are created upon user creation (an attempt to create user homepages may also be done upon login) userHomepage = PageBL.CreateUserHomePage(newUser); } catch (Exception e) { _log.WarnExceptionFormat(e, "Error creating user page for {0}", newUser); } if (userHomepage != null) { var rcUser = UserBL.GetUserById(userHomepage.UserID) ?? DekiContext.Current.User ?? newUser; RecentChangeBL.AddUserCreatedRecentChange(DekiContext.Current.Now, userHomepage, rcUser, DekiResources.USER_ADDED(newUser.Name)); } DekiContext.Current.Instance.EventSink.UserCreate(DekiContext.Current.Now, newUser); return(newUser); }
public void RestoreAttachment(ResourceBE attachmentToRestore, PageBE toPage, DateTime timestamp, uint transactionId) { if (toPage == null || toPage.ID == 0) { ArchiveBE archivesMatchingPageId = _session.Archive_GetPageHeadById(attachmentToRestore.ParentPageId.Value); if (archivesMatchingPageId == null) { throw new AttachmentRestoreFailedNoParentFatalException(); } else { toPage = PageBL.GetPageByTitle(archivesMatchingPageId.Title); if (0 == toPage.ID) { PageBL.Save(toPage, _resources.Localize(DekiResources.RESTORE_ATTACHMENT_NEW_PAGE_TEXT()), DekiMimeType.DEKI_TEXT, null); } } } string filename = attachmentToRestore.Name; //Check for name conflicts on target page ResourceBE conflictingFile = GetPageAttachment(toPage.ID, filename); if (conflictingFile != null) { //rename the restored file filename = string.Format("{0}(restored {1}){2}", attachmentToRestore.FilenameWithoutExtension, DateTime.Now.ToString("g"), string.IsNullOrEmpty(attachmentToRestore.FilenameExtension) ? string.Empty : "." + attachmentToRestore.FilenameExtension); conflictingFile = GetPageAttachment(toPage.ID, filename); if (conflictingFile != null) { throw new AttachmentRestoreNameConflictException(); } } //Build new revision for restored file attachmentToRestore = BuildRevForRestore(attachmentToRestore, toPage, filename, transactionId); //Insert new revision into DB attachmentToRestore = SaveResource(attachmentToRestore); //Recent Changes RecentChangeBL.AddFileRecentChange(_dekiContext.Now, toPage, _dekiContext.User, DekiResources.FILE_RESTORED(attachmentToRestore.Name), transactionId); _dekiContext.Instance.EventSink.AttachmentRestore(_dekiContext.Now, attachmentToRestore, _dekiContext.User); }
private static void RestorePageRevisionsForPage(ArchiveBE[] archivedRevs, Title newTitle, uint transactionId, bool minorChange, DateTime utcTimestamp) { // add the most recent archive entry to the pages table // NOTE: this will preserve the page id if it was saved with the archive or create a new page id if it is not available ArchiveBE mostRecentArchiveRev = archivedRevs[archivedRevs.Length - 1]; PageBE restoredPage = null; if (0 < archivedRevs.Length) { restoredPage = new PageBE(); restoredPage.Title = newTitle; restoredPage.Revision = mostRecentArchiveRev.Revision; restoredPage.MinorEdit = mostRecentArchiveRev.MinorEdit; bool conflict; PageBL.Save(restoredPage, null, mostRecentArchiveRev.Comment, mostRecentArchiveRev.Text, mostRecentArchiveRev.ContentType, mostRecentArchiveRev.Title.DisplayName, mostRecentArchiveRev.Language, -1, null, mostRecentArchiveRev.TimeStamp, mostRecentArchiveRev.LastPageId, false, false, null, false, out conflict); RecentChangeBL.AddRestorePageRecentChange(utcTimestamp, restoredPage, DekiContext.Current.User, DekiResources.UNDELETED_ARTICLE(restoredPage.Title.AsPrefixedUserFriendlyPath()), minorChange, transactionId); } // add all other archive entries to the old table // NOTE: this will preserve the old ids if they were saved with the archive or create new old ids if not available for (int i = 0; i < archivedRevs.Length - 1; i++) { ArchiveBE archivedRev = archivedRevs[i]; PageBE currentPage = new PageBE(); currentPage.Title = newTitle; if (i < archivedRevs.Length - 1) { ParserResult parserResult = DekiXmlParser.ParseSave(currentPage, archivedRev.ContentType, currentPage.Language, archivedRev.Text, -1, null, false, null); currentPage.SetText(parserResult.BodyText); currentPage.ContentType = parserResult.ContentType; currentPage.UserID = archivedRev.UserID; currentPage.TimeStamp = archivedRev.TimeStamp; currentPage.MinorEdit = archivedRev.MinorEdit; currentPage.Comment = archivedRev.Comment; currentPage.Language = archivedRev.Language; currentPage.IsHidden = archivedRev.IsHidden; currentPage.Revision = archivedRev.Revision; currentPage.ID = restoredPage.ID; PageBL.InsertOld(currentPage, archivedRev.OldId); } } }
private void PutTags(PageBE page, List <TagBE> newTags) { List <TagBE> existingTags = GetTagsForPage(page).ToList(); // retrieve a diff of the existing and new tags List <TagBE> added; List <uint> removed; var diffSummary = CompareTagSets(existingTags, newTags, out added, out removed); // add and delete tags as determined from the diff added = InsertTags(page.ID, added); _session.TagMapping_Delete(page.ID, removed); if ((0 < added.Count) || (0 < removed.Count)) { RecentChangeBL.AddTagsRecentChange(_dekiContext.Now, page, _user, diffSummary); } PageBL.Touch(page, _dekiContext.Now); _eventSink.PageTagsUpdate(_dekiContext.Now, page, _user); }
public static CommentBE PostNewComment(PageBE page, DreamMessage request, DreamContext context) { ValidateCommentText(request.ContentType, request.AsText()); CommentBE comment = new CommentBE(); comment.Title = context.GetParam("title", string.Empty); comment.PageId = page.ID; comment.Content = request.AsText(); comment.ContentMimeType = request.ContentType.ToString(); comment.PosterUserId = DekiContext.Current.User.ID; comment.CreateDate = DateTime.UtcNow; //Note (MaxM): Replytoid/replies not yet exposed //ulong replyToId = context.GetParam<ulong>("replyto", 0); //if (replyToId == 0) // newComment.ReplyToId = null; //else // newComment.ReplyToId = replyToId; ushort commentNumber; uint commentId = DbUtils.CurrentSession.Comments_Insert(comment, out commentNumber); if (commentId == 0) { return(null); } else { comment.Id = commentId; comment.Number = commentNumber; PageBL.Touch(page, comment.CreateDate); RecentChangeBL.AddCommentCreateRecentChange(comment.CreateDate, page, DekiContext.Current.User, DekiResources.COMMENT_ADDED(comment.Number), comment); return(comment); } }
/// <summary> /// Move this attachment to the target page. /// </summary> /// <remarks> /// This will fail if destination page has a file with the same name. /// </remarks> /// <param name="sourcePage">Current file location</param> /// <param name="targetPage">Target file location. May be same as sourcepage for rename</param> /// <param name="name">New filename or null for no change</param> /// <returns></returns> public ResourceBE MoveAttachment(ResourceBE attachment, PageBE sourcePage, PageBE targetPage, string name, bool loggingEnabled) { //TODO MaxM: Connect with a changeset uint changeSetId = 0; attachment.AssertHeadRevision(); bool move = targetPage != null && targetPage.ID != sourcePage.ID; bool rename = name != null && !name.EqualsInvariant(attachment.Name); //Just return the current revision if no change is being made if (!move && !rename) { return(attachment); } //validate filename if (rename) { name = ValidateFileName(name); } //Check the resource exists on the target (may be same as source page) with new name (if given) or current name ResourceBE existingAttachment = GetPageAttachment((targetPage ?? sourcePage).ID, name ?? attachment.Name); if (existingAttachment != null) { throw new AttachmentExistsOnPageConflictException(name ?? attachment.Name, (targetPage ?? sourcePage).Title.AsUserFriendlyName()); } //Performing a move? if (move) { _dekiContext.Instance.Storage.MoveFile(attachment, targetPage); //Perform the IStorage move (should be a no-op) } //Build the new revision ResourceBE newRevision = BuildRevForMoveAndRename(attachment, targetPage, name, changeSetId); //Insert new revision into DB try { newRevision = SaveResource(newRevision); } catch { //failed to save the revision, undo the file move with the IStorage. (Should be a no-op) if (move) { _dekiContext.Instance.Storage.MoveFile(attachment, sourcePage); } throw; //NOTE MaxM: file rename does not even touch IStorage. No need to undo it } //Notification for file move if (loggingEnabled) { if (move) { RecentChangeBL.AddFileRecentChange(_dekiContext.Now, sourcePage, _dekiContext.User, DekiResources.FILE_MOVED_TO(attachment.Name, targetPage.Title.AsPrefixedUserFriendlyPath()), changeSetId); RecentChangeBL.AddFileRecentChange(_dekiContext.Now, targetPage, _dekiContext.User, DekiResources.FILE_MOVED_FROM(attachment.Name, sourcePage.Title.AsPrefixedUserFriendlyPath()), changeSetId); } if (rename) { RecentChangeBL.AddFileRecentChange(_dekiContext.Now, sourcePage, _dekiContext.User, DekiResources.FILE_RENAMED_TO(attachment.Name, name), changeSetId); } } //Notification for file rename and move use same event _dekiContext.Instance.EventSink.AttachmentMove(_dekiContext.Now, attachment, sourcePage, _dekiContext.User); return(newRevision); }
public ResourceBE AddAttachment(ResourceBE existingRevision, Stream filestream, long filesize, MimeType mimeType, PageBE targetPage, string userDescription, string fileName, bool isMsWebDav) { if (_dekiContext.Instance.MaxFileSize < filesize) { throw new AttachmentMaxFileSizeAllowedInvalidArgumentException(_dekiContext.Instance.MaxFileSize); } var saveFileName = ValidateFileName(fileName); if (existingRevision != null) { if (!saveFileName.EqualsInvariant(existingRevision.Name)) { // An existing file is getting renamed. Make sure no file exists with the new name var existingAttachment = GetPageAttachment(targetPage.ID, saveFileName); if (existingAttachment != null) { throw new AttachmentExistsOnPageConflictException(saveFileName, targetPage.Title.AsUserFriendlyName()); } } } // If file is found but has been deleted, create a new file. if (existingRevision != null && existingRevision.ResourceIsDeleted) { existingRevision = null; } if (isMsWebDav) { _log.DebugFormat("Upload client is MD WebDAV, provided mimetype is: {0}", mimeType); var extensionFileType = MimeType.FromFileExtension(Path.GetExtension(saveFileName)); if (!extensionFileType.Match(mimeType) || extensionFileType == MimeType.DefaultMimeType) { mimeType = existingRevision == null ? extensionFileType : existingRevision.MimeType; _log.DebugFormat("using mimetype '{0}' instead", mimeType); } } ResourceBE attachment; var resourceContents = new ResourceContentBE((uint)filesize, mimeType); var isUpdate = false; if (existingRevision == null) { attachment = _resourceBL.BuildRevForNewResource((uint)targetPage.ID, ResourceBE.ParentType.PAGE, saveFileName, mimeType, (uint)filesize, null, ResourceBE.Type.FILE, _dekiContext.User.ID, resourceContents); } else { isUpdate = true; attachment = BuildRevForContentUpdate(existingRevision, mimeType, (uint)filesize, null, saveFileName, resourceContents); } // rewrite mimetype to text/plain for certain extensions string extension = attachment.FilenameExtension; if (_dekiContext.Instance.FileExtensionForceAsTextList.Any(forcedExtensions => extension == forcedExtensions)) { attachment.MimeType = MimeType.TEXT; } // Insert the attachment into the DB attachment = SaveResource(attachment); try { // Save file to storage provider _dekiContext.Instance.Storage.PutFile(attachment, SizeType.ORIGINAL, new StreamInfo(filestream, filesize, mimeType)); } catch (Exception x) { _dekiContext.Instance.Log.WarnExceptionFormat(x, "Failed to save attachment to storage provider"); // Upon save failure, delete the record from the db. _session.Resources_DeleteRevision(attachment.ResourceId, attachment.Revision); throw; } // Set description property if (!string.IsNullOrEmpty(userDescription)) { attachment = SetDescription(attachment, userDescription); } // For images resolve width/height (if not in imagemagick's blacklist) attachment = IdentifyUnknownImage(attachment); // Pre render thumbnails of images AttachmentPreviewBL.PreSaveAllPreviews(attachment); PageBL.Touch(targetPage, DateTime.UtcNow); //TODO MaxM: Connect with transaction RecentChangeBL.AddFileRecentChange(targetPage.Touched, targetPage, _dekiContext.User, DekiResources.FILE_ADDED(attachment.Name), 0); if (isUpdate) { _dekiContext.Instance.EventSink.AttachmentUpdate(_dekiContext.Now, attachment, _dekiContext.User); } else { _dekiContext.Instance.EventSink.AttachmentCreate(_dekiContext.Now, attachment, _dekiContext.User); } return(attachment); }