diff --git a/r2/r2/controllers/api.py b/r2/r2/controllers/api.py index 0bf41bae9..e464bcc1d 100644 --- a/r2/r2/controllers/api.py +++ b/r2/r2/controllers/api.py @@ -526,8 +526,9 @@ class ApiController(RedditController): body = VComment('comment')) def POST_editcomment(self, res, comment, body): res._update('status_' + comment._fullname, innerHTML = '') - if (not res._chk_error(errors.BAD_COMMENT, comment._fullname) and - not res._chk_error(errors.NOT_AUTHOR, comment._fullname)): + + if res._chk_errors((errors.BAD_COMMENT, errors.COMMENT_TOO_LONG, errors.NOT_AUTHOR), + comment._fullname): comment.body = body if not c.user_is_admin: comment.editted = True comment._commit() @@ -541,12 +542,13 @@ class ApiController(RedditController): @Json @validate(VUser(), VModhash(), - VRatelimit(rate_user = True, rate_ip = True, - prefix = "rate_comment_"), + VRatelimit(rate_user = True, rate_ip = True, prefix = "rate_comment_"), ip = ValidIP(), parent = VSubmitParent('id'), comment = VComment('comment')) def POST_comment(self, res, parent, comment, ip): + + #wipe out the status message res._update('status_' + parent._fullname, innerHTML = '') should_ratelimit = True @@ -572,9 +574,8 @@ class ApiController(RedditController): if not should_ratelimit: c.errors.remove(errors.RATELIMIT) - if res._chk_error(errors.BAD_COMMENT, parent._fullname) or \ - res._chk_error(errors.COMMENT_TOO_LONG, parent._fullname) or \ - res._chk_error(errors.RATELIMIT, parent._fullname): + if res._chk_errors((errors.BAD_COMMENT,errors.COMMENT_TOO_LONG, errors.RATELIMIT), + parent._fullname): res._focus("comment_reply_" + parent._fullname) return res._show('reply_' + parent._fullname) diff --git a/r2/r2/controllers/validator/validator.py b/r2/r2/controllers/validator/validator.py index f527b9dda..291f45e9e 100644 --- a/r2/r2/controllers/validator/validator.py +++ b/r2/r2/controllers/validator/validator.py @@ -204,11 +204,20 @@ class VLength(Validator): return title class VTitle(VLength): + only_whitespace = re.compile(r"^\s*$", re.UNICODE) + def __init__(self, item, length = 200, **kw): VLength.__init__(self, item, length = length, empty_error = errors.NO_TITLE, length_error = errors.TITLE_TOO_LONG, **kw) + def run(self, title): + title = VLength.run(self, title) + if title and self.only_whitespace.match(title): + c.errors.add(errors.NO_TITLE) + else: + return title + class VComment(VLength): def __init__(self, item, length = 10000, **kw): VLength.__init__(self, item, length = length, **kw) diff --git a/r2/r2/lib/menus.py b/r2/r2/lib/menus.py index 73edd1186..fd34d3f8f 100644 --- a/r2/r2/lib/menus.py +++ b/r2/r2/lib/menus.py @@ -242,7 +242,8 @@ class NavButton(Styled): style = "plain", **kw): # keep original dest to check against c.location when rendering - self.aliases = set(aliases + [dest.strip('/')]) + self.aliases = set(a.rstrip('/') for a in aliases) + self.aliases.add(dest.rstrip('/')) self.dest = dest Styled.__init__(self, style = style, sr_path = sr_path, @@ -261,6 +262,7 @@ class NavButton(Styled): base_path = ("%s/%s/" % (base_path, self.dest)).replace('//', '/') self.bare_path = _force_unicode(base_path.replace('//', '/')).lower() + self.bare_path = self.bare_path.rstrip('/') # append the query string base_path += query_string(p) @@ -274,10 +276,11 @@ class NavButton(Styled): if self.opt: return request.params.get(self.opt, '') in self.aliases else: - stripped_path = _force_unicode(request.path.rstrip('/')).lower() - if stripped_path == self.bare_path.rstrip('/'): + stripped_path = request.path.rstrip('/').lower() + ustripped_path = _force_unicode(stripped_path) + if stripped_path == self.bare_path: return True - if stripped_path in (a.rstrip('/') for a in self.aliases): + if stripped_path in self.aliases: return True def selected_title(self): diff --git a/r2/r2/models/admintools.py b/r2/r2/models/admintools.py index 8a757c7ba..c1a7f43ea 100644 --- a/r2/r2/models/admintools.py +++ b/r2/r2/models/admintools.py @@ -19,12 +19,17 @@ # All portions of the code written by CondeNet are Copyright (c) 2006-2008 # CondeNet, Inc. All Rights Reserved. ################################################################################ +from r2.lib.utils import tup class AdminTools(object): - def spam(self, thing): - pass + def spam(self, thing, amount = 1, mark_as_spam = True, **kw): + things = tup(thing) + for t in things: + if mark_as_spam: + t._spam = (amount > 0) + t._commit() - def report(self, thing): + def report(self, thing, amount = 1): pass def add_thing(self, thing): diff --git a/r2/r2/public/static/comments.js b/r2/r2/public/static/comments.js index fee449157..51fdf2e40 100644 --- a/r2/r2/public/static/comments.js +++ b/r2/r2/public/static/comments.js @@ -166,10 +166,10 @@ function reply(id) { function chkcomment(form) { if(form.replace.value) { - return post_form(form, 'editcomment'); + return post_form(form, 'editcomment', null, null, true); } else { - return post_form(form, 'comment'); + return post_form(form, 'comment', null, null, true); } }; diff --git a/r2/r2/public/static/utils.js b/r2/r2/public/static/utils.js index d4ad11643..528822fe5 100644 --- a/r2/r2/public/static/utils.js +++ b/r2/r2/public/static/utils.js @@ -103,7 +103,7 @@ function buildParams(parameters) { } var api_loc = '/api/'; -function redditRequest(op, parameters, worker_in) { +function redditRequest(op, parameters, worker_in, block) { var action = op; var worker = worker_in; if (!parameters) { @@ -118,11 +118,26 @@ function redditRequest(op, parameters, worker_in) { } else { worker = function(r) { + remove_ajax_work(action); return worker_in(r); } } - new Ajax.Request(op, {parameters: make_get_params(parameters), - onComplete: worker}); + if(block == null || add_ajax_work(action)) { + new Ajax.Request(op, {parameters: make_get_params(parameters), + onComplete: worker}); + } +} + +var _ajax_work_queue = {}; +function add_ajax_work(op) { + if(_ajax_work_queue[op]) { + return false; + } + _ajax_work_queue[op] = true; + return true; +} +function remove_ajax_work(op) { + _ajax_work_queue[op] = false; } function redditRequest_no_response(op, parameters) { @@ -156,6 +171,7 @@ function handleResponse(action) { } }; var responseHandler = function(r) { + remove_ajax_work(action); var res_obj = parse_response(r); if(!res_obj) { if($('status')) @@ -293,7 +309,7 @@ function change_state(link, type) { return false; } -function post_form(form, where, statusfunc, nametransformfunc) { +function post_form(form, where, statusfunc, nametransformfunc, block) { var p = {uh: modhash}; var id = _id(form); var status = $("status"); @@ -318,7 +334,7 @@ function post_form(form, where, statusfunc, nametransformfunc) { } } } - redditRequest(where, p); + redditRequest(where, p, null, block); return false; } diff --git a/r2/r2/templates/messagecompose.html b/r2/r2/templates/messagecompose.html index d6c7f5770..748e04beb 100644 --- a/r2/r2/templates/messagecompose.html +++ b/r2/r2/templates/messagecompose.html @@ -1,4 +1,4 @@ -## "The contents of this file are subject to the Common Public Attribution +## The contents of this file are subject to the Common Public Attribution ## License Version 1.0. (the "License"); you may not use this file except in ## compliance with the License. You may obtain a copy of the License at ## http://code.reddit.com/LICENSE. The License is based on the Mozilla Public @@ -27,7 +27,7 @@ ${success_field(_("your message has been delivered"), successful=thing.success)} -<%call expr="submit_form(onsubmit='return post_form(this, \'compose\')', +<%call expr="submit_form(onsubmit='return post_form(this, \'compose\', null, null, true)', method='post', action='/message/compose', _class='iform')">