Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Subreddit admin updates #536

Closed
wants to merge 9 commits into
from
View
@@ -1220,14 +1220,21 @@ def POST_vote(self, dir, thing, ip, vote_type):
VModhash(),
# nop is safe: handled after auth checks below
stylesheet_contents = nop('stylesheet_contents'),
- prevstyle = VLength('prevstyle', max_length=256),
+ prevstyle = VLength('prevstyle', max_length=36),
op = VOneOf('op',['save','preview']))
@api_doc(api_section.subreddits)
def POST_subreddit_stylesheet(self, form, jquery,
stylesheet_contents = '', prevstyle='', op='save'):
+ if form.has_errors("prevstyle", errors.TOO_LONG):
+ return
report, parsed = c.site.parse_css(stylesheet_contents)
-
+
+ # Use the raw POST value as we need to tell the difference between
+ # None/Undefined and an empty string. The validators use a default
+ # value with both of those cases and would need to be changed.
+ # In order to avoid breaking functionality, this was done instead.
+ prevstyle = request.post.get('prevstyle')
if not report:
return self.abort(403,'forbidden')
@@ -1257,6 +1264,8 @@ def POST_subreddit_stylesheet(self, form, jquery,
form.set_inputs(prevstyle=str(wr._id))
ModAction.create(c.site, c.user, 'wikirevise', description)
except ConflictException as e:
+ c.errors.add(errors.CONFLICT, field="stylesheet_contents")
+ form.has_errors("stylesheet_contents", errors.CONFLICT)
form.set_html(".status", _('conflict error'))
form.set_html(".errors ul", _('There was a conflict while editing the stylesheet'))
form.find('#conflict_box').show()
@@ -1265,11 +1274,9 @@ def POST_subreddit_stylesheet(self, form, jquery,
form.set_html('#conflict_diff', e.htmldiff)
form.find('.errors').show()
return
- except ValueError:
- # Revision does not belong to page
- return
- except tdb_cassandra.NotFound:
- # Previous revision not found
+ except (tdb_cassandra.NotFound, ValueError):
+ c.errors.add(errors.BAD_REVISION, field="prevstyle")
+ form.has_errors("prevstyle", errors.BAD_REVISION)
return
jquery.apply_stylesheet(stylesheet_contents_parsed)
if op == 'preview':
@@ -1456,8 +1463,8 @@ def POST_upload_sr_img(self, file, header, sponsor, name, form_id, img_type):
type = VOneOf('type', ('public', 'private', 'restricted', 'archived')),
link_type = VOneOf('link_type', ('any', 'link', 'self')),
wikimode = VOneOf('wikimode', ('disabled', 'modonly', 'anyone')),
- wiki_edit_karma = VInt("wiki_edit_karma", coerce=False, min=0),
- wiki_edit_age = VInt("wiki_edit_age", coerce=False, min=0),
+ wiki_edit_karma = VInt("wiki_edit_karma", coerce=False, num_default=0, min=0),
+ wiki_edit_age = VInt("wiki_edit_age", coerce=False, num_default=0, min=0),
ip = ValidIP(),
sponsor_text =VLength('sponsorship-text', max_length = 500),
sponsor_name =VLength('sponsorship-name', max_length = 64),
@@ -1469,6 +1476,7 @@ def POST_site_admin(self, form, jquery, name, ip, sr,
sponsor_text, sponsor_url, sponsor_name, **kw):
def apply_wikid_field(sr, form, pagename, value, prev, field, error):
+ id_field_name = 'prev_%s_id' % field
try:
wikipage = wiki.WikiPage.get(sr, pagename)
except tdb_cassandra.NotFound:
@@ -1478,22 +1486,19 @@ def apply_wikid_field(sr, form, pagename, value, prev, field, error):
setattr(sr, field, value)
if not wr:
return True
- setattr(sr, "prev_" + field + "_id", str(wikipage.revision))
+ setattr(sr, id_field_name, str(wikipage.revision))
ModAction.create(sr, c.user, 'wikirevise', details=wiki.modactions.get(pagename))
return True
except ConflictException as e:
- c.errors.add(errors.CONFLICT, field = field)
+ c.errors.add(errors.CONFLICT, field=field)
form.has_errors(field, errors.CONFLICT)
form.parent().set_html('.status', error)
form.find('#%s_conflict_box' % field).show()
- form.set_inputs(**{'prev_%s_id' % field: e.new_id, '%s_conflict_old' % field: e.your, field: e.new})
+ form.set_inputs(**{id_field_name: e.new_id, '%s_conflict_old' % field: e.your, field: e.new})
form.set_html('#%s_conflict_diff' % field, e.htmldiff)
- except ValueError:
- # Revision does not belong to page
- pass
- except tdb_cassandra.NotFound:
- # Previous revision not found
- pass
+ except (tdb_cassandra.NotFound, ValueError):
+ c.errors.add(errors.BAD_REVISION, field=id_field_name)
+ form.has_errors(id_field_name, errors.BAD_REVISION)
return False
# the status button is outside the form -- have to reset by hand
@@ -1502,34 +1507,41 @@ def apply_wikid_field(sr, form, pagename, value, prev, field, error):
redir = False
kw = dict((k, v) for k, v in kw.iteritems()
if k in ('name', 'title', 'domain', 'description',
- 'prev_description_id', 'prev_public_description_id',
'show_media', 'show_cname_sidebar', 'type', 'link_type', 'lang',
'css_on_cname', 'header_title', 'over_18',
'wikimode', 'wiki_edit_karma', 'wiki_edit_age',
'allow_top', 'public_description'))
-
- description = kw.pop('description')
- prev_desc = kw.pop('prev_description_id')
-
+
public_description = kw.pop('public_description')
- prev_pubdesc = kw.pop('prev_public_description_id')
+ description = kw.pop('description')
+
+ # Use the raw POST value as we need to tell the difference between
+ # None/Undefined and an empty string. The validators use a default
+ # value with both of those cases and would need to be changed.
+ # In order to avoid breaking functionality, this was done instead.
+ prev_desc = request.post.get('prev_description_id')
+ prev_pubdesc = request.post.get('prev_public_description_id')
def update_wiki_text(sr):
- apply_wikid_field(sr,
- form,
- 'config/sidebar',
- description,
- prev_desc,
- 'description',
- _("Sidebar was not saved"))
-
- apply_wikid_field(sr,
- form,
- 'config/description',
- public_description,
- prev_pubdesc,
- 'public_description',
- _("Description was not saved"))
+ error = False
+ if not apply_wikid_field(sr,
+ form,
+ 'config/sidebar',
+ description,
+ prev_desc,
+ 'description',
+ _("Sidebar was not saved")):
+ error = True
+
+ if not apply_wikid_field(sr,
+ form,
+ 'config/description',
+ public_description,
+ prev_pubdesc,
+ 'public_description',
+ _("Description was not saved")):
+ error = True
+ return not error
#if a user is banned, return rate-limit errors
@@ -1560,7 +1572,12 @@ def update_wiki_text(sr):
form.has_errors('public_description', errors.TOO_LONG) or
form.has_errors('description', errors.TOO_LONG)):
pass
-
+ elif sr and (form.has_errors(('prev_public_description_id',
+ 'prev_description_id'), errors.TOO_LONG)):
+ pass
+ elif (form.has_errors(('wiki_edit_karma', 'wiki_edit_age'),
+ errors.BAD_NUMBER)):
+ pass
#creating a new reddit
elif not sr:
#sending kw is ok because it was sanitized above
@@ -1596,7 +1613,7 @@ def update_wiki_text(sr):
#assume sr existed, or was just built
old_domain = sr.domain
- update_wiki_text(sr)
+ success = update_wiki_text(sr)
if not sr.domain:
del kw['css_on_cname']
@@ -1614,7 +1631,8 @@ def update_wiki_text(sr):
# flag search indexer that something has changed
changed(sr)
- form.parent().set_html('.status', _("saved"))
+ if success:
+ form.parent().set_html('.status', _("saved"))
if form.has_error():
return
@@ -55,7 +55,7 @@
('USER_DOESNT_EXIST', _("that user doesn't exist")),
('NO_USER', _('please enter a username')),
('INVALID_PREF', "that preference isn't valid"),
- ('BAD_NUMBER', _("that number isn't in the right range (%(min)d to %(max)d)")),
+ ('BAD_NUMBER', _("that number isn't in the right range (%(range)s)")),
('BAD_STRING', _("you used a character here that we can't handle")),
('BAD_BID', _("your bid must be at least $%(min)d per day and no more than to $%(max)d in total.")),
('ALREADY_SUB', _("that link has already been submitted")),
@@ -92,6 +92,7 @@
('NO_LINKS', _("that reddit only allows text posts")),
('TOO_OLD', _("that's a piece of history now; it's too late to reply to it")),
('BAD_CSS_NAME', _('invalid css name')),
+ ('BAD_REVISION', _('invalid revision ID')),
('TOO_MUCH_FLAIR_CSS', _('too many flair css classes')),
('BAD_FLAIR_TARGET', _('not a valid flair target')),
('OAUTH2_INVALID_CLIENT', _('invalid client id')),
@@ -1157,19 +1157,21 @@ def param_docs(self):
class VNumber(Validator):
def __init__(self, param, min=None, max=None, coerce = True,
- error = errors.BAD_NUMBER, *a, **kw):
+ error=errors.BAD_NUMBER, num_default=None,
+ *a, **kw):
self.min = self.cast(min) if min is not None else None
self.max = self.cast(max) if max is not None else None
self.coerce = coerce
self.error = error
+ self.num_default = num_default
Validator.__init__(self, param, *a, **kw)
def cast(self, val):
raise NotImplementedError
def run(self, val):
if not val:
- return
+ return self.num_default
try:
val = self.cast(val)
if self.min is not None and val < self.min:
@@ -1184,8 +1186,15 @@ def run(self, val):
raise ValueError, ""
return val
except ValueError:
- self.set_error(self.error, msg_params = dict(min=self.min,
- max=self.max))
+ if self.max is None and self.min is None:
+ range = ""
+ elif self.max is None:
+ range = _("%(min)d to any") % dict(min=self.min)
+ elif self.min is None:
+ range = _("any to %(max)d") % dict(max=self.max)
+ else:
+ range = _("%(min)d to %(max)d") % dict(min=self.min, max=self.max)
+ self.set_error(self.error, msg_params=dict(range=range))
class VInt(VNumber):
def cast(self, val):
@@ -235,7 +235,11 @@ class WikiApiController(WikiController):
content=VMarkdown(('content')))
def POST_wiki_edit(self, pageandprevious, content):
page, previous = pageandprevious
- previous = previous._id if previous else None
+ # Use the raw POST value as we need to tell the difference between
+ # None/Undefined and an empty string. The validators use a default
+ # value with both of those cases and would need to be changed.
+ # In order to avoid breaking functionality, this was done instead.
+ previous = previous._id if previous else request.post.get('previous')
try:
if page.name == 'config/stylesheet':
report, parsed = c.site.parse_css(content, verify=False)
View
@@ -272,6 +272,7 @@ def has_editor(self, editor):
def revise(self, content, previous = None, author=None, force=False, reason=None):
if self.content == content:
return
+ force = True if previous is None else force
max_length = special_length_restrictions_bytes.get(self.name, MAX_PAGE_LENGTH_BYTES)
if len(content) > max_length:
raise ContentLengthError(max_length)
@@ -97,6 +97,10 @@
%if thing.site:
<input type="hidden" name="prev_public_description_id" value="${thing.site.prev_public_description_id}"/>
<input type="hidden" name="prev_description_id" value="${thing.site.prev_description_id}"/>
+ ${error_field("TOO_LONG", "prev_public_description_id")}
+ ${error_field("TOO_LONG", "prev_description_id")}
+ ${error_field("BAD_REVISION", "prev_public_description_id")}
+ ${error_field("BAD_REVISION", "prev_description_id")}
%endif
<%utils:line_field title="${_('language')}">
@@ -174,6 +178,7 @@
%else:
<input id="wiki_edit_karma" type="text" name="wiki_edit_karma" value="100" />
%endif
+ ${error_field("BAD_NUMBER", "wiki_edit_karma")}
</div>
<div class="delete-field">
<label for="wiki_edit_age">${_('Account age (days) required to edit and create wiki pages:')}</label>
@@ -183,6 +188,7 @@
%else:
<input id="wiki_edit_age" type="text" name="wiki_edit_age" value="0" />
%endif
+ ${error_field("BAD_NUMBER", "wiki_edit_age")}
</div>
</div>
</%utils:line_field>
@@ -42,6 +42,8 @@
<h2>${_("stylesheet")}</h2>
<input type="hidden" name="prevstyle" value="${thing.site.prev_stylesheet}"/>
+ ${error_field("TOO_LONG", "prevstyle")}
+ ${error_field("BAD_REVISION", "prevstyle")}
<div class="sheets">
<div style="width: 100%" class="col">
<div>