public Yield GetUsers(DreamContext context, DreamMessage request, Result <DreamMessage> response) { // TODO (steveb): add 'emailfilter' and use it to obsolete 'usernameemailfilter'; 'usernamefilter', 'fullnamefilter', and 'emailfilter' // should be OR'ed together when they are present. PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.READ); uint totalCount; uint queryCount; var users = UserBL.GetUsersByQuery(context, null, out totalCount, out queryCount); XDoc result = new XDoc("users"); result.Attr("count", users.Count()); result.Attr("querycount", queryCount); result.Attr("totalcount", totalCount); result.Attr("href", DekiContext.Current.ApiUri.At("users")); bool verbose = context.GetParam <bool>("verbose", true); foreach (UserBE u in users) { if (verbose) { result.Add(UserBL.GetUserXmlVerbose(u, null, Utils.ShowPrivateUserInfo(u), true, true)); } else { result.Add(UserBL.GetUserXml(u, null, Utils.ShowPrivateUserInfo(u))); } } response.Return(DreamMessage.Ok(result)); yield break; }
public Yield GetFiles(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.READ); uint skip = context.GetParam <uint>("skip", 0); uint numfiles = 100; string numfilesStr = context.GetParam("numfiles", numfiles.ToString()); if (StringUtil.EqualsInvariantIgnoreCase(numfilesStr, "ALL")) { numfiles = uint.MaxValue; } else { if (!uint.TryParse(numfilesStr, out numfiles)) { throw new AttachmentCannotParseNumFilesInvalidArgumentException(); } } IList <ResourceBE> files = AttachmentBL.Instance.RetrieveAttachments(skip, numfiles); XDoc ret = AttachmentBL.Instance.GetFileXml(files, false, null, null, null); response.Return(DreamMessage.Ok(ret)); yield break; }
public Yield GetGroupUsers(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.READ); GroupBE group = GetGroupFromUrl(); DreamMessage responseMsg = null; uint totalCount; uint queryCount; var usersInGroup = UserBL.GetUsersByQuery(context, group.Id, out totalCount, out queryCount); XDoc ret = new XDoc("users"); ret.Attr("count", usersInGroup.Count()); ret.Attr("querycount", queryCount); ret.Attr("totalcount", totalCount); ret.Attr("href", DekiContext.Current.ApiUri.At("groups", group.Id.ToString(), "users")); foreach (UserBE member in usersInGroup) { ret.Add(UserBL.GetUserXml(member, null, Utils.ShowPrivateUserInfo(member))); } responseMsg = DreamMessage.Ok(ret); response.Return(responseMsg); yield break; }
public Yield PostUserAuth(DreamContext context, DreamMessage request, Result <DreamMessage> response) { uint serviceId = context.GetParam <uint>("authprovider", 0); bool altPassword; //This will internally fail with a 501 response if credentials are invalid. //Anonymous accounts (no credentials/authtoken) are not allowed -> 401 UserBE u = SetContextAndAuthenticate(request, serviceId, context.Verb == Verb.POST, false, true, out altPassword); PermissionsBL.CheckUserAllowed(u, Permissions.LOGIN); string token = AuthBL.CreateAuthTokenForUser(u); try { PageBL.CreateUserHomePage(DekiContext.Current.User); } catch { } XUri redirectUri = XUri.TryParse(context.GetParam("redirect", null)); DreamMessage ret = BuildSetAuthTokenResponse(token, redirectUri); DekiContext.Current.Instance.EventSink.UserLogin(DekiContext.Current.Now, DekiContext.Current.User); //TODO Max: Set a response header or status to indicate that an alt password was used. response.Return(ret); yield break; }
public Yield PostArchiveFilesRestore(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); // parameter parsing PageBE destPage = null; string to = context.GetParam("to", string.Empty); if (to != string.Empty) { destPage = PageBL_GetPageFromPathSegment(false, to); } PageBE parentPage; ResourceBE removedFile = GetAttachment(context, request, Permissions.NONE, true, true, out parentPage); if (!removedFile.ResourceIsDeleted) { throw new AttachmentArchiveFileNotDeletedNotFoundException(); } //Optionally move the restored file to the given page if (null == destPage) { destPage = parentPage; } AttachmentBL.Instance.RestoreAttachment(removedFile, destPage, DateTime.UtcNow, 0); response.Return(DreamMessage.Ok()); yield break; }
public Yield GetBan(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); BanBE ban = GetBanFromRequest(context, context.GetParam <uint>("banid")); response.Return(DreamMessage.Ok(BanningBL.GetBanXml(ban))); yield break; }
public Yield GetArchivePageSubpages(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); XDoc responseXml = PageArchiveBL.GetArchivedSubPagesXml(context.GetParam <uint>("pageid")); response.Return(DreamMessage.Ok(responseXml)); yield break; }
public Yield GetArchivePageContents(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); DreamMessage ret = PageArchiveBL.BuildDeletedPageContents(context.GetParam <uint>("pageid")); response.Return(ret); yield break; }
public Yield PostGroupUsers(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); GroupBE group = GetGroupFromUrl(); group = GroupBL.AddGroupMembers(group, request.ToDocument()); response.Return(DreamMessage.Ok(GroupBL.GetGroupXmlVerbose(group, null))); yield break; }
public Yield DeleteGroup(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); GroupBE group = GetGroupFromUrl(); DbUtils.CurrentSession.Groups_Delete(group.Id); response.Return(DreamMessage.Ok()); yield break; }
public Yield GetGroup(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.READ); GroupBE group = GetGroupFromUrl(); DreamMessage responseMsg = DreamMessage.Ok(GroupBL.GetGroupXmlVerbose(group, null)); response.Return(responseMsg); yield break; }
public Yield GetSiteStatus(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.UPDATE); var status = new XDoc("status") .Elem("state", DekiContext.Current.Instance.Status); response.Return(DreamMessage.Ok(status)); yield break; }
public Yield GetArchiveFiles(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); IList <ResourceBE> removedFiles = AttachmentBL.Instance.GetDeletedAttachments(null, null); XDoc responseXml = AttachmentBL.Instance.GetFileXml(removedFiles, true, "archive", null, null); response.Return(DreamMessage.Ok(responseXml)); yield break; }
public Yield PostBans(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); BanBE ban = BanningBL.SaveBan(request.ToDocument()); DekiContext.Current.Instance.EventSink.BanCreated(DekiContext.Current.Now, ban); response.Return(DreamMessage.Ok(BanningBL.GetBanXml(ban))); yield break; }
public Yield DeleteGroupUser(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); GroupBE group = GetGroupFromUrl(); UserBE user = GetUserFromUrlMustExist(); group = GroupBL.RemoveGroupMember(group, user); response.Return(DreamMessage.Ok(GroupBL.GetGroupXmlVerbose(group, null))); yield break; }
public Yield PostGroup(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); DreamMessage responseMsg = null; GroupBE group = GroupBL.PostGroupFromXml(request.ToDocument(), null, context.GetParam("authusername", null), context.GetParam("authpassword", null)); responseMsg = DreamMessage.Ok(GroupBL.GetGroupXmlVerbose(group, null)); response.Return(responseMsg); yield break; }
public Yield DeleteBan(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); BanBE ban = GetBanFromRequest(context, context.GetParam <uint>("banid")); BanningBL.DeleteBan(ban); DekiContext.Current.Instance.EventSink.BanRemoved(DekiContext.Current.Now, ban); response.Return(DreamMessage.Ok()); yield break; }
public Yield PutSiteRole(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); RoleBE role = GetRoleFromUrl(false); role = PermissionsBL.PutRole(role, request, context); response.Return(DreamMessage.Ok(PermissionsBL.GetRoleXml(role, null))); yield break; }
public Yield GetArchive(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); XDoc ret = new XDoc("archive"); ret.Start("pages.archive").Attr("href", DekiContext.Current.ApiUri.At("archive", "pages")).End(); ret.Start("files.archive").Attr("href", DekiContext.Current.ApiUri.At("archive", "files")).End(); response.Return(DreamMessage.Ok(ret)); yield break; }
public Yield GetArchiveFileInfo(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); PageBE parentPage = null; ResourceBE removedFile = GetAttachment(context, request, Permissions.NONE, true, true, out parentPage); if (!removedFile.ResourceIsDeleted) { throw new AttachmentArchiveFileNotDeletedNotFoundException(); } response.Return(DreamMessage.Ok(AttachmentBL.Instance.GetFileXml(removedFile, true, "archive", null))); yield break; }
public Yield GetUser(DreamContext context, DreamMessage request, Result <DreamMessage> response) { UserBE u = GetUserFromUrlMustExist(); //Perform permission check if not looking yourself up if (u.ID != DekiContext.Current.User.ID) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.READ); } var showGroups = !context.GetParam("exclude", "").Contains("groups"); var showProperties = !context.GetParam("exclude", "").Contains("properties"); response.Return(DreamMessage.Ok(UserBL.GetUserXmlVerbose(u, null, Utils.ShowPrivateUserInfo(u), showGroups, showProperties))); yield break; }
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 Yield PostArchivePagesPageIdRestore(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); uint pageid = context.GetParam <uint>("pageid"); string targetPathStr = context.GetParam("to", string.Empty); string reason = context.GetParam("reason", string.Empty); Title targetPath = null; if (!string.IsNullOrEmpty(targetPathStr)) { targetPath = Title.FromUIUri(null, context.GetParam("to"), false); } XDoc responseXml = PageArchiveBL.RestoreDeletedPage(pageid, targetPath, reason); response.Return(DreamMessage.Ok(responseXml)); yield break; }
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); }
private static UserBE RenameUser(UserBE user, string newUserName, string newFullName) { //Renaming requires admin rights. PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); if (!ServiceBL.IsLocalAuthService(user.ServiceId)) { //TODO MaxM: allow renaming of external users throw new ExternalUserRenameNotImplementedExceptionException(); } //Check for already existing user with same name UserBE existingUser = DbUtils.CurrentSession.Users_GetByName(newUserName); if (existingUser != null) { throw new UserWithIdExistsConflictException(existingUser.Name, existingUser.ID); } PageBE existingTargetUserHomePage = PageBL.GetPageByTitle(Title.FromUIUsername(newUserName)); if (existingTargetUserHomePage != null && existingTargetUserHomePage.ID != 0 && !existingTargetUserHomePage.IsRedirect) { throw new UserHomepageRenameConflictException(); } //Try to move the homepage. PageBE userHomePage = GetHomePage(user); if (userHomePage != null && userHomePage.ID != 0) { Title newTitle = Title.FromUIUsername(newUserName); // new user homepage displayname is the user's full name or rebuilt from the username newTitle.DisplayName = !string.IsNullOrEmpty(newFullName) ? newFullName : newTitle.AsUserFriendlyDisplayName(); PageBL.MovePage(userHomePage, newTitle, true); } //Rename the user user.Name = newUserName; UserBL.UpdateUser(user); return(user); }
public Yield GetArchivePages(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); uint limit, offset; SortDirection sortDir; string sortField; Utils.GetOffsetAndCountFromRequest(context, 100, out limit, out offset, out sortDir, out sortField); Title filterTitle = null; string titleStr = context.GetParam("title", null); if (!string.IsNullOrEmpty(titleStr)) { filterTitle = Title.FromUIUri(null, titleStr, false); } XDoc responseXml = PageArchiveBL.GetArchivedPagesXml(limit, offset, filterTitle); response.Return(DreamMessage.Ok(responseXml)); yield break; }
public Yield GetGroups(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.READ); uint totalCount, queryCount; IList <GroupBE> groups = GroupBL.GetGroupsByQuery(context, out totalCount, out queryCount); XDoc result = new XDoc("groups"); result.Attr("count", groups.Count); result.Attr("querycount", queryCount); result.Attr("totalcount", totalCount); result.Attr("href", DekiContext.Current.ApiUri.At("groups")); foreach (GroupBE g in groups) { result.Add(GroupBL.GetGroupXmlVerbose(g, null)); } response.Return(DreamMessage.Ok(result)); yield break; }
public Yield GetArchiveFile(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); PageBE parentPage = null; ResourceBE removedFile = GetAttachment(context, request, Permissions.NONE, true, true, out parentPage); if (!removedFile.ResourceIsDeleted) { throw new AttachmentArchiveFileNotDeletedNotFoundException(); } StreamInfo file = DekiContext.Current.Instance.Storage.GetFile(removedFile, SizeType.ORIGINAL, false); if (file == null) { throw new AttachmentDoesNotExistFatalException(removedFile.ResourceId, removedFile.Revision); } var responseMsg = DreamMessage.Ok(file.Type, file.Length, file.Stream); responseMsg.Headers.ContentDisposition = new ContentDisposition(true, removedFile.Timestamp, null, null, removedFile.Name, file.Length); response.Return(responseMsg); yield break; }
public Yield GetFile(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PageBE parentPage = null; DreamMessage responseMsg = null; ResourceBE fileRevision = GetAttachment(context, request, Permissions.READ, true, false, out parentPage); if (fileRevision.IsHidden) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); } // check if only file information is requested if (context.Verb == Verb.HEAD) { response.Return(new DreamMessage(DreamStatus.Ok, null, fileRevision.MimeType, (long)fileRevision.Size, Stream.Null)); yield break; } try { if (request.CheckCacheRevalidation(fileRevision.Timestamp)) { responseMsg = DreamMessage.NotModified(); } if (responseMsg == null) { #region Preview related parameter parsing string sFormat = context.GetParam("format", string.Empty); string sRatio = context.GetParam("ratio", string.Empty); uint height = context.GetParam <uint>("height", 0); uint width = context.GetParam <uint>("width", 0); string cachedSize = context.GetParam("size", string.Empty); // check 'ratio' parameter RatioType ratio = RatioType.UNDEFINED; if (!string.IsNullOrEmpty(sRatio)) { switch (sRatio.ToLowerInvariant().Trim()) { case "var": case "variable": ratio = RatioType.VARIABLE; break; case "fixed": ratio = RatioType.FIXED; break; default: throw new AttachmentFileRatioInvalidArgumentException(); } } // check 'size' parameter SizeType size = SizeType.UNDEFINED; if (!string.IsNullOrEmpty(cachedSize) && !SysUtil.TryParseEnum(cachedSize.Trim(), out size)) { throw new AttachmentFilesizeInvalidArgumentException(); } // check 'format' parameter FormatType format = FormatType.UNDEFINED; if (!string.IsNullOrEmpty(sFormat) && !SysUtil.TryParseEnum(sFormat.Trim(), out format)) { throw new AttachmentFileFormatInvalidArgumentException(); } #endregion //if any preview related parameters are set, do preview logic. Otherwise return the file StreamInfo file = null; if ((size != SizeType.UNDEFINED && size != SizeType.ORIGINAL) || ratio != RatioType.UNDEFINED || format != FormatType.UNDEFINED || height != 0 || width != 0 ) { file = AttachmentPreviewBL.RetrievePreview(fileRevision, height, width, ratio, size, format); } else { var isMSWebDAV = MSWEBDAV_USER_AGENT_REGEX.IsMatch(request.Headers.UserAgent ?? string.Empty); file = DekiContext.Current.Instance.Storage.GetFile(fileRevision, SizeType.ORIGINAL, !isMSWebDAV); } // prepare response if (file == null) { throw new AttachmentDoesNotExistFatalException(fileRevision.ResourceId, fileRevision.Revision); } if (file.Uri != null) { responseMsg = DreamMessage.Redirect(file.Uri); } else { bool inline = fileRevision.MetaXml.ImageHeight.HasValue; // see if we can use the MimeType map for allowing inlining if (!inline) { // if IE inline security is not disabled bool isIE = false; if (!DekiContext.Current.Instance.EnableUnsafeIEContentInlining) { // check the user agent to see if we're dealing with IE isIE = MSIE_USER_AGENT_REGEX.IsMatch(request.Headers.UserAgent ?? string.Empty); } // see if the mime-type could allow inlining inline = DekiContext.Current.Instance.MimeTypeCanBeInlined(fileRevision.MimeType); if (inline && isIE) { // check whether the creator of the file had unsafecontent permission, to override IE security IList <ResourceBE> revisions = ResourceBL.Instance.GetResourceRevisions(fileRevision.ResourceId, ResourceBE.ChangeOperations.CONTENT, SortDirection.DESC, 1); UserBE lastContentEditor = UserBL.GetUserById(revisions[0].UserId); inline = PermissionsBL.IsUserAllowed(lastContentEditor, parentPage, Permissions.UNSAFECONTENT); } } responseMsg = DreamMessage.Ok(fileRevision.MimeType, file.Length, file.Stream); responseMsg.Headers["X-Content-Type-Options"] = "nosniff"; responseMsg.Headers.ContentDisposition = new ContentDisposition(inline, fileRevision.Timestamp, null, null, fileRevision.Name, file.Length, request.Headers.UserAgent); // MSIE6 will delete a downloaded file before the helper app trying to use it can get to it so we //have to do custom cache control headers for MSIE6 so that the file can actually be opened if (MSIE6_USER_AGENT_REGEX.IsMatch(request.Headers.UserAgent ?? string.Empty)) { responseMsg.Headers["Expires"] = "0"; responseMsg.Headers.Pragma = "cache"; responseMsg.Headers.CacheControl = "private"; } else { responseMsg.SetCacheMustRevalidate(fileRevision.Timestamp); } } } } catch { if (responseMsg != null) { responseMsg.Close(); } throw; } response.Return(responseMsg); yield break; }
public ResourceBE[] ModifyRevisionVisibility(ResourceBE res, XDoc request, string comment) { List <ResourceBE> revisionsToHide = new List <ResourceBE>(); List <ResourceBE> revisionsToUnhide = new List <ResourceBE>(); List <ResourceBE> ret = new List <ResourceBE>(); foreach (XDoc fileDoc in request["/revisions/file"]) { ulong?id = fileDoc["@id"].AsULong; //Provided id of all file revision must match the file id if (id != null && id.Value != res.MetaXml.FileId) { throw new MismatchedIdInvalidArgumentException(); } int?revNum = fileDoc["@revision"].AsInt; if ((revNum ?? 0) <= 0) { throw new RevisionInvalidArgumentException(); } //Hiding the head revision is not allowed. Reasons include: //* Behavior of search indexing undefined //* Behavior of accessing HEAD revision is undefined if (revNum == res.ResourceHeadRevision) { throw new HideHeadInvalidOperationException(); } bool?hide = fileDoc["@hidden"].AsBool; if (hide == null) { throw new HiddenAttributeInvalidArgumentException(); } ResourceBE rev = _resourceBL.GetResourceRevision(res.ResourceId, revNum.Value); if (rev == null) { throw new RevisionNotFoundInvalidArgumentException(); } //Only allow hiding revisions with content changes if ((rev.ChangeMask & ResourceBE.ChangeOperations.CONTENT) != ResourceBE.ChangeOperations.CONTENT) { throw new RevisionCannotBeHiddenConflictException(); } if (hide.Value != rev.IsHidden) { if (hide.Value) { revisionsToHide.Add(rev); } else { revisionsToUnhide.Add(rev); } } } if (revisionsToUnhide.Count == 0 && revisionsToHide.Count == 0) { throw new NoRevisionToHideUnHideInvalidOperationException(); } uint currentUserId = _dekiContext.User.ID; DateTime currentTs = DateTime.UtcNow; foreach (ResourceBE rev in revisionsToHide) { rev.IsHidden = true; rev.MetaXml.RevisionHiddenUserId = currentUserId; rev.MetaXml.RevisionHiddenTimestamp = currentTs; rev.MetaXml.RevisionHiddenComment = comment; ret.Add(_resourceBL.UpdateResourceRevision(rev)); } if (revisionsToUnhide.Count > 0) { PermissionsBL.CheckUserAllowed(_dekiContext.User, Permissions.ADMIN); } foreach (ResourceBE rev in revisionsToUnhide) { rev.IsHidden = false; rev.MetaXml.RevisionHiddenUserId = null; rev.MetaXml.RevisionHiddenTimestamp = null; rev.MetaXml.RevisionHiddenComment = null; ret.Add(_resourceBL.UpdateResourceRevision(rev)); } return(ret.ToArray()); }