Move permissions (and related strings) to lib.

This commit is contained in:
Logan Hanks
2013-02-05 14:49:47 -08:00
parent 890916859f
commit 9a23deb878
8 changed files with 207 additions and 165 deletions

View File

@@ -169,6 +169,13 @@ class StringsSource(Source):
self.keys = keys
self.prepend = prepend
@staticmethod
def _encoder(obj):
from r2.lib import strings, translation
if isinstance(obj, strings.StringHandler):
return obj.string_dict
raise TypeError
def get_source(self):
from pylons.i18n import get_lang
from r2.lib import strings, translation
@@ -184,7 +191,7 @@ class StringsSource(Source):
else:
data = dict(strings.strings)
output = self.prepend + json.dumps(data) + "\n"
output = self.prepend + json.dumps(data, default=self._encoder) + "\n"
if self.lang:
translation.set_lang(old_lang)

97
r2/r2/lib/permissions.py Normal file
View File

@@ -0,0 +1,97 @@
# 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
# License Version 1.1, but Sections 14 and 15 have been added to cover use of
# software over a computer network and provide for limited attribution for the
# Original Developer. In addition, Exhibit A has been modified to be consistent
# with Exhibit B.
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
# the specific language governing rights and limitations under the License.
#
# The Original Code is reddit.
#
# The Original Developer is the Initial Developer. The Initial Developer of
# the Original Code is reddit Inc.
#
# All portions of the code written by reddit are Copyright (c) 2006-2013 reddit
# Inc. All Rights Reserved.
###############################################################################
from pylons.i18n import _
class PermissionSet(dict):
ALL = 'all'
info = None
def __init__(self, *args, **kwargs):
super(PermissionSet, self).__init__(*args, **kwargs)
@classmethod
def loads(cls, encoded, validate=False):
if not encoded:
return cls()
result = cls(((term[1:], term[0] == '+')
for term in encoded.split(',')))
if result.get(cls.ALL) == False:
del result[cls.ALL]
if validate and not result.is_valid():
raise ValueError
return result
def dumps(self):
if self.is_superuser():
return '+all'
return ','.join('-+'[bool(v)] + k for k, v in sorted(self.iteritems()))
def is_superuser(self):
return bool(super(PermissionSet, self).get(self.ALL))
def is_valid(self):
if not self.info:
return False
for k in self:
if k != self.ALL and k not in self.info:
return False
return True
def get(self, key, default=None):
if self.info and self.is_superuser():
return True if key in self.info else default
return super(PermissionSet, self).get(key, default)
def __getitem__(self, key):
if self.info and self.is_superuser():
return key in self.info
return super(PermissionSet, self).get(key, False)
class ModeratorPermissionSet(PermissionSet):
info = dict(
access=dict(
title=_('access'),
description=_('manage the lists of contributors and banned users'),
),
config=dict(
title=_('config'),
description=_('edit settings, sidebar, css, and images'),
),
flair=dict(
title=_('flair'),
description=_('manage user flair, link flair, and flair templates'),
),
posts=dict(
title=_('posts'),
description=_(
'use the approve, remove, spam, distinguish, and nsfw buttons'),
),
)
@classmethod
def loads(cls, encoded, **kwargs):
if encoded is None:
return cls(all=True)
return super(ModeratorPermissionSet, cls).loads(encoded, **kwargs)

View File

@@ -33,6 +33,7 @@ from pylons.i18n import _, ungettext, get_lang
import random
import babel.numbers
from r2.lib.permissions import ModeratorPermissionSet
from r2.lib.translation import set_lang
__all__ = ['StringHandler', 'strings', 'PluralManager', 'plurals',
@@ -192,6 +193,15 @@ Note: there are a couple of places outside of your subreddit where someone can c
missing_credit_city = _("missing city"),
missing_credit_state = _("missing state or province"),
missing_credit_zip = _("missing zip code"),
permissions = dict(
info=dict(
moderator=ModeratorPermissionSet.info,
moderator_invite=ModeratorPermissionSet.info,
),
all_msg=_("full permissions"),
none_msg=_("no permissions"),
),
)
class StringHandler(object):
@@ -213,7 +223,7 @@ class StringHandler(object):
if isinstance(rval, (str, unicode)):
return _(rval)
elif isinstance(rval, dict):
return dict((k, _(v)) for k, v in rval.iteritems())
return StringHandler(**rval)
else:
raise AttributeError

View File

@@ -144,14 +144,6 @@ def js_config(extra_config=None):
"clicktracker_url": g.clicktracker_url,
"uitracker_url": g.uitracker_url,
"static_root": static(''),
"permissions": {
"info": {
"moderator": ModeratorPermissionSet.info,
"moderator_invite": ModeratorPermissionSet.info,
},
"all_msg": _("full permissions"),
"none_msg": _("no permissions"),
},
}
if extra_config:

View File

