permissions.py 4.18 KB
Newer Older
Mike Chen committed
1
import logging
2
from util.cache import cache
3 4
from django.core import cache
cache = cache.get_cache('default')
5

Calen Pennington committed
6

7
def cached_has_permission(user, permission, course_id=None):
Mike Chen committed
8 9
    """
    Call has_permission if it's not cached. A change in a user's role or
10
    a role's permissions will only become effective after CACHE_LIFESPAN seconds.
Mike Chen committed
11 12
    """
    CACHE_LIFESPAN = 60
13 14 15 16
    key = "permission_%d_%s_%s" % (user.id, str(course_id), permission)
    val = cache.get(key, None)
    if val not in [True, False]:
        val = has_permission(user, permission, course_id=course_id)
Mike Chen committed
17
        cache.set(key, val, CACHE_LIFESPAN)
18 19
    return val

Calen Pennington committed
20

21
def has_permission(user, permission, course_id=None):
22 23 24
    for role in user.roles.filter(course_id=course_id):
        if role.has_permission(permission):
            return True
Mike Chen committed
25 26 27
    return False


28
CONDITIONS = ['is_open', 'is_author']
Calen Pennington committed
29 30


31 32
def check_condition(user, condition, course_id, data):
    def check_open(user, condition, course_id, data):
Rocky Duan committed
33 34 35 36
        try:
            return data and not data['content']['closed']
        except KeyError:
            return False
Mike Chen committed
37

38
    def check_author(user, condition, course_id, data):
Rocky Duan committed
39 40 41 42
        try:
            return data and data['content']['user_id'] == str(user.id)
        except KeyError:
            return False
Mike Chen committed
43

44
    handlers = {
Calen Pennington committed
45 46
        'is_open': check_open,
        'is_author': check_author,
47
    }
Mike Chen committed
48

49
    return handlers[condition](user, condition, course_id, data)
50

51 52

def check_conditions_permissions(user, permissions, course_id, **kwargs):
53 54
    """
    Accepts a list of permissions and proceed if any of the permission is valid.
55
    Note that ["can_view", "can_edit"] will proceed if the user has either
56 57
    "can_view" or "can_edit" permission. To use AND operator in between, wrap them in
    a list.
58
    """
59 60 61 62 63

    def test(user, per, operator="or"):
        if isinstance(per, basestring):
            if per in CONDITIONS:
                return check_condition(user, per, course_id, kwargs)
64
            return cached_has_permission(user, per, course_id=course_id)
65 66
        elif isinstance(per, list) and operator in ["and", "or"]:
            results = [test(user, x, operator="and") for x in per]
67 68 69 70
            if operator == "or":
                return True in results
            elif operator == "and":
                return not False in results
Kevin Chugh committed
71
    return test(user, permissions, operator="or")
72 73 74


VIEW_PERMISSIONS = {
75 76
    'update_thread'     :       ['edit_content', ['update_thread', 'is_open', 'is_author']],
    'create_comment'    :       [["create_comment", "is_open"]],
77
    'delete_thread'     :       ['delete_thread', ['update_thread', 'is_author']],
78
    'update_comment'    :       ['edit_content', ['update_comment', 'is_open', 'is_author']],
79 80 81
    'endorse_comment'   :       ['endorse_comment'],
    'openclose_thread'  :       ['openclose_thread'],
    'create_sub_comment':       [['create_sub_comment', 'is_open']],
82
    'delete_comment'    :       ['delete_comment', ['update_comment', 'is_open', 'is_author']],
83 84 85
    'vote_for_comment'  :       [['vote', 'is_open']],
    'undo_vote_for_comment':    [['unvote', 'is_open']],
    'vote_for_thread'   :       [['vote', 'is_open']],
86 87 88 89
    'flag_abuse_for_thread':    [['vote', 'is_open']],
    'un_flag_abuse_for_thread':    [['vote', 'is_open']],
    'flag_abuse_for_comment':    [['vote', 'is_open']],
    'un_flag_abuse_for_comment':    [['vote', 'is_open']],
90
    'undo_vote_for_thread':     [['unvote', 'is_open']],
Your Name committed
91 92
    'pin_thread':    ['create_comment'],
    'un_pin_thread':    ['create_comment'],
93
    'follow_thread'     :       ['follow_thread'],
94
    'follow_commentable':       ['follow_commentable'],
95 96 97 98 99
    'follow_user'       :       ['follow_user'],
    'unfollow_thread'   :       ['unfollow_thread'],
    'unfollow_commentable':     ['unfollow_commentable'],
    'unfollow_user'     :       ['unfollow_user'],
    'create_thread'     :       ['create_thread'],
Calen Pennington committed
100
    'update_moderator_status': ['manage_moderator'],
101 102
}

103 104

def check_permissions_by_view(user, course_id, content, name):
105 106 107 108
    try:
        p = VIEW_PERMISSIONS[name]
    except KeyError:
        logging.warning("Permission for view named %s does not exist in permissions.py" % name)
109
    return check_conditions_permissions(user, p, course_id, content=content)