public ActionResult ClearLinkFlair(int?submissionID) { if (submissionID == null) { return(HybridError(ErrorViewModel.GetErrorViewModel(ErrorType.NotFound))); //return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } // get model for selected submission var submissionModel = _db.Submission.Find(submissionID); if (submissionModel == null || submissionModel.IsDeleted) { return(HybridError(ErrorViewModel.GetErrorViewModel(ErrorType.NotFound))); //return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } // check if caller is subverse moderator, if not, deny posting if (!ModeratorPermission.HasPermission(User, submissionModel.Subverse, Domain.Models.ModeratorAction.AssignFlair)) { return(HybridError(ErrorViewModel.GetErrorViewModel(ErrorType.Unauthorized))); } // clear flair and save submission submissionModel.FlairCss = null; submissionModel.FlairLabel = null; _db.SaveChanges(); DataCache.Submission.Remove(submissionID.Value); return(JsonResult(CommandResponse.FromStatus(Status.Success))); //return new HttpStatusCodeResult(HttpStatusCode.OK); }
public async Task <CommandResponse <string> > RegenerateThumbnail(int submissionID) { DemandAuthentication(); // get model for selected submission var submission = _db.Submission.Find(submissionID); var response = CommandResponse.FromStatus(Status.Error); if (submission == null || submission.IsDeleted) { return(CommandResponse.FromStatus("", Status.Error, "Submission is missing or deleted")); } var subverse = submission.Subverse; // check if caller is subverse moderator, if not, deny change if (!ModeratorPermission.HasPermission(User, subverse, Domain.Models.ModeratorAction.AssignFlair)) { return(CommandResponse.FromStatus("", Status.Denied, "Moderator Permissions are not satisfied")); } try { throw new NotImplementedException(); await _db.SaveChangesAsync(); return(CommandResponse.FromStatus("", Status.Success)); } catch (Exception ex) { return(CommandResponse.Error <CommandResponse <string> >(ex)); } }
public async Task <CommandResponse <bool?> > SetSubverseListChange(DomainReference setReference, string subverse, SubscriptionAction action) { DemandAuthentication(); var set = GetSet(setReference.Name, setReference.OwnerName); if (set == null) { return(CommandResponse.FromStatus <bool?>(null, Status.Denied, "Set cannot be found")); } //Check Perms var perms = SetPermission.GetPermissions(set.Map(), User.Identity); if (!perms.EditList) { return(CommandResponse.FromStatus <bool?>(null, Status.Denied, "User not authorized to modify set")); } var sub = GetSubverseInfo(subverse); if (sub == null) { return(CommandResponse.FromStatus <bool?>(null, Status.Denied, "Subverse cannot be found")); } return(await SetSubverseListChange(set, sub, action).ConfigureAwait(CONSTANTS.AWAIT_CAPTURE_CONTEXT)); }
public async Task <CommandResponse <bool> > ToggleNSFW(int submissionID) { DemandAuthentication(); // get model for selected submission var submission = _db.Submission.Find(submissionID); var response = CommandResponse.FromStatus(Status.Error); if (submission == null || submission.IsDeleted) { return(CommandResponse.FromStatus(false, Status.Error, "Submission is missing or deleted")); } var subverse = submission.Subverse; if (!User.Identity.Name.IsEqual(submission.UserName)) { // check if caller is subverse moderator, if not, deny change if (!ModeratorPermission.HasPermission(User, subverse, Domain.Models.ModeratorAction.AssignFlair)) { return(CommandResponse.FromStatus(false, Status.Denied, "Moderator Permissions are not satisfied")); } } try { submission.IsAdult = !submission.IsAdult; await _db.SaveChangesAsync(); return(CommandResponse.FromStatus(submission.IsAdult, Status.Success)); } catch (Exception ex) { return(CommandResponse.Error <CommandResponse <bool> >(ex)); } }
public async Task <ActionResult> Reply(MessageReplyViewModel message) { if (!ModelState.IsValid) { PreventSpamAttribute.Reset(HttpContext); if (Request.IsAjaxRequest()) { return(new JsonResult(CommandResponse.FromStatus(Status.Invalid, ModelState.GetFirstErrorMessage()))); } else { return(View()); } } if (message.ID <= 0) { return(RedirectToAction("Sent", "Messages")); } var cmd = new SendMessageReplyCommand(message.ID, message.Body).SetUserContext(User); var response = await cmd.Execute(); return(JsonResult(response)); }
public async Task <CommandResponse <Comment> > DistinguishComment(int commentID) { DemandAuthentication(); var response = CommandResponse.FromStatus <Comment>(null, Status.Invalid); var comment = await this.GetComment(commentID); if (comment != null) { // check to see if request came from comment author if (User.Identity.Name == comment.UserName) { // check to see if comment author is also sub mod or sub admin for comment sub if (ModeratorPermission.HasPermission(User, comment.Subverse, ModeratorAction.DistinguishContent)) { var m = new DapperMulti(); var u = new DapperUpdate(); //u.Update = $"{SqlFormatter.Table("Comment")} SET \"IsDistinguished\" = {SqlFormatter.ToggleBoolean("\"IsDistinguished\"")}"; u.Update = SqlFormatter.UpdateSetBlock($"\"IsDistinguished\" = {SqlFormatter.ToggleBoolean("\"IsDistinguished\"")}", SqlFormatter.Table("Comment")); u.Where = "\"ID\" = @id"; u.Parameters.Add("id", commentID); m.Add(u); var s = new DapperQuery(); s.Select = $"\"IsDistinguished\" FROM {SqlFormatter.Table("Comment")}"; s.Where = "\"ID\" = @id"; m.Add(s); //ProTip: The actual execution of code is important. var result = await _db.Connection.ExecuteScalarAsync <bool>(m.ToCommandDefinition()); comment.IsDistinguished = result; response = CommandResponse.FromStatus(comment, Status.Success); } else { response.Message = "User does not have permissions to distinquish content"; response.Status = Status.Denied; } } else { response.Message = "User can only distinquish owned content"; response.Status = Status.Denied; } } else { response.Message = "Comment can not be found"; response.Status = Status.Denied; } return(response); }
//These are meant to bridge the gap between the UI and ajax calls. protected ActionResult HybridError(ErrorViewModel errorViewModel) { if (Request.IsAjaxRequest()) { return(JsonResult(CommandResponse.FromStatus(Status.Error, errorViewModel.Description))); } else { return(ErrorView(errorViewModel)); } }
public async Task <CommandResponse <bool?> > DeleteSet(DomainReference setReference) { DemandAuthentication(); var set = GetSet(setReference.Name, setReference.OwnerName); if (set == null) { return(CommandResponse.FromStatus <bool?>(null, Status.Denied, "Set cannot be found")); } //Check Perms var perms = SetPermission.GetPermissions(set.Map(), User.Identity); if (!perms.Delete) { return(CommandResponse.FromStatus <bool?>(null, Status.Denied, "User not authorized to delete set")); } var param = new DynamicParameters(); param.Add("ID", set.ID); var conn = _db.Connection; //var tran = conn.BeginTransaction(System.Data.IsolationLevel.Serializable); try { var d = new DapperDelete(); d.Delete = SqlFormatter.DeleteBlock(SqlFormatter.Table("SubverseSetSubscription")); d.Where = "\"SubverseSetID\" = @ID"; await conn.ExecuteAsync(d.ToString(), param); d.Delete = SqlFormatter.DeleteBlock(SqlFormatter.Table("SubverseSetList")); d.Where = "\"SubverseSetID\" = @ID"; await conn.ExecuteAsync(d.ToString(), param); d.Delete = SqlFormatter.DeleteBlock(SqlFormatter.Table("SubverseSet")); d.Where = "\"ID\" = @ID"; await conn.ExecuteAsync(d.ToString(), param); //tran.Commit(); return(CommandResponse.FromStatus <bool?>(true, Status.Success)); } catch (Exception ex) { //tran.Rollback(); return(CommandResponse.Error <CommandResponse <bool?> >(ex)); } }
public override CommandResponse <IVoteRestriction> Evaluate(IPrincipal principal) { var evaluation = CommandResponse.FromStatus <IVoteRestriction>(this, Status.Success); using (var repo = new Repository()) { var count = repo.UserContributionCount(principal.Identity.Name, (Voat.Domain.Models.ContentType)ContentType, Subverse, DateRange); if (count < MinimumCount) { evaluation = CommandResponse.FromStatus <IVoteRestriction>(this, Status.Denied, $"User only has {count} and needs {MinimumCount}"); } } return(evaluation); }
public async Task <ActionResult> Update(Set set) { if (ModelState.IsValid) { var cmd = new UpdateSetCommand(set).SetUserContext(User); var result = await cmd.Execute(); return(JsonResult(result)); } else { return(JsonResult(CommandResponse.FromStatus(Status.Invalid, ModelState.GetFirstErrorMessage()))); } }
public async Task <ActionResult> ReportContent(ReportContentModel model) { if (ModelState.IsValid) { var cmd = new SaveRuleReportCommand(model.ContentType, model.ID, model.RuleSetID.Value).SetUserContext(User); var result = await cmd.Execute(); return(JsonResult(result)); } else { PreventSpamAttribute.Reset(HttpContext); return(JsonResult(CommandResponse.FromStatus(Status.Error, ModelState.GetFirstErrorMessage()))); } }
public async Task <ActionResult> DeleteComment(int id) { if (ModelState.IsValid) { var cmd = new DeleteCommentCommand(id, "This feature is not yet implemented").SetUserContext(User); var result = await cmd.Execute(); return(base.JsonResult(result)); } else { return(base.JsonResult(CommandResponse.FromStatus(Status.Error, ModelState.GetFirstErrorMessage()))); //return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } }
public static async Task <CommandResponse <string> > GenerateAvatar(Stream imageStream, string fileName, string mimetype, bool purgeTempFile = true) { var fileManager = FileManager.Instance; var fileCheck = fileManager.IsUploadPermitted(fileName, FileType.Avatar, mimetype, imageStream.Length); if (fileCheck.Success) { var key = new FileKey(); key.FileType = FileType.Avatar; key.ID = await GenerateRandomFilename(Path.GetExtension(fileName), FileType.Avatar); await GenerateImageThumbnail(fileManager, key, imageStream, VoatSettings.Instance.AvatarSize, false, false); return(CommandResponse.Successful(key.ID)); } return(CommandResponse.FromStatus <string>(null, fileCheck.Status, fileCheck.Message)); }
public async Task <ActionResult> EditComment([FromBody()] CommentEditInput commentModel) { if (ModelState.IsValid) { var cmd = new EditCommentCommand(commentModel.ID, commentModel.Content).SetUserContext(User); var result = await cmd.Execute(); if (!result.Success) { PreventSpamAttribute.Reset(HttpContext); } return(JsonResult(result)); } else { PreventSpamAttribute.Reset(HttpContext); return(JsonResult(CommandResponse.FromStatus(Status.Error, ModelState.GetFirstErrorMessage()))); } }
public async Task <CommandResponse> BanGlobally(IEnumerable <GenericReference <BanType> > banList, string reason) { DemandAuthentication(); var statements = new List <DapperInsert>(); foreach (var banItem in banList) { var insert = new DapperInsert(); string tablename = "", columnname = ""; insert.Parameters.Add("CreatedBy", User.Identity.Name); insert.Parameters.Add("CreationDate", CurrentDate); insert.Parameters.Add("Reason", reason); switch (banItem.Type) { case BanType.Domain: insert.Parameters.Add("Value", banItem.Name.ToNormalized(Normalization.Lower)); tablename = "BannedDomain"; columnname = "Domain"; break; case BanType.User: insert.Parameters.Add("Value", banItem.Name); tablename = "BannedUser"; columnname = "UserName"; break; } insert.Insert = SqlFormatter.Table(tablename) + $" (\"{columnname}\", \"Reason\", \"CreatedBy\", \"CreationDate\")"; insert.Insert += $" SELECT @Value, @Reason, @CreatedBy, @CreationDate WHERE NOT EXISTS (SELECT * FROM {SqlFormatter.Table(tablename)} WHERE \"{columnname}\" = @Value)"; statements.Add(insert); } //This needs to executed in a single batch, but since a low traffic scenario this is ok foreach (var statement in statements) { await _db.Connection.ExecuteAsync(statement.ToString(), statement.Parameters); } return(CommandResponse.FromStatus(Status.Success)); }
public async Task <ActionResult> EditSubmission([FromBody] EditSubmission model) { if (ModelState.IsValid) { var cmd = new EditSubmissionCommand(model.SubmissionId, new Domain.Models.UserSubmission() { Content = model.SubmissionContent }).SetUserContext(User); var response = await cmd.Execute(); if (response.Success) { DataCache.Submission.Remove(model.SubmissionId); CacheHandler.Instance.Remove(CachingKey.Submission(model.SubmissionId)); //return Json(new { response = response.Response.FormattedContent }); } return(JsonResult(response)); } return(JsonResult(CommandResponse.FromStatus(Status.Error, ModelState.GetFirstErrorMessage()))); }
public ActionResult ApplyLinkFlair(int?submissionID, int?flairId) { if (submissionID == null || flairId == null) { return(HybridError(ErrorViewModel.GetErrorViewModel(ErrorType.NotFound))); //return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } var submission = _db.Submission.Find(submissionID); if (submission == null || submission.IsDeleted) { return(HybridError(ErrorViewModel.GetErrorViewModel(ErrorType.NotFound))); //return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } if (!ModeratorPermission.HasPermission(User, submission.Subverse, Domain.Models.ModeratorAction.AssignFlair)) { return(HybridError(ErrorViewModel.GetErrorViewModel(ErrorType.Unauthorized))); //return new HttpUnauthorizedResult(); } // find flair by id, apply it to submission var flairModel = _db.SubverseFlair.Find(flairId); if (flairModel == null || flairModel.Subverse != submission.Subverse) { return(HybridError(ErrorViewModel.GetErrorViewModel(ErrorType.NotFound))); } //return new HttpStatusCodeResult(HttpStatusCode.BadRequest); // apply flair and save submission submission.FlairCss = flairModel.CssClass; submission.FlairLabel = flairModel.Label; _db.SaveChanges(); DataCache.Submission.Remove(submissionID.Value); return(JsonResult(CommandResponse.FromStatus(Status.Success))); //return new HttpStatusCodeResult(HttpStatusCode.OK); }
public async Task <ActionResult> SubmitComment(CommentInput commentModel) { if (!ModelState.IsValid) { //we want to reset spam filter if the modelstate was not triggered by preventspam PreventSpamAttribute.Reset(HttpContext); return(JsonResult(CommandResponse.FromStatus(Status.Error, ModelState.GetFirstErrorMessage()))); } else { var cmd = new CreateCommentCommand(commentModel.SubmissionID.Value, commentModel.ParentID, commentModel.Content).SetUserContext(User); var result = await cmd.Execute(); if (result.Success) { //if good return formatted comment if (Request.IsAjaxRequest()) { var comment = result.Response; comment.IsOwner = true; ViewBag.CommentId = comment.ID; //why? ViewBag.rootComment = comment.ParentID == null; //why? return(PartialView("~/Views/Shared/Comments/_SubmissionComment.cshtml", comment)); } else { return(new EmptyResult()); } } else { PreventSpamAttribute.Reset(HttpContext); return(JsonResult(result)); } } }
public virtual CommandResponse IsUploadPermitted(string fileName, FileType fileType, string mimeType = null, long?length = null) { var result = CommandResponse.FromStatus(Status.Success); var uploadLimit = VoatSettings.Instance.FileUploadLimits.FirstOrDefault(x => x.Type == fileType); if (uploadLimit == null) { uploadLimit = new FileUploadLimit() { Type = fileType }; } switch (fileType) { case FileType.Avatar: case FileType.Thumbnail: case FileType.Badge: if (!uploadLimit.IsExtensionAllowed(fileName)) { result = CommandResponse.FromStatus(Status.Invalid, "File type is not permitted for upload"); } else if (!uploadLimit.IsMimeTypeAllowed(mimeType)) { result = CommandResponse.FromStatus(Status.Invalid, "Mime type is not permitted for upload"); } if (length == null || length.Value == 0 || (uploadLimit.ByteLimit > 0 && length > uploadLimit.ByteLimit)) { result = CommandResponse.FromStatus(Status.Invalid, $"File length is too big or too small but we aren't saying (Hint: {Math.Round(uploadLimit.ByteLimit / (decimal)1000000, 1)} MB max)"); } break; } return(result); }
public async Task <CommandResponse> ToggleSticky(int submissionID, string subverse = null, bool clearExisting = false, int stickyLimit = 3) { DemandAuthentication(); // get model for selected submission var submission = _db.Submission.Find(submissionID); var response = CommandResponse.FromStatus(Status.Error); if (submission == null || submission.IsDeleted) { return(CommandResponse.FromStatus(Status.Error, "Submission is missing or deleted")); } //Eventually we want users to be able to sticky other subs posts, but for now make sure we don't allow this subverse = submission.Subverse; // check if caller is subverse moderator, if not, deny change if (!ModeratorPermission.HasPermission(User, subverse, Domain.Models.ModeratorAction.AssignStickies)) { return(CommandResponse.FromStatus(Status.Denied, "Moderator Permissions are not satisfied")); } int affectedCount = 0; try { // find and clear current sticky if toggling var existingSticky = _db.StickiedSubmission.FirstOrDefault(s => s.SubmissionID == submissionID); if (existingSticky != null) { _db.StickiedSubmission.Remove(existingSticky); affectedCount += -1; } else { if (clearExisting) { // remove all stickies for subverse matching submission subverse _db.StickiedSubmission.RemoveRange(_db.StickiedSubmission.Where(s => s.Subverse == subverse)); affectedCount = 0; } // set new submission as sticky var stickyModel = new Data.Models.StickiedSubmission { SubmissionID = submissionID, CreatedBy = User.Identity.Name, CreationDate = Repository.CurrentDate, Subverse = subverse }; _db.StickiedSubmission.Add(stickyModel); affectedCount += 1; } //limit sticky counts var currentCount = _db.StickiedSubmission.Count(x => x.Subverse == subverse); if ((currentCount + affectedCount) > stickyLimit) { return(CommandResponse.FromStatus(Status.Denied, $"Stickies are limited to {stickyLimit}")); } await _db.SaveChangesAsync(); StickyHelper.ClearStickyCache(submission.Subverse); return(CommandResponse.FromStatus(Status.Success)); } catch (Exception ex) { return(CommandResponse.Error <CommandResponse>(ex)); } }
public static async Task <CommandResponse <string> > GenerateThumbnail(Uri uri, bool purgeTempFile = true) { if (VoatSettings.Instance.OutgoingTraffic.Enabled) { var url = uri.ToString(); if (!String.IsNullOrEmpty(url) && UrlUtility.IsUriValid(url)) { try { //Ok this all needs to be centralized, we should only make 1 request to a remote resource using (var httpResource = new HttpResource( new Uri(url), new HttpResourceOptions() { AllowAutoRedirect = true }, VoatSettings.Instance.OutgoingTraffic.Proxy.ToWebProxy())) { var result = await httpResource.GiddyUp(); if (httpResource.IsImage) { var fileManager = FileManager.Instance; var fileCheck = fileManager.IsUploadPermitted(url, FileType.Thumbnail, httpResource.Response.Content.Headers.ContentType.MediaType, httpResource.Stream.Length); if (fileCheck.Success) { var key = new FileKey(); key.FileType = FileType.Thumbnail; key.ID = await GenerateRandomFilename(".jpg", FileType.Thumbnail); var stream = httpResource.Stream; await GenerateImageThumbnail(fileManager, key, stream, VoatSettings.Instance.ThumbnailSize, true); return(CommandResponse.Successful(key.ID)); } } else if (httpResource.Image != null) { //just do it. again. return(await GenerateThumbnail(httpResource.Image)); } } } catch (Exception ex) { EventLogger.Instance.Log(ex, new { url = url, type = FileType.Thumbnail }); var response = CommandResponse.Error <CommandResponse <string> >(ex); response.Response = ""; //Make sure this returns string.empty as other failures do. return(response); } } EventLogger.Instance.Log(new LogInformation() { Type = LogType.Debug, Category = "Thumbnail Diag", Message = "Default Response", Data = new { url = url }, Origin = VoatSettings.Instance.Origin }); } return(CommandResponse.FromStatus <string>("", Status.Invalid)); }
public async Task <CommandResponse <Domain.Models.Set> > CreateOrUpdateSet(Set set) { DemandAuthentication(); set.Name = set.Name.TrimSafe(); //Evaulate Rules var context = new VoatRuleContext(User); context.PropertyBag.Set = set; var outcome = VoatRulesEngine.Instance.EvaluateRuleSet(context, RuleScope.CreateSet); if (!outcome.IsAllowed) { return(MapRuleOutCome <Set>(outcome, null)); } var existingSet = _db.SubverseSet.FirstOrDefault(x => x.ID == set.ID); if (existingSet != null) { var perms = SetPermission.GetPermissions(existingSet.Map(), User.Identity); if (!perms.EditProperties) { return(CommandResponse.FromStatus <Set>(null, Status.Denied, "User does not have permission to edit this set")); } //HACK: Need to clear this entry out of cache if name changes and check name if (!existingSet.Name.IsEqual(set.Name)) { if (_db.SubverseSet.Any(x => x.Name.ToLower() == set.Name.ToLower() && x.UserName.ToLower() == UserName.ToLower())) { return(CommandResponse.FromStatus <Set>(null, Status.Denied, "A set with this name already exists")); } CacheHandler.Instance.Remove(CachingKey.Set(existingSet.Name, existingSet.UserName)); } existingSet.Name = set.Name; existingSet.Title = set.Title; existingSet.Description = set.Description; existingSet.IsPublic = set.IsPublic; await _db.SaveChangesAsync().ConfigureAwait(CONSTANTS.AWAIT_CAPTURE_CONTEXT); return(CommandResponse.FromStatus <Set>(existingSet.Map(), Status.Success)); } else { //Validation - MOVE TO RULES SYSTEM MAYBE if (!VoatSettings.Instance.SetCreationEnabled || VoatSettings.Instance.MaximumOwnedSets <= 0) { return(CommandResponse.FromStatus <Set>(null, Status.Denied, "Set creation is currently disabled")); } if (VoatSettings.Instance.MaximumOwnedSets > 0) { var d = new DapperQuery(); d.Select = $"SELECT COUNT(*) FROM {SqlFormatter.Table("SubverseSet", "subSet")}"; d.Where = "subSet.\"Type\" = @Type AND subSet.\"UserName\" = @UserName"; d.Parameters.Add("Type", (int)SetType.Normal); d.Parameters.Add("UserName", UserName); var setCount = _db.Connection.ExecuteScalar <int>(d.ToString(), d.Parameters); if (setCount >= VoatSettings.Instance.MaximumOwnedSets) { return(CommandResponse.FromStatus <Set>(null, Status.Denied, $"Sorry, Users are limited to {VoatSettings.Instance.MaximumOwnedSets} sets and you currently have {setCount}")); } } //Create new set try { var setCheck = GetSet(set.Name, UserName); if (setCheck != null) { return(CommandResponse.FromStatus <Set>(null, Status.Denied, "A set with same name and owner already exists")); } var newSet = new SubverseSet { Name = set.Name, Title = set.Title, Description = set.Description, UserName = UserName, Type = (int)SetType.Normal, IsPublic = set.IsPublic, CreationDate = Repository.CurrentDate, SubscriberCount = 1, //Owner is a subscriber. Reminds me of that hair club commercial: I"m not only the Set Owner, I'm also a subscriber. }; _db.SubverseSet.Add(newSet); await _db.SaveChangesAsync().ConfigureAwait(CONSTANTS.AWAIT_CAPTURE_CONTEXT); _db.SubverseSetSubscription.Add(new SubverseSetSubscription() { SubverseSetID = newSet.ID, UserName = UserName, CreationDate = CurrentDate }); await _db.SaveChangesAsync().ConfigureAwait(CONSTANTS.AWAIT_CAPTURE_CONTEXT); return(CommandResponse.Successful(newSet.Map())); } catch (Exception ex) { return(CommandResponse.Error <CommandResponse <Set> >(ex)); } } }
public async Task <CommandResponse <Domain.Models.Vote> > SaveVote(Domain.Models.Vote vote) { DemandAuthentication(); var newDataModel = VoteDomainMaps.Map(vote); var domainModel = vote; //UPDATE if (newDataModel.ID > 0) { var existingDataModel = await GetVoteDataModel(newDataModel.ID); //Check some basics if (existingDataModel == null) { return(CommandResponse.FromStatus <Domain.Models.Vote>(null, Status.Error, "Vote can not be found")); } if (!existingDataModel.CreatedBy.IsEqual(User.Identity.Name) && !User.IsInAnyRole(new[] { UserRole.GlobalAdmin, UserRole.Admin })) { return(CommandResponse.FromStatus <Domain.Models.Vote>(null, Status.Error, "Vote can not be edited by current user")); } if (existingDataModel.StartDate <= CurrentDate) { return(CommandResponse.FromStatus <Domain.Models.Vote>(null, Status.Error, "Vote can not be edited once voting has begun")); } //TODO: Verify incoming model ids all belong to this vote var restrictionsAreBelongToUs = newDataModel.VoteRestrictions.Where(x => x.ID > 0).All(x => existingDataModel.VoteRestrictions.Any(e => e.ID == x.ID)); if (!restrictionsAreBelongToUs) { return(CommandResponse.FromStatus <Domain.Models.Vote>(null, Status.Error, "Message integrity violated (Restrictions)")); } var optionsAreBelongToUs = newDataModel.VoteOptions.Where(x => x.ID > 0).All(x => existingDataModel.VoteOptions.Any(e => e.ID == x.ID)); if (!optionsAreBelongToUs) { return(CommandResponse.FromStatus <Domain.Models.Vote>(null, Status.Error, "Message integrity violated (Options)")); } var outcomesAreBelongToUs = newDataModel.VoteOptions.Where(x => x.ID > 0).SelectMany(x => x.VoteOutcomes.Where(o => o.ID > 0)).All(x => existingDataModel.VoteOptions.SelectMany(y => y.VoteOutcomes).Any(e => e.ID == x.ID)); if (!outcomesAreBelongToUs) { return(CommandResponse.FromStatus <Domain.Models.Vote>(null, Status.Error, "Message integrity violated (Outcomes)")); } existingDataModel.LastEditDate = CurrentDate; existingDataModel.Title = newDataModel.Title; existingDataModel.Content = newDataModel.Content; existingDataModel.FormattedContent = newDataModel.FormattedContent; newDataModel.VoteOptions.ForEachIndex((option, index) => { //TODO: Ensure ID belongs to proper vote (aka fuzzy will exploit this) if (option.ID > 0) { //Update Existing var existingOption = existingDataModel.VoteOptions.FirstOrDefault(x => x.ID == option.ID); existingOption.Title = option.Title; existingOption.Content = option.Content; existingOption.FormattedContent = option.FormattedContent; existingOption.SortOrder = index; option.VoteOutcomes.ForEachIndex((outcome, oIndex) => { if (outcome.ID > 0) { var existingOutcome = existingDataModel.VoteOptions[index].VoteOutcomes.FirstOrDefault(x => x.ID == outcome.ID); existingOutcome.Type = outcome.Type; existingOutcome.Data = outcome.Data; } else { var newOutcome = new VoteOutcome(); newOutcome.Type = outcome.Type; newOutcome.Data = outcome.Data; existingOption.VoteOutcomes.Add(newOutcome); } }); //Remove deleted outcomes var deletedOutcomes = existingOption.VoteOutcomes.Where(c => !option.VoteOutcomes.Any(n => c.ID == n.ID)).ToList(); deletedOutcomes.ForEach(x => existingOption.VoteOutcomes.Remove(x)); } else { //Add new var newOption = new Data.Models.VoteOption(); newOption.Title = option.Title; newOption.Content = option.Content; newOption.FormattedContent = option.FormattedContent; newOption.SortOrder = index; existingDataModel.VoteOptions.Add(newOption); option.VoteOutcomes.ForEachIndex((outcome, oIndex) => { var newOutcome = new VoteOutcome(); newOutcome.Type = outcome.Type; newOutcome.Data = outcome.Data; newOption.VoteOutcomes.Add(newOutcome); }); } }); //Remove deleted options var deletedOptions = existingDataModel.VoteOptions.Where(c => !newDataModel.VoteOptions.Any(n => c.ID == n.ID)).ToList(); deletedOptions.ForEach(x => existingDataModel.VoteOptions.Remove(x)); //handle restrictions newDataModel.VoteRestrictions.ForEachIndex((restriction, index) => { if (restriction.ID > 0) { //Update Existing var existingRestriction = existingDataModel.VoteRestrictions.FirstOrDefault(x => x.ID == restriction.ID); existingRestriction.Type = restriction.Type; existingRestriction.Data = restriction.Data; } else { //Add new var newRestriction = new Data.Models.VoteRestriction(); newRestriction.Type = restriction.Type; newRestriction.Data = restriction.Data; existingDataModel.VoteRestrictions.Add(newRestriction); } }); //Remove deleted options var deletedRestrictions = existingDataModel.VoteRestrictions.Where(c => !newDataModel.VoteRestrictions.Any(n => c.ID == n.ID)).ToList(); deletedRestrictions.ForEach(x => existingDataModel.VoteRestrictions.Remove(x)); await _db.SaveChangesAsync(); return(CommandResponse.FromStatus <Domain.Models.Vote>(existingDataModel.Map(), Status.Success)); } //NEW else { newDataModel.CreatedBy = User.Identity.Name; newDataModel.CreationDate = CurrentDate; //TODO: Set start end dates according to logic newDataModel.StartDate = CurrentDate.AddDays(7); newDataModel.EndDate = CurrentDate.AddDays(14); _db.Vote.Add(newDataModel); await _db.SaveChangesAsync(); domainModel = VoteDomainMaps.Map(newDataModel); return(CommandResponse.FromStatus <Domain.Models.Vote>(newDataModel.Map(), Status.Success)); } }