@@ -37,6 +37,7 @@ from r2.lib.db.userrel import UserRel
from r2.lib.db.operators import lower, or_, and_, desc
from r2.lib.errors import UserRequiredException
from r2.lib.memoize import memoize
from r2.lib.permissions import ModeratorPermissionSet
from r2.lib.utils import tup, interleave_lists, last_modified_multi, flatten
from r2.lib.utils import timeago, summarize_markdown
from r2.lib.cache import sgm
@@ -57,81 +58,6 @@ from r2.models.wiki import WikiPage
import os.path
import random
class PermissionSet(dict):
ALL = 'all'
info = None
def __init__(self, *args, **kwargs):
super(PermissionSet, self).__init__(*args, **kwargs)
@classmethod
def loads(cls, encoded, validate=False):
if not encoded:
return cls()
result = cls(((term[1:], term[0] == '+')
for term in encoded.split(',')))
if result.get(cls.ALL) == False:
del result[cls.ALL]
if validate and not result.is_valid():
raise ValueError
return result
def dumps(self):
if self.is_superuser():
return '+all'
return ','.join('-+'[bool(v)] + k for k, v in sorted(self.iteritems()))
def is_superuser(self):
return bool(super(PermissionSet, self).get(self.ALL))
def is_valid(self):
if not self.info:
return False
for k in self:
if k != self.ALL and k not in self.info:
return False
return True
def get(self, key, default=None):
if self.info and self.is_superuser():
return True if key in self.info else default
return super(PermissionSet, self).get(key, default)
def __getitem__(self, key):
if self.info and self.is_superuser():
return key in self.info
return super(PermissionSet, self).get(key, False)
class ModeratorPermissionSet(PermissionSet):
info = dict(
access=dict(
title=_('access'),
description=_('manage the lists of contributors and banned users'),
),
config=dict(
title=_('config'),
description=_('edit settings, sidebar, css, and images'),
),
flair=dict(
title=_('flair'),
description=_('manage user flair, link flair, and flair templates'),
),
posts=dict(
title=_('posts'),
description=_(
'use the approve, remove, spam, distinguish, and nsfw buttons'),
),
)
@classmethod
def loads(cls, encoded, **kwargs):
if encoded is None:
return cls(all=True)
return super(ModeratorPermissionSet, cls).loads(encoded, **kwargs)
class SubredditExists(Exception): pass
class Subreddit(Thing, Printable):

View File

