示例#1
0
        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);
        }
示例#2
0
 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);
     }
 }
示例#3
0
        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);
        }
示例#4
0
        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);
        }
示例#5
0
        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);
        }
示例#6
0
        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);
                }
            }
        }
示例#7
0
        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);
        }
示例#8
0
        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);
            }
        }
示例#9
0
        /// <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);
        }
示例#10
0
        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);
        }