src/cm/security.py
changeset 522 c9c2148f09c9
parent 470 077be006891e
child 523 cc1cd48289e0
equal deleted inserted replaced
521:afb684b6cb16 522:c9c2148f09c9
     7 from django.http import HttpResponseRedirect
     7 from django.http import HttpResponseRedirect
     8 from django.utils.http import urlquote
     8 from django.utils.http import urlquote
     9 from django.db.models import Q
     9 from django.db.models import Q
    10 from piston.utils import rc
    10 from piston.utils import rc
    11 import logging
    11 import logging
       
    12 from django.core.cache import cache
       
    13 from hashlib import sha1
    12 
    14 
    13 from cm.models import *
    15 from cm.models import *
    14 from cm import cm_settings
    16 from cm import cm_settings
    15 from cm.exception import UnauthorizedException
    17 from cm.exception import UnauthorizedException
    16 from cm.cm_settings import DECORATED_CREATORS
    18 from cm.cm_settings import DECORATED_CREATORS
    37     
    39     
    38     # make sure perm exist
    40     # make sure perm exist
    39     assert Permission.objects.get(codename=perm_name)
    41     assert Permission.objects.get(codename=perm_name)
    40     
    42     
    41     user = get_request_user(request)
    43     user = get_request_user(request)
       
    44     myself = request.GET.get('name', None)
       
    45     key = sha1(str((settings.SITE_URL, 'has_perm', (user, myself, text, perm_name)))).hexdigest()
       
    46     val = cache.get(key)
       
    47     if val != None:
       
    48       return val
    42 
    49 
    43     if user and user.is_staff:
    50     if user and user.is_staff:
       
    51         cache.set(key, True)
    44         return True
    52         return True
    45     
    53     
    46     if not text:
    54     if not text:
    47         return UserRole.objects.filter(user=user, text=None).filter(Q(role__permissions__codename__exact=perm_name)).count() != 0
    55         ret = UserRole.objects.filter(user=user, text=None).filter(Q(role__permissions__codename__exact=perm_name)).count() != 0
       
    56         cache.set(key, ret)
       
    57         return ret
    48     else:
    58     else:
    49         # local role only ADDS permissions:
    59         # local role only ADDS permissions:
    50         # either a global or a local role with appropriate permissions
    60         # either a global or a local role with appropriate permissions
    51         #return UserRole.objects.filter(user=user).filter(Q(text=text) | Q(text=None)).filter(Q(role__permissions__codename__exact=perm_name)).count() != 0
    61         #return UserRole.objects.filter(user=user).filter(Q(text=text) | Q(text=None)).filter(Q(role__permissions__codename__exact=perm_name)).count() != 0
    52 
    62 
    53         # local role OVERRIDES global role:
    63         # local role OVERRIDES global role:
    54         if UserRole.objects.filter(Q(user=user),Q(text=text),~Q(role=None)): # if non void local role
    64         if UserRole.objects.filter(Q(user=user),Q(text=text),~Q(role=None)): # if non void local role
    55             return UserRole.objects.filter(user=user).filter(text=text).filter(Q(role__permissions__codename__exact=perm_name)).count() != 0
    65             ret = UserRole.objects.filter(user=user).filter(text=text).filter(Q(role__permissions__codename__exact=perm_name)).count() != 0
       
    66             cache.set(key, ret)
       
    67             return ret
    56         else:
    68         else:
    57             # local role for anon users
    69             # local role for anon users
    58             # OR global role for anon users
    70             # OR global role for anon users
    59             # OR global role for this user
    71             # OR global role for this user
    60             return UserRole.objects.filter(Q(user=user) | Q(user=None)).filter(Q(text=None) | Q(text=text)).filter(Q(role__permissions__codename__exact=perm_name)).count() != 0            
    72             ret = UserRole.objects.filter(Q(user=user) | Q(user=None)).filter(Q(text=None) | Q(text=text)).filter(Q(role__permissions__codename__exact=perm_name)).count() != 0            
       
    73             cache.set(key, ret)
       
    74             return ret
    61             #return UserRole.objects.filter(user=user).filter(text=None).filter(Q(role__permissions__codename__exact=perm_name)).count() != 0
    75             #return UserRole.objects.filter(user=user).filter(text=None).filter(Q(role__permissions__codename__exact=perm_name)).count() != 0
    62         
    76         
    63 def has_own_perm(request, perm_name, text, comment):
    77 def has_own_perm(request, perm_name, text, comment):
    64     
    78     
    65     user = get_request_user(request)
    79     user = get_request_user(request)
    71     if cm_settings.NO_SECURITY:
    85     if cm_settings.NO_SECURITY:
    72         return True
    86         return True
    73     
    87     
    74     # make sure perm exist
    88     # make sure perm exist
    75     assert Permission.objects.get(codename=perm_name)
    89     assert Permission.objects.get(codename=perm_name)
       
    90 
       
    91     myself = request.GET.get('name', None)
       
    92     key = sha1(str((settings.SITE_URL, 'has_own_perm', (user, myself, text, comment, perm_name)))).hexdigest()
       
    93     val = cache.get(key)
       
    94     if val != None:
       
    95       return val
    76     
    96     
    77     # 2 special cases for comment own edition:
    97     # 2 special cases for comment own edition:
    78     
    98     
    79     # 1
    99     # 1
    80     # if perm = can_edit_own_comment and 
   100     # if perm = can_edit_own_comment and 
    83     # don't have moderation rights and
   103     # don't have moderation rights and
    84     if comment and comment.state == 'approved' and \
   104     if comment and comment.state == 'approved' and \
    85        perm_name == 'can_edit_comment_own' and \
   105        perm_name == 'can_edit_comment_own' and \
    86        text.last_text_version.mod_posteriori == False and \
   106        text.last_text_version.mod_posteriori == False and \
    87        not has_perm(request, 'can_manage_text', text=text):
   107        not has_perm(request, 'can_manage_text', text=text):
       
   108         cache.set(key, False)
    88         return False
   109         return False
    89     
   110     
    90     # 2       
   111     # 2       
    91     # if perm = can_edit_own_comment and and 
   112     # if perm = can_edit_own_comment and and 
    92     # text is a posteriori moderated and
   113     # text is a posteriori moderated and
    95     if comment and comment.state == 'approved' and \
   116     if comment and comment.state == 'approved' and \
    96        perm_name == 'can_edit_comment_own' and \
   117        perm_name == 'can_edit_comment_own' and \
    97        text.last_text_version.mod_posteriori == True and \
   118        text.last_text_version.mod_posteriori == True and \
    98        comment.comment_set.count() != 0 and \
   119        comment.comment_set.count() != 0 and \
    99        not has_perm(request, 'can_manage_text', text=text):
   120        not has_perm(request, 'can_manage_text', text=text):
       
   121         cache.set(key, False)
   100         return False
   122         return False
   101     
   123     
   102     actual_own_user = False
   124     actual_own_user = False
   103     if comment.user == request.user:
   125     if comment.user == request.user:
   104       if DECORATED_CREATORS:
   126       if DECORATED_CREATORS:
   105         if request.GET.get('name', None) == comment.get_name():
   127         if request.GET.get('name', None) == comment.get_name():
   106           actual_own_user = True
   128           actual_own_user = True
   107       else:
   129       else:
   108         actual_own_user = True
   130         actual_own_user = True
   109     return (actual_own_user and has_perm(request, perm_name, text=text)) 
   131     ret = (actual_own_user and has_perm(request, perm_name, text=text)) 
       
   132     cache.set(key, ret)
       
   133     return ret
   110         
   134         
   111 def is_authenticated(request):
   135 def is_authenticated(request):
   112     # We customize this to be able to monkey patch it if needed
   136     # We customize this to be able to monkey patch it if needed
   113     return request.user.is_authenticated()
   137     return request.user.is_authenticated()
   114     
   138     
   118 def get_texts_with_perm(request, perm_name):
   142 def get_texts_with_perm(request, perm_name):
   119     assert Permission.objects.get(codename=perm_name)
   143     assert Permission.objects.get(codename=perm_name)
   120 
   144 
   121     user = get_request_user(request)
   145     user = get_request_user(request)
   122     
   146     
       
   147     key = sha1(str((settings.SITE_URL, 'get_texts_with_perm', (user, perm_name)))).hexdigest()
       
   148     val = cache.get(key)
       
   149     if val != None:
       
   150       return val
       
   151 
   123     if user and user.is_staff:
   152     if user and user.is_staff:
   124         return Text.objects.all()
   153         ret = Text.objects.all()
       
   154         cache.set(key, ret)
       
   155         return ret
   125     
   156     
   126     # local role only ADDS permissions:
   157     # local role only ADDS permissions:
   127     ## global perm
   158     ## global perm
   128     # if UserRole.objects.filter(text=None).filter(role__permissions__codename__exact=perm_name).filter(Q(user=user) | Q(user=None) ).count() != 0:
   159     # if UserRole.objects.filter(text=None).filter(role__permissions__codename__exact=perm_name).filter(Q(user=user) | Q(user=None) ).count() != 0:
   129     #    return Text.objects.all().distinct()
   160     #    return Text.objects.all().distinct()
   143         texts_without_local_role_with_perm = Text.objects.filter(id__in=texts_without_local_role)
   174         texts_without_local_role_with_perm = Text.objects.filter(id__in=texts_without_local_role)
   144     else:
   175     else:
   145         texts_without_local_role_with_perm = []
   176         texts_without_local_role_with_perm = []
   146     
   177     
   147     ids = set([t.id for t in texts_with_local_role_with_perm]).union(set([t.id for t in texts_without_local_role_with_perm]))
   178     ids = set([t.id for t in texts_with_local_role_with_perm]).union(set([t.id for t in texts_without_local_role_with_perm]))
   148     return Text.objects.filter(id__in=ids)
   179     ret = Text.objects.filter(id__in=ids)
       
   180     cache.set(key, ret)
       
   181     return ret
   149     
   182     
   150 def get_viewable_comments(request, comments, text, order_by=('created',)):
   183 def get_viewable_comments(request, comments, text, order_by=('created',)):
   151     """
   184     """
   152     Get comments visibles by user
   185     Get comments visibles by user
   153     comments: queryset
   186     comments: queryset
   154     """
   187     """
   155     user = get_request_user(request)
   188     user = get_request_user(request)
       
   189     myself = request.GET.get('name', None)
       
   190     key = sha1(str((settings.SITE_URL, 'get_viewable_comments', (user, myself, text, comments)))).hexdigest()
       
   191     val = cache.get(key)
       
   192     if val != None:
       
   193       return val
   156         
   194         
   157     if user and has_perm(request, 'can_view_unapproved_comment', text=text):
   195     if user and has_perm(request, 'can_view_unapproved_comment', text=text):
   158         return list(comments.order_by(*order_by))
   196         ret = list(comments.order_by(*order_by))
       
   197         cache.set(key, ret)
       
   198         return ret
   159     else:
   199     else:
   160         # Fetch role_model to process specific behaviour for role_teacher model
   200         # Fetch role_model to process specific behaviour for role_teacher model
   161         from cm.models import ApplicationConfiguration
   201         from cm.models import ApplicationConfiguration
   162         role_model = ApplicationConfiguration.get_key('workspace_role_model')
   202         role_model = ApplicationConfiguration.get_key('workspace_role_model')
   163 
   203 
   179                     role = c.user.get_profile().global_userrole().role
   219                     role = c.user.get_profile().global_userrole().role
   180                   else:
   220                   else:
   181                     role = userrole.role
   221                     role = userrole.role
   182                   if role.name == 'Individual student':
   222                   if role.name == 'Individual student':
   183                     comments_thread_viewable.remove(c)
   223                     comments_thread_viewable.remove(c)
       
   224             cache.set(key, comments_thread_viewable)
   184             return comments_thread_viewable 
   225             return comments_thread_viewable 
   185         elif user and has_perm(request, 'can_view_comment_own', text=text):
   226         elif user and has_perm(request, 'can_view_comment_own', text=text):
   186             if DECORATED_CREATORS:
   227             if DECORATED_CREATORS:
   187               visible_comments = comments.filter(name=request.GET.get('name', None)).order_by(*order_by)
   228               visible_comments = comments.filter(name=myself).order_by(*order_by)
   188             else:
   229             else:
   189               visible_comments = comments.filter(user=user).order_by(*order_by)
   230               visible_comments = comments.filter(user=user).order_by(*order_by)
   190 
   231 
   191             # for role_teacher role model, add 'teacher' comments
   232             # for role_teacher role model, add 'teacher' comments
   192             if (role_model == 'teacher'):
   233             if (role_model == 'teacher'):
   196 
   237 
   197               # add admin and current user
   238               # add admin and current user
   198               admin =  User.objects.get(id=1)
   239               admin =  User.objects.get(id=1)
   199               with_teachers.append(admin.id)
   240               with_teachers.append(admin.id)
   200               if DECORATED_CREATORS:
   241               if DECORATED_CREATORS:
   201                 myself = request.GET.get('name', None)
       
   202                 visible_comments = comments.filter(Q(user__id__in=with_teachers) | Q(name=myself)).order_by(*order_by)
   242                 visible_comments = comments.filter(Q(user__id__in=with_teachers) | Q(name=myself)).order_by(*order_by)
   203               else:
   243               else:
   204                 with_teachers.append(user.id)
   244                 with_teachers.append(user.id)
   205                 visible_comments = comments.filter(user__id__in=with_teachers).order_by(*order_by)
   245                 visible_comments = comments.filter(user__id__in=with_teachers).order_by(*order_by)
   206 
   246 
   207             # filter comments with a non visible (i.e. moderated) comment in the above thread 
   247             # filter comments with a non visible (i.e. moderated) comment in the above thread 
   208             comments_thread_viewable = [c for c in visible_comments if c.is_thread_full_visible(own_user=user)]
   248             comments_thread_viewable = [c for c in visible_comments if c.is_thread_full_visible(own_user=user)]
       
   249             cache.set(key, comments_thread_viewable)
   209             return comments_thread_viewable                
   250             return comments_thread_viewable                
   210         else:
   251         else:
       
   252             cache.set(key, [])
   211             return []
   253             return []
   212     
   254     
   213 def get_viewable_activities(request=None, act_types={}, text=None):
   255 def get_viewable_activities(request=None, act_types={}, text=None):
   214     """
   256     """
   215     Get activities user in request is allowed to see
   257     Get activities user in request is allowed to see