@@ -212,7 +212,7 @@ r.ui.PermissionEditor = function(el) {
var permission_type = params.type
var name = params.name
this.form_id = permission_type + "-permissions-" + name
this.permission_info = r.config.permissions.info[permission_type]
this.permission_info = r.strings.permissions.info[permission_type]
this.sorted_perm_keys = $.map(this.permission_info,
function(v, k) { return k })
this.sorted_perm_keys.sort()
@@ -235,7 +235,7 @@ r.ui.PermissionEditor.init = function() {
})
}
activate('body')
for (var permission_type in r.config.permissions.info) {
for (var permission_type in r.strings.permissions.info) {
$('.' + permission_type + '-table')
.on('insert-row', 'tr', function(e) { activate(this) })
}
@@ -290,7 +290,7 @@ r.ui.PermissionEditor.prototype = $.extend(new r.ui.Base(), {
update()
})
$label.append(
document.createTextNode(r.config.permissions.all_msg))
document.createTextNode(r.strings.permissions.all_msg))
} else if (info) {
$input.change(update)
$label.append(document.createTextNode(info.title))
@@ -335,7 +335,7 @@ r.ui.PermissionEditor.prototype = $.extend(new r.ui.Base(), {
var info = this.permission_info[perm]
var text
if (perm == "all") {
text = r.config.permissions.all_msg
text = r.strings.permissions.all_msg
} else if (info) {
text = info.title
} else {
@@ -388,7 +388,7 @@ r.ui.PermissionEditor.prototype = $.extend(new r.ui.Base(), {
}
if (!spans.length) {
spans.push($('<span class="permission-bit">')
.text(r.config.permissions.none_msg)
.text(r.strings.permissions.none_msg)
.addClass("none"))
}
var $new_summary = $('<div class="permission-summary">')

View File

@@ -0,0 +1,82 @@
#!/usr/bin/env python
import unittest
from r2.tests import stage_for_paste
stage_for_paste()
from r2.lib.permissions import PermissionSet, ModeratorPermissionSet
class TestPermissionSet(PermissionSet):
info = dict(x={}, y={})
class PermissionSetTest(unittest.TestCase):
def test_dumps(self):
self.assertEquals(
'+all', PermissionSet(all=True).dumps())
self.assertEquals(
'+all', PermissionSet(all=True, other=True).dumps())
self.assertEquals(
'+a,-b', PermissionSet(a=True, b=False).dumps())
def test_loads(self):
self.assertEquals("", TestPermissionSet.loads(None).dumps())
self.assertEquals("", TestPermissionSet.loads("").dumps())
self.assertEquals("+x,+y", TestPermissionSet.loads("+x,+y").dumps())
self.assertEquals("+x,-y", TestPermissionSet.loads("+x,-y").dumps())
self.assertEquals("+all", TestPermissionSet.loads("+x,-y,+all").dumps())
self.assertEquals("+x,-y,+z",
TestPermissionSet.loads("+x,-y,+z").dumps())
self.assertRaises(ValueError,
TestPermissionSet.loads, "+x,-y,+z", validate=True)
self.assertEquals(
"+x,-y",
TestPermissionSet.loads("-all,+x,-y", validate=True).dumps())
def test_is_superuser(self):
perm_set = PermissionSet()
self.assertFalse(perm_set.is_superuser())
perm_set[perm_set.ALL] = True
self.assertTrue(perm_set.is_superuser())
perm_set[perm_set.ALL] = False
self.assertFalse(perm_set.is_superuser())
def test_is_valid(self):
perm_set = PermissionSet()
self.assertFalse(perm_set.is_valid())
perm_set = TestPermissionSet()
self.assertTrue(perm_set.is_valid())
perm_set['x'] = True
self.assertTrue(perm_set.is_valid())
perm_set[perm_set.ALL] = True
self.assertTrue(perm_set.is_valid())
perm_set['z'] = True
self.assertFalse(perm_set.is_valid())
def test_getitem(self):
perm_set = PermissionSet()
perm_set[perm_set.ALL] = True
self.assertFalse(perm_set['x'])
perm_set = TestPermissionSet()
perm_set['x'] = True
self.assertTrue(perm_set['x'])
self.assertFalse(perm_set['y'])
perm_set['x'] = False
self.assertFalse(perm_set['x'])
perm_set[perm_set.ALL] = True
self.assertTrue(perm_set['x'])
self.assertTrue(perm_set['y'])
self.assertFalse(perm_set['z'])
self.assertTrue(perm_set.get('x', False))
self.assertFalse(perm_set.get('z', False))
self.assertTrue(perm_set.get('z', True))
class ModeratorPermissionSetTest(unittest.TestCase):
def test_loads(self):
self.assertTrue(ModeratorPermissionSet.loads(None).is_superuser())
self.assertFalse(ModeratorPermissionSet.loads('').is_superuser())

View File

@@ -2,86 +2,14 @@
import unittest
from r2.lib.permissions import PermissionSet
from r2.models.account import Account
from r2.models.subreddit import (
ModeratorPermissionSet,
PermissionSet,
SRMember,
Subreddit,
)
from r2.models.subreddit import SRMember, Subreddit
class TestPermissionSet(PermissionSet):
info = dict(x={}, y={})
class PermissionSetTest(unittest.TestCase):
def test_dumps(self):
self.assertEquals(
'+all', PermissionSet(all=True).dumps())
self.assertEquals(
'+all', PermissionSet(all=True, other=True).dumps())
self.assertEquals(
'+a,-b', PermissionSet(a=True, b=False).dumps())
def test_loads(self):
self.assertEquals("", TestPermissionSet.loads(None).dumps())
self.assertEquals("", TestPermissionSet.loads("").dumps())
self.assertEquals("+x,+y", TestPermissionSet.loads("+x,+y").dumps())
self.assertEquals("+x,-y", TestPermissionSet.loads("+x,-y").dumps())
self.assertEquals("+all", TestPermissionSet.loads("+x,-y,+all").dumps())
self.assertEquals("+x,-y,+z",
TestPermissionSet.loads("+x,-y,+z").dumps())
self.assertRaises(ValueError,
TestPermissionSet.loads, "+x,-y,+z", validate=True)
self.assertEquals(
"+x,-y",
TestPermissionSet.loads("-all,+x,-y", validate=True).dumps())
def test_is_superuser(self):
perm_set = PermissionSet()
self.assertFalse(perm_set.is_superuser())
perm_set[perm_set.ALL] = True
self.assertTrue(perm_set.is_superuser())
perm_set[perm_set.ALL] = False
self.assertFalse(perm_set.is_superuser())
def test_is_valid(self):
perm_set = PermissionSet()
self.assertFalse(perm_set.is_valid())
perm_set = TestPermissionSet()
self.assertTrue(perm_set.is_valid())
perm_set['x'] = True
self.assertTrue(perm_set.is_valid())
perm_set[perm_set.ALL] = True
self.assertTrue(perm_set.is_valid())
perm_set['z'] = True
self.assertFalse(perm_set.is_valid())
def test_getitem(self):
perm_set = PermissionSet()
perm_set[perm_set.ALL] = True
self.assertFalse(perm_set['x'])
perm_set = TestPermissionSet()
perm_set['x'] = True
self.assertTrue(perm_set['x'])
self.assertFalse(perm_set['y'])
perm_set['x'] = False
self.assertFalse(perm_set['x'])
perm_set[perm_set.ALL] = True
self.assertTrue(perm_set['x'])
self.assertTrue(perm_set['y'])
self.assertFalse(perm_set['z'])
self.assertTrue(perm_set.get('x', False))
self.assertFalse(perm_set.get('z', False))
self.assertTrue(perm_set.get('z', True))
class ModeratorPermissionSetTest(unittest.TestCase):
def test_loads(self):
self.assertTrue(ModeratorPermissionSet.loads(None).is_superuser())
self.assertFalse(ModeratorPermissionSet.loads('').is_superuser())
class SRMemberTest(unittest.TestCase):
def setUp(self):