bgneal@459: """
bgneal@459: This module does permissions checking for the forums application.
bgneal@459: 
bgneal@459: """
bgneal@459: from django.core.cache import cache
bgneal@459: 
bgneal@459: # How long (in secs) to cache group information for various entities:
bgneal@459: CATEGORY_TIMEOUT = 4 * 60 * 60
bgneal@459: FORUM_TIMEOUT = 4 * 60 * 60
bgneal@459: USER_TIMEOUT = 15 * 60
bgneal@459: 
bgneal@459: 
bgneal@459: def can_access(category, user):
bgneal@459:     """
bgneal@459:     This function returns True if the given user can access the forum category
bgneal@459:     and False otherwise.
bgneal@459: 
bgneal@459:     """
bgneal@459:     if user.is_superuser:
bgneal@459:         return True
bgneal@459: 
bgneal@459:     # If this category has no groups assigned to it, return True. Else, return
bgneal@459:     # True if the user belongs to a group that has been assigned to this
bgneal@459:     # category, and False otherwise.
bgneal@459: 
bgneal@459:     # Get the groups assigned to this category.
bgneal@459:     cat_groups = get_category_groups(category)
bgneal@459: 
bgneal@459:     if len(cat_groups) == 0:
bgneal@459:         return True         # No groups => public category
bgneal@459: 
bgneal@459:     user_groups = get_user_groups(user)
bgneal@459:     return bool(user_groups & cat_groups)
bgneal@459: 
bgneal@459: 
bgneal@459: def can_moderate(forum, user):
bgneal@459:     """
bgneal@459:     Returns True if the user can moderate the forum.
bgneal@459: 
bgneal@459:     """
bgneal@459:     # Get the simple cases out of the way first:
bgneal@459:     if not user.is_authenticated():
bgneal@459:         return False
bgneal@459:     elif user.is_superuser:
bgneal@459:         return True
bgneal@459: 
bgneal@459:     # If we get here, we have to see if there is an intersection between the
bgneal@459:     # user's groups and the forum's moderator groups.
bgneal@459: 
bgneal@459:     forum_groups = get_forum_groups(forum)
bgneal@459:     user_groups = get_user_groups(user)
bgneal@459: 
bgneal@459:     return bool(user_groups & forum_groups)
bgneal@459: 
bgneal@459: 
bgneal@459: def can_post(topic, user):
bgneal@459:     """
bgneal@459:     Returns True if the user can post in the topic and False otherwise.
bgneal@459: 
bgneal@459:     """
bgneal@459:     if not user.is_authenticated():
bgneal@459:         return False
bgneal@459:     if user.is_superuser or can_moderate(topic.forum, user):
bgneal@459:         return True
bgneal@459: 
bgneal@459:     return not topic.locked and can_access(topic.forum.category, user)
bgneal@459: 
bgneal@459: 
bgneal@459: def get_user_groups(user):
bgneal@459:     """
bgneal@459:     Returns a set of group ID's that the user belongs to.
bgneal@459: 
bgneal@459:     """
bgneal@459:     user_groups_key = '%s_groups' % user.username
bgneal@459:     return _get_groups(user_groups_key, user.groups.all(), USER_TIMEOUT)
bgneal@459: 
bgneal@459: 
bgneal@459: def get_forum_groups(forum):
bgneal@459:     """
bgneal@459:     Returns a set of group ID's of the forum's moderator groups.
bgneal@459: 
bgneal@459:     """
bgneal@459:     forum_groups_key = 'forum_%d_mods' % forum.id
bgneal@459:     return _get_groups(forum_groups_key, forum.moderators.all(), FORUM_TIMEOUT)
bgneal@459: 
bgneal@459: 
bgneal@459: def get_category_groups(category):
bgneal@459:     """
bgneal@459:     Returns a set of group ID's of the groups that can access this forum
bgneal@459:     category.
bgneal@459: 
bgneal@459:     """
bgneal@459:     cat_groups_key = 'cat_%d_groups' % category.id
bgneal@459:     return _get_groups(cat_groups_key, category.groups.all(), CATEGORY_TIMEOUT)
bgneal@459: 
bgneal@459: 
bgneal@459: def _get_groups(key, qs, timeout):
bgneal@459:     """
bgneal@459:     This internal function contains the code common to the get_xxx_groups()
bgneal@459:     functions. Returns a set of group ID's from the cache. If the set is not
bgneal@459:     found in the cache, the set is generated from the queryset qs and cached
bgneal@459:     with the given timeout.
bgneal@459: 
bgneal@459:     key - the cache key for the set of group ID's
bgneal@459:     qs - the query set of groups to query if the set is not in the cache
bgneal@459:     timeout - the cache timeout to use
bgneal@459: 
bgneal@459:     """
bgneal@459:     groups = cache.get(key)
bgneal@459:     if groups is None:
bgneal@459:         groups = set([g.id for g in qs])
bgneal@459:         cache.set(key, groups, timeout)
bgneal@459: 
bgneal@459:     return groups