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, string.Format(DekiResources.COMMENT_ADDED, comment.Number.ToString()), comment); return comment; } }
public Yield PutPasswordChange(DreamContext context, DreamMessage request, Result<DreamMessage> response) { UserBE targetUser = GetUserFromUrlMustExist(); string password = request.AsText(); if (string.IsNullOrEmpty(password)) { response.Return(DreamMessage.BadRequest(DekiResources.NEW_PASSWORD_NOT_PROVIDED)); yield break; } if( password.Length < 4) throw new DreamAbortException(DreamMessage.BadRequest(DekiResources.NEW_PASSWORD_TOO_SHORT)); //Ensure that the password is being set only on local accounts ServiceBE s = ServiceBL.GetServiceById(targetUser.ServiceId); if( s != null && !ServiceBL.IsLocalAuthService(s)){ throw new DreamAbortException(DreamMessage.BadRequest(DekiResources.PASSWORD_CHANGE_LOCAL_ONLY)); } if (UserBL.IsAnonymous(targetUser)) throw new DreamBadRequestException(DekiResources.CANNOT_CHANGE_ANON_PASSWORD); //Admins can always change anyones password. if (PermissionsBL.IsUserAllowed(DekiContext.Current.User, Permissions.ADMIN)) { //For admins a currentpassword is option but if given then it should be validated string currentPwd = context.GetParam("currentpassword", string.Empty); if (!string.IsNullOrEmpty(currentPwd)) { if (!AuthBL.IsValidAuthenticationForLocalUser(targetUser, currentPwd)) { throw new DreamAbortException(DreamMessage.Forbidden(DekiResources.CURRENTPASSWORD_DOES_NOT_MATCH)); } } }else if (DekiContext.Current.User.ID == targetUser.ID){ if (context.GetParam<bool>("altpassword", false)) { throw new DreamBadRequestException(DekiResources.CANNOT_CHANGE_OWN_ALT_PASSWORD); } //User changing their own password requires knowledge of their current password string currentPwd = context.GetParam("currentpassword"); if (!AuthBL.IsValidAuthenticationForLocalUser(DekiContext.Current.User, currentPwd)) { throw new DreamAbortException(DreamMessage.Forbidden(DekiResources.CURRENTPASSWORD_DOES_NOT_MATCH)); } } else { response.Return(DreamMessage.Forbidden(DekiResources.MUST_BE_TARGET_USER_OR_ADMIN)); yield break; } bool altPassword = context.GetParam<bool>("altpassword", false); targetUser = UserBL.SetPassword(targetUser, password, altPassword); if(DekiContext.Current.User.ID == targetUser.ID) { response.Return(BuildSetAuthTokenResponse(AuthBL.CreateAuthTokenForUser(targetUser))); } else { response.Return(DreamMessage.Ok()); } yield break; }
// TODO (brigettek): this feature currently always fails. Commenting out until we need/fix it. // [DreamFeature("POST:site/notifyadmin", "Notifies the site admin")]/ // [DreamFeatureParam("subject", "string", "Subject of the notice")] // [DreamFeatureStatus(DreamStatus.Ok, "The request completed successfully")] // [DreamFeatureStatus(DreamStatus.BadRequest, "Invalid input parameter or request body")] // [DreamFeatureStatus(DreamStatus.Forbidden, "User must be logged in")] public Yield PostSiteNotifyAdmin(DreamContext context, DreamMessage request, Result<DreamMessage> response) { if((DekiContext.CurrentOrNull == null) || UserBL.IsAnonymous(DekiContext.Current.User)) { response.Return(DreamMessage.Forbidden(DekiResources.MUST_BE_LOGGED_IN)); yield break; } SiteBL.SendNoticeToAdmin(context.GetParam("subject"), request.AsText(), request.ContentType); response.Return(DreamMessage.Ok()); 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, string.Format(DekiResources.COMMENT_EDITED, comment.Number.ToString()), comment); return comment; }
public Yield PostPageContents(DreamContext context, DreamMessage request, Result<DreamMessage> response) { PageBE cur = PageBL_GetPageFromUrl(context, false); // load page contents based on mime type string contents; MimeType mimeType = request.ContentType; if(mimeType.IsXml) { XDoc contentsDoc = request.ToDocument(); if(contentsDoc == null || contentsDoc.IsEmpty || !contentsDoc.HasName("content")) { throw new PostedDocumentInvalidArgumentException("content"); } contents = contentsDoc["body"].ToInnerXHtml(); } else if(MimeType.TEXT.Match(mimeType) || MimeType.FORM_URLENCODED.Match(mimeType)) { contents = request.AsText(); } else { throw new UnsupportedContentTypeInvalidArgumentException(mimeType); } bool isExistingPage = cur.ID != 0 && !cur.IsRedirect; string abort = context.GetParam("abort", "never").ToLowerInvariant(); if(isExistingPage && "exists" == abort) { throw new PageExistsConflictException(); } // Retrieve the title used for path normalization (if any) Title relToTitle = Utils.GetRelToTitleFromUrl(context); string editTimeStr = context.GetParam("edittime", null); DateTime editTime = DateTime.MinValue; if(!string.IsNullOrEmpty(editTimeStr)) { editTime = editTimeStr.EqualsInvariantIgnoreCase("now") ? DateTime.UtcNow : DbUtils.ToDateTime(editTimeStr); } string comment = context.GetParam("comment", String.Empty); string language = context.GetParam("language", null); string displayName = context.GetParam("title", null); int section = context.GetParam<int>("section", -1); if((section < -1) || ((!isExistingPage) && (0 < section))) { throw new SectionParamInvalidArgumentException(); } // determin how unsafe/invalid content should be handled bool removeIllegalElements = StringUtil.EqualsInvariantIgnoreCase(context.GetParam("tidy", "convert"), "remove"); // a new revision is created when no changes are detected when overwrite is enabled bool overwrite = context.GetParam<bool>("overwrite", false); // check whether the page exists and is not a redirect DateTime pageLastEditTime = cur.TimeStamp; OldBE baseOld = null; OldBE overwrittenOld = null; if(isExistingPage) { PageBL.AuthorizePage(DekiContext.Current.User, Permissions.UPDATE, cur, false); // ensure that 'edittime' is set if(DateTime.MinValue == editTime) { throw new PageEditTimeInvalidArgumentException(); } // check if page was modified since since the specified time if(pageLastEditTime > editTime) { // ensure we're allowed to save a modified page if("modified" == abort) { throw new PageModifiedConflictException(); } // if an edit has occurred since the specified edit time, retrieve the revision upon which it is based // NOTE: this can be null if someone created the page after the specified edit time (ie. no common base revision) baseOld = DbUtils.CurrentSession.Old_GetOldByTimestamp(cur.ID, editTime); // if editing a particular section, use the page upon which the section edits were based. if(0 < section && null == baseOld) { throw new PageHeadingInvalidArgumentException(); } } } // save page bool conflict; try { overwrittenOld = PageBL.Save(cur, baseOld, comment, contents, DekiMimeType.DEKI_TEXT, displayName, language, section, context.GetParam("xpath", null), DateTime.UtcNow, 0, true, removeIllegalElements, relToTitle, overwrite, out conflict); } catch(DekiScriptDocumentTooLargeException e) { response.Return(DreamMessage.Forbidden(string.Format(e.Message))); yield break; } // check if this post is part of an import action var importTimeStr = context.GetParam("importtime", null); if(!string.IsNullOrEmpty(importTimeStr)) { var dateModified = DbUtils.ToDateTime(importTimeStr); var lastImport = PropertyBL.Instance.GetPageProperty((uint)cur.ID, SiteImportBuilder.LAST_IMPORT); var lastImportDoc = new XDoc("last-import").Elem("etag", cur.Etag).Elem("date.modified", dateModified); var content = new ResourceContentBE(lastImportDoc); if(lastImport == null) { PropertyBL.Instance.CreateProperty((uint)cur.ID, PageBL.GetUri(cur), ResourceBE.ParentType.PAGE, SiteImportBuilder.LAST_IMPORT, content, string.Format("import at revision {0}", cur.Revision), content.ComputeHashString(), AbortEnum.Never); } else { PropertyBL.Instance.UpdatePropertyContent(lastImport, content, string.Format("updated import at revision {0}", cur.Revision), content.ComputeHashString(), AbortEnum.Never, PageBL.GetUri(cur), ResourceBE.ParentType.PAGE); } } // generate xml output XDoc editXml = new XDoc("edit") { PageBL.GetPageXml(cur, String.Empty) }; // if a non-redirect was overwritten, report it if((overwrittenOld != null) && (pageLastEditTime != editTime) && isExistingPage && conflict) { editXml.Attr("status", "conflict"); editXml.Add(baseOld == null ? new XDoc("page.base") : PageBL.GetOldXml(cur, baseOld, "base")); editXml.Add(PageBL.GetOldXml(cur, overwrittenOld, "overwritten")); } else { editXml.Attr("status", "success"); } response.Return(DreamMessage.Ok(editXml)); yield break; }
public Yield PostPageMessage(DreamContext context, DreamMessage request, Result<DreamMessage> response) { if(UserBL.IsAnonymous(DekiContext.Current.User)) { response.Return(DreamMessage.Forbidden("A logged-in user is required")); yield break; } if(request.ContentLength > 128 * 1024) { response.Return(DreamMessage.BadRequest("Content-length cannot exceed 128KB)")); yield break; } PageBE page = PageBL_AuthorizePage(context, null, Permissions.READ, false); XDoc body = new XDoc("body"); switch(request.ContentType.FullType) { case "text/plain": body.Attr("content-type", request.ContentType.ToString()) .Value(request.AsText()); break; default: body.Attr("content-type", request.ContentType.ToString()) .Add(request.ToDocument()); break; } string[] path = context.GetSuffixes(UriPathFormat.Original); path = ArrayUtil.SubArray(path, 1); DekiContext.Current.Instance.EventSink.PageMessage(DekiContext.Current.Now, page, DekiContext.Current.User, body, path); response.Return(DreamMessage.Ok()); yield break; }
public Yield PutFileDescription(DreamContext context, DreamMessage request, Result<DreamMessage> response) { PageBE parentPage; AttachmentBE file = GetAttachment(request, Permissions.UPDATE, false, false, out parentPage); // determine if description needs to be set or cleared string description = StringUtil.EqualsInvariant(context.Verb, "PUT") ? request.AsText() : string.Empty; file = AttachmentBL.Instance.SetDescription(file, description); response.Return(DreamMessage.Ok(AttachmentBL.Instance.GetFileXml(file, true, null, null))); yield break; }
// TODO (brigettek): this feature currently always fails. Commenting out until we need/fix it. // [DreamFeature("POST:site/notifyadmin", "Notifies the site admin")]/ // [DreamFeatureParam("subject", "string", "Subject of the notice")] // [DreamFeatureStatus(DreamStatus.Ok, "The request completed successfully")] // [DreamFeatureStatus(DreamStatus.BadRequest, "Invalid input parameter or request body")] // [DreamFeatureStatus(DreamStatus.Forbidden, "User must be logged in")] public Yield PostSiteNotifyAdmin(DreamContext context, DreamMessage request, Result<DreamMessage> response) { if((DekiContext.CurrentOrNull == null) || UserBL.IsAnonymous(DekiContext.Current.User)) { throw new SiteMustBeLoggedInForbiddenException(); } var siteBL = new SiteBL(); siteBL.SendNoticeToAdmin(context.GetParam("subject"), request.AsText(), request.ContentType); response.Return(DreamMessage.Ok()); yield break; }
public Yield PutPasswordChange(DreamContext context, DreamMessage request, Result<DreamMessage> response) { UserBE targetUser = GetUserFromUrlMustExist(); string password = request.AsText(); if(string.IsNullOrEmpty(password)) { throw new UserNewPasswordNotProvidedInvalidArgumentException(); } if(password.Length < 4) { throw new UserNewPasswordTooShortInvalidArgumentException(); } // Ensure that the password is being set only on local accounts ServiceBE s = ServiceBL.GetServiceById(targetUser.ServiceId); if(s != null && !ServiceBL.IsLocalAuthService(s)) { throw new UserCanOnlyChangeLocalUserPasswordInvalidOperationException(); } if(UserBL.IsAnonymous(targetUser)) { throw new UserCannotChangeAnonPasswordInvalidOperationException(); } // Admins can always change anyones password. if(PermissionsBL.IsUserAllowed(DekiContext.Current.User, Permissions.ADMIN)) { //For admins a currentpassword is option but if given then it should be validated string currentPwd = context.GetParam("currentpassword", string.Empty); if(!string.IsNullOrEmpty(currentPwd)) { if(!AuthBL.IsValidAuthenticationForLocalUser(targetUser, currentPwd)) { throw new UserCurrentPasswordIncorrectForbiddenException(); } } } else if(DekiContext.Current.User.ID == targetUser.ID) { if(context.GetParam("altpassword", false)) { throw new UserCannotChangeOwnAltPasswordInvalidOperationException(); } // User changing their own password requires knowledge of their current password string currentPwd = context.GetParam("currentpassword"); if(!AuthBL.IsValidAuthenticationForLocalUser(DekiContext.Current.User, currentPwd)) { throw new UserCurrentPasswordIncorrectForbiddenException(); } } else { throw new UserMustBeTargetOrAdminForbiddenException(); } bool altPassword = context.GetParam<bool>("altpassword", false); targetUser = UserBL.SetPassword(targetUser, password, altPassword); if(DekiContext.Current.User.ID == targetUser.ID) { response.Return(BuildSetAuthTokenResponse(AuthBL.CreateAuthTokenForUser(targetUser), null)); } else { response.Return(DreamMessage.Ok()); } yield break; }