public async Task<ActionResult> SubverseStylesheetEditor(Subverse updatedModel) { try { if (!ModelState.IsValid) return View("~/Views/Subverses/Admin/SubverseSettings.cshtml"); var existingSubverse = _db.Subverses.Find(updatedModel.name); // check if subverse exists before attempting to edit it if (existingSubverse != null) { // check if user requesting edit is authorized to do so for current subverse // check that the user requesting to edit subverse settings is subverse owner! var subAdmin = _db.SubverseAdmins.FirstOrDefault(x => x.SubverseName == updatedModel.name && x.Username == User.Identity.Name && x.Power <= 2); // user was not authorized to commit the changes, drop attempt if (subAdmin == null) return new EmptyResult(); if (updatedModel.stylesheet != null) { if (updatedModel.stylesheet.Length < 50001) { existingSubverse.stylesheet = updatedModel.stylesheet; } else { ModelState.AddModelError(string.Empty, "Sorry, custom CSS limit is set to 50000 characters."); return View("~/Views/Subverses/Admin/SubverseSettings.cshtml"); } } else { existingSubverse.stylesheet = updatedModel.stylesheet; } await _db.SaveChangesAsync(); DataCache.Subverse.Remove(existingSubverse.name); // go back to this subverse return RedirectToAction("SubverseIndex", "Subverses", new { subversetoshow = updatedModel.name }); } ModelState.AddModelError(string.Empty, "Sorry, The subverse you are trying to edit does not exist."); return View("~/Views/Subverses/Admin/SubverseSettings.cshtml"); } catch (Exception) { ModelState.AddModelError(string.Empty, "Something bad happened."); return View("~/Views/Subverses/Admin/SubverseSettings.cshtml"); } }
public async Task<ActionResult> SubverseSettings(Subverse updatedModel) { try { if (!ModelState.IsValid) return View("~/Views/Subverses/Admin/SubverseSettings.cshtml"); var existingSubverse = _db.Subverses.Find(updatedModel.name); // check if subverse exists before attempting to edit it if (existingSubverse != null) { // check if user requesting edit is authorized to do so for current subverse if (!UserHelper.IsUserSubverseModerator(User.Identity.Name, updatedModel.name)) { return new EmptyResult(); } // TODO investigate if EntityState is applicable here and use that instead // db.Entry(updatedModel).State = EntityState.Modified; existingSubverse.description = updatedModel.description; existingSubverse.sidebar = updatedModel.sidebar; if (updatedModel.stylesheet != null) { if (updatedModel.stylesheet.Length < 50001) { existingSubverse.stylesheet = updatedModel.stylesheet; } else { ModelState.AddModelError(string.Empty, "Sorry, custom CSS limit is set to 50000 characters."); return View("~/Views/Subverses/Admin/SubverseSettings.cshtml"); } } else { existingSubverse.stylesheet = updatedModel.stylesheet; } existingSubverse.rated_adult = updatedModel.rated_adult; existingSubverse.private_subverse = updatedModel.private_subverse; existingSubverse.enable_thumbnails = updatedModel.enable_thumbnails; existingSubverse.authorized_submitters_only = updatedModel.authorized_submitters_only; existingSubverse.exclude_sitewide_bans = updatedModel.exclude_sitewide_bans; existingSubverse.minimumdownvoteccp = updatedModel.minimumdownvoteccp; // these properties are currently not implemented but they can be saved and edited for future use existingSubverse.type = updatedModel.type; existingSubverse.label_submit_new_link = updatedModel.label_submit_new_link; existingSubverse.label_sumit_new_selfpost = updatedModel.label_sumit_new_selfpost; existingSubverse.submission_text = updatedModel.submission_text; existingSubverse.allow_default = updatedModel.allow_default; if (existingSubverse.anonymized_mode && updatedModel.anonymized_mode == false) { ModelState.AddModelError(string.Empty, "Sorry, this subverse is permanently locked to anonymized mode."); return View("~/Views/Subverses/Admin/SubverseSettings.cshtml"); } // only subverse owners should be able to convert a sub to anonymized mode if (UserHelper.IsUserSubverseAdmin(User.Identity.Name, updatedModel.name)) { existingSubverse.anonymized_mode = updatedModel.anonymized_mode; } await _db.SaveChangesAsync(); DataCache.Subverse.Remove(existingSubverse.name); // go back to this subverse return RedirectToAction("SubverseIndex", "Subverses", new { subversetoshow = updatedModel.name }); // user was not authorized to commit the changes, drop attempt } ModelState.AddModelError(string.Empty, "Sorry, The subverse you are trying to edit does not exist."); return View("~/Views/Subverses/Admin/SubverseSettings.cshtml"); } catch (Exception) { ModelState.AddModelError(string.Empty, "Something bad happened."); return View("~/Views/Subverses/Admin/SubverseSettings.cshtml"); } }
public async Task<ActionResult> CreateSubverse([Bind(Include = "Name, Title, Description, Type, Sidebar, Creation_date, Owner")] AddSubverse subverseTmpModel) { // abort if model state is invalid if (!ModelState.IsValid) return View(); int minimumCcp = Settings.MinimumCcp; int maximumOwnedSubs = Settings.MaximumOwnedSubs; // verify recaptcha if user has less than minimum required CCP if (Karma.CommentKarma(User.Identity.Name) < minimumCcp) { // begin recaptcha check bool isCaptchaCodeValid = await ReCaptchaUtility.Validate(Request); if (!isCaptchaCodeValid) { ModelState.AddModelError("", "Incorrect recaptcha answer."); // TODO // SET PREVENT SPAM DELAY TO 0 return View(); } } // only allow users with less than maximum allowed subverses to create a subverse var amountOfOwnedSubverses = _db.SubverseAdmins .Where(s => s.Username == User.Identity.Name && s.Power == 1) .ToList(); if (amountOfOwnedSubverses.Count >= maximumOwnedSubs) { ModelState.AddModelError(string.Empty, "Sorry, you can not own more than " + maximumOwnedSubs + " subverses."); return View(); } // check if subverse already exists if (DataCache.Subverse.Retrieve(subverseTmpModel.Name) != null) { ModelState.AddModelError(string.Empty, "Sorry, The subverse you are trying to create already exists, but you can try to claim it by submitting a takeover request to /v/subverserequest."); return View(); } try { // setup default values and create the subverse var subverse = new Subverse { name = subverseTmpModel.Name, title = "/v/" + subverseTmpModel.Name, description = subverseTmpModel.Description, sidebar = subverseTmpModel.Sidebar, creation_date = DateTime.Now, type = "link", enable_thumbnails = true, rated_adult = false, private_subverse = false, minimumdownvoteccp = 0, admin_disabled = false }; _db.Subverses.Add(subverse); await _db.SaveChangesAsync(); // subscribe user to the newly created subverse Voat.Utilities.UserHelper.SubscribeToSubverse(subverseTmpModel.Owner, subverse.name); // register user as the owner of the newly created subverse var tmpSubverseAdmin = new SubverseAdmin { SubverseName = subverseTmpModel.Name, Username = User.Identity.Name, Power = 1 }; _db.SubverseAdmins.Add(tmpSubverseAdmin); await _db.SaveChangesAsync(); // go to newly created Subverse return RedirectToAction("SubverseIndex", "Subverses", new { subversetoshow = subverseTmpModel.Name }); } catch (Exception) { ModelState.AddModelError(string.Empty, "Something bad happened, please report this to /v/voatdev. Thank you."); return View(); } }
// various spam checks, to be replaced with new rule engine public static async Task<string> PreAddSubmissionCheck(Message submissionModel, HttpRequestBase request, string userName, Subverse targetSubverse, Func<HttpRequestBase, Task<bool>> captchaValidator) { // TODO: reject if a submission with this title was posted in the last 60 minutes // check posting quotas if user is posting to subs they do not moderate if (!UserHelper.IsUserSubverseModerator(userName, submissionModel.Subverse)) { // reject if user has reached global daily submission quota if (UserHelper.UserDailyGlobalPostingQuotaUsed(userName)) { return ("You have reached your daily global submission quota."); } // reject if user has reached global hourly submission quota if (UserHelper.UserHourlyGlobalPostingQuotaUsed(userName)) { return ("You have reached your hourly global submission quota."); } // check if user has reached hourly posting quota for target subverse if (UserHelper.UserHourlyPostingQuotaForSubUsed(userName, submissionModel.Subverse)) { return ("You have reached your hourly submission quota for this subverse."); } // check if user has reached daily posting quota for target subverse if (UserHelper.UserDailyPostingQuotaForSubUsed(userName, submissionModel.Subverse)) { return ("You have reached your daily submission quota for this subverse."); } } // verify recaptcha if user has less than 25 CCP var userCcp = Karma.CommentKarma(userName); if (userCcp < 25) { bool isCaptchaCodeValid = await captchaValidator(request); if (!isCaptchaCodeValid) { // TODO: SET PREVENT SPAM DELAY TO 0 return ("Incorrect recaptcha answer."); } } // if user CCP or SCP is less than -50, allow only X submissions per 24 hours var userScp = Karma.LinkKarma(userName); if (userCcp <= -50 || userScp <= -50) { var quotaUsed = UserHelper.UserDailyPostingQuotaForNegativeScoreUsed(userName); if (quotaUsed) { return ("You have reached your daily submission quota. Your current quota is " + Settings.DailyPostingQuotaForNegativeScore + " submission(s) per 24 hours."); } } // check if subverse has "authorized_submitters_only" set and dissalow submission if user is not allowed submitter if (targetSubverse.authorized_submitters_only) { if (!UserHelper.IsUserSubverseModerator(userName, targetSubverse.name)) { return ("You are not authorized to submit links or start discussions in this subverse. Please contact subverse moderators for authorization."); } } // null is returned if all checks have passed return null; }
// add new link submission public static async Task<string> AddNewSubmission(Message submissionModel, Subverse targetSubverse, string userName) { using (var db = new voatEntities()) { // LINK TYPE SUBMISSION if (submissionModel.Type == 2) { // strip unicode if title contains unicode if (ContainsUnicode(submissionModel.Linkdescription)) { submissionModel.Linkdescription = StripUnicode(submissionModel.Linkdescription); } // reject if title is whitespace or < than 5 characters if (submissionModel.Linkdescription.Length < 5 || String.IsNullOrWhiteSpace(submissionModel.Linkdescription)) { return ("The title may not be less than 5 characters."); } // make sure the input URI is valid if (!UrlUtility.IsUriValid(submissionModel.MessageContent)) { // ABORT return ("The URI you are trying to submit is invalid."); } // check if target subvere allows submissions from globally banned hostnames if (!targetSubverse.exclude_sitewide_bans) { // check if hostname is banned before accepting submission var domain = UrlUtility.GetDomainFromUri(submissionModel.MessageContent); if (BanningUtility.IsHostnameBanned(domain)) { // ABORT return ("The hostname you are trying to submit is banned."); } } // check if user has reached daily crossposting quota if (UserHelper.DailyCrossPostingQuotaUsed(userName, submissionModel.MessageContent)) { // ABORT return ("You have reached your daily crossposting quota for this URL."); } // check if target subverse has thumbnails setting enabled before generating a thumbnail if (targetSubverse.enable_thumbnails) { // try to generate and assign a thumbnail to submission model submissionModel.Thumbnail = await ThumbGenerator.ThumbnailFromSubmissionModel(submissionModel); } // flag the submission as anonymized if it was submitted to a subverse with active anonymized_mode if (targetSubverse.anonymized_mode) { submissionModel.Anonymized = true; } else { submissionModel.Name = userName; } // accept submission and save it to the database submissionModel.Subverse = targetSubverse.name; submissionModel.Likes = 1; db.Messages.Add(submissionModel); // update last submission received date for target subverse targetSubverse.last_submission_received = DateTime.Now; await db.SaveChangesAsync(); } else // MESSAGE TYPE SUBMISSION { // strip unicode if submission contains unicode if (ContainsUnicode(submissionModel.Title)) { submissionModel.Title = StripUnicode(submissionModel.Title); } // reject if title is whitespace or less than 5 characters if (submissionModel.Title.Length < 5 || String.IsNullOrWhiteSpace(submissionModel.Title)) { return ("Sorry, submission title may not be less than 5 characters."); } // flag the submission as anonymized if it was submitted to a subverse with active anonymized_mode if (targetSubverse.anonymized_mode) { submissionModel.Anonymized = true; } else { submissionModel.Name = userName; } // grab server timestamp and modify submission timestamp to have posting time instead of "started writing submission" time submissionModel.Subverse = targetSubverse.name; submissionModel.Date = DateTime.Now; submissionModel.Likes = 1; db.Messages.Add(submissionModel); // update last submission received date for target subverse targetSubverse.last_submission_received = DateTime.Now; if (ContentProcessor.Instance.HasStage(ProcessingStage.InboundPreSave)) { submissionModel.MessageContent = ContentProcessor.Instance.Process(submissionModel.MessageContent, ProcessingStage.InboundPreSave, submissionModel); } await db.SaveChangesAsync(); if (ContentProcessor.Instance.HasStage(ProcessingStage.InboundPostSave)) { ContentProcessor.Instance.Process(submissionModel.MessageContent, ProcessingStage.InboundPostSave, submissionModel); } } } // null is returned if no errors were raised return null; }
public async Task<ActionResult> SubverseSettings(Subverse updatedModel) { try { if (!ModelState.IsValid) return View("~/Views/Subverses/Admin/SubverseSettings.cshtml"); var existingSubverse = _db.Subverses.Find(updatedModel.Name); // check if subverse exists before attempting to edit it if (existingSubverse != null) { // check if user requesting edit is authorized to do so for current subverse if (!UserHelper.IsUserSubverseModerator(User.Identity.Name, updatedModel.Name)) { return new EmptyResult(); } // TODO investigate if EntityState is applicable here and use that instead // db.Entry(updatedModel).State = EntityState.Modified; existingSubverse.Description = updatedModel.Description; existingSubverse.SideBar = updatedModel.SideBar; if (updatedModel.Stylesheet != null) { if (updatedModel.Stylesheet.Length < 50001) { existingSubverse.Stylesheet = updatedModel.Stylesheet; } else { ModelState.AddModelError(string.Empty, "Sorry, custom CSS limit is set to 50000 characters."); return View("~/Views/Subverses/Admin/SubverseSettings.cshtml"); } } else { existingSubverse.Stylesheet = updatedModel.Stylesheet; } existingSubverse.IsAdult = updatedModel.IsAdult; existingSubverse.IsPrivate = updatedModel.IsPrivate; existingSubverse.IsThumbnailEnabled = updatedModel.IsThumbnailEnabled; existingSubverse.IsAuthorizedOnly = updatedModel.IsAuthorizedOnly; existingSubverse.ExcludeSitewideBans = updatedModel.ExcludeSitewideBans; existingSubverse.MinCCPForDownvote = updatedModel.MinCCPForDownvote; // these properties are currently not implemented but they can be saved and edited for future use existingSubverse.Type = updatedModel.Type; existingSubverse.SubmitLinkLabel = updatedModel.SubmitLinkLabel; existingSubverse.SubmitPostLabel = updatedModel.SubmitPostLabel; existingSubverse.SubmissionText = updatedModel.SubmissionText; existingSubverse.IsDefaultAllowed = updatedModel.IsDefaultAllowed; if (existingSubverse.IsAnonymized && updatedModel.IsAnonymized == false) { ModelState.AddModelError(string.Empty, "Sorry, this subverse is permanently locked to anonymized mode."); return View("~/Views/Subverses/Admin/SubverseSettings.cshtml"); } // only subverse owners should be able to convert a sub to anonymized mode if (UserHelper.IsUserSubverseAdmin(User.Identity.Name, updatedModel.Name)) { existingSubverse.IsAnonymized = updatedModel.IsAnonymized; } await _db.SaveChangesAsync(); DataCache.Subverse.Remove(existingSubverse.Name); // go back to this subverse return RedirectToAction("SubverseIndex", "Subverses", new { subversetoshow = updatedModel.Name }); // user was not authorized to commit the changes, drop attempt } ModelState.AddModelError(string.Empty, "Sorry, The subverse you are trying to edit does not exist."); return View("~/Views/Subverses/Admin/SubverseSettings.cshtml"); } catch (Exception) { ModelState.AddModelError(string.Empty, "Something bad happened."); return View("~/Views/Subverses/Admin/SubverseSettings.cshtml"); } }