optimisation to open and save projects
authorcavaliet
Fri, 12 Apr 2013 12:46:02 +0200
changeset 1146 4491284e73bb
parent 1145 160b769463b6
child 1147 cd4672501c82
optimisation to open and save projects
src/ldt/ldt/ldt_utils/views/lignesdetemps.py
src/ldt/ldt/security/__init__.py
src/ldt/ldt/security/permissionchecker.py
src/ldt/ldt/security/utils.py
--- a/src/ldt/ldt/ldt_utils/views/lignesdetemps.py	Thu Apr 11 10:15:51 2013 +0200
+++ b/src/ldt/ldt/ldt_utils/views/lignesdetemps.py	Fri Apr 12 12:46:02 2013 +0200
@@ -7,6 +7,7 @@
 from ldt.ldt_utils.models import Content, Project, Media
 from ldt.ldt_utils.utils import LdtUtils, clean_description
 from ldt.indexation import SimpleSearch
+from ldt.security.permissionchecker import check_object_perm_for_user
 from ldt.security.utils import set_forbidden_stream
 from ldt.ldt_utils.stat import update_stat_project
 from ldt.ldt_utils.searchutils import search_generate_ldt
@@ -14,6 +15,9 @@
 from ldt.utils.web_url_management import get_web_url
 import base64
 import lxml.etree
+
+import logging
+logger = logging.getLogger(__name__)
   
 def search_index_get(request, field, query):
     
@@ -180,28 +184,29 @@
    
 @login_required    
 def index_project(request, id, full=False): 
-
+    
     urlStr = absurl(request, "ldt.ldt_utils.views.lignesdetemps.init", args=['ldt_project', id])
     posturl = absurl(request, "ldt.ldt_utils.views.lignesdetemps.save_ldt_project")
     language_code = request.LANGUAGE_CODE[:2]
     colorurl=absstatic(request, "ldt/swf/ldt/pkg/color.xml")
     i18nurl=absstatic(request, "ldt/swf/ldt/pkg/i18n")
     baseurl=absstatic(request, "ldt/swf/ldt/")
+    
     try:
         ldt = Project.safe_objects.get(ldt_id=id)
     except Project.DoesNotExist:
         return HttpResponseRedirect(reverse("ldt.ldt_utils.views.workspace.home"))
     
-    if ldt.state == 2 or not request.user.has_perm('change_project', ldt): #published
+    if ldt.state == 2 or not check_object_perm_for_user(ldt, 'change_project', request.user):
         readonly = 'true'
     else:
         readonly = 'false'
-       
+    
     if full:
         template_path = 'ldt/ldt_utils/init_ldt_full.html'
     else:
         template_path = 'ldt/ldt_utils/init_ldt.html'
-  
+    
     return render_to_response(template_path, {'colorurl': colorurl, 'i18nurl': i18nurl, 'language': language_code, 'baseurl': baseurl, 'url': urlStr, 'posturl': posturl, 'id': id, 'readonly': readonly}, context_instance=RequestContext(request))
     
     
@@ -211,7 +216,7 @@
     doc = ldtgen.generate_init([url], 'ldt.ldt_utils.views.lignesdetemps.' + method, None)    
 
     library = doc.xpath('/iri/files/library')[0]
-    for c in Content.safe_objects.all():
+    for c in Content.safe_objects.all().select_related("media_obj"):
         elem = lxml.etree.SubElement(library, 'file')
         elem.set('src', c.iri_url())
         if c.videopath :
@@ -290,26 +295,26 @@
             if c not in contents_id:
                 content = Content.objects.get(iri_id=c)
                 ldtproject.contents.add(content)
-         
+        
         update_stat_project(ldtproject)
         
         #remove html tags added by flash
         description = ldtproject.get_description(doc)
         new_desc = clean_description(description)
-            
-        if new_desc:        
+        
+        if new_desc:
             desc_node = doc.xpath('/iri/project')[0]
             desc_node.set('abstract', new_desc)
             ldtproject.ldt = lxml.etree.tostring(doc, pretty_print=True)
-            
+        
         ldtproject.description = new_desc if new_desc else description
-    
+        
         #set a new icon for this project
         if check_icon_project:
             ldtproject.set_icon()
-    
+        
         ldtproject.save()
-            
+        
     else:
         ldt = ''
         new_contents = []
--- a/src/ldt/ldt/security/__init__.py	Thu Apr 11 10:15:51 2013 +0200
+++ b/src/ldt/ldt/security/__init__.py	Fri Apr 12 12:46:02 2013 +0200
@@ -2,6 +2,7 @@
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.auth.models import User
 from django.core.signals import request_started 
+from ldt.security.permissionchecker import check_object_perm_for_user
 
 try:
     from threading import local
@@ -94,9 +95,10 @@
             if not user:
                 user = get_anonymous_user()
             
-            if self.pk and not user.has_perm('change_%s' % cls_name, self):
+            # use our check_object_perm_for_user instead of not optimized guardian has_perm
+            if self.pk and not check_object_perm_for_user(self, 'change_%s' % cls_name, user):
                 raise AttributeError('User %s is not allowed to change object %s' % (user, self))
-      
+            
             return func(self, *args, **kwargs)
         return wrapped    
     return wrapper
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ldt/ldt/security/permissionchecker.py	Fri Apr 12 12:46:02 2013 +0200
@@ -0,0 +1,47 @@
+from django.contrib.contenttypes.models import ContentType
+from django.contrib.auth.models import Permission
+from guardian.models import UserObjectPermission, GroupObjectPermission
+
+import logging
+logger = logging.getLogger(__name__)
+
+def check_object_perm_for_user(obj, perm_name, user):
+    # Guardian has_perm request is REALLY long and not optimized.
+    # So we check manually the change_project permission for the user and the user's groups
+    # Get necessary datas
+    model_name = obj.__class__.__name__.lower()
+    content_type = ContentType.objects.get(model=model_name)
+    perm = Permission.objects.get(codename=perm_name)
+    can_change = False
+    # Check for the user
+    try:
+        logger.debug("COUCOU 5-2")
+        uop = UserObjectPermission.objects.get(user=user, content_type=content_type, permission=perm, object_pk=obj.pk)
+        logger.debug("COUCOU 5-3")
+        if uop:
+            logger.debug("COUCOU 5-4")
+            can_change = True
+        logger.debug("COUCOU 5-5")
+    except:
+        logger.debug("COUCOU 5-6")
+        can_change = False
+    logger.debug("COUCOU 5-7 can_change =")
+    logger.debug(can_change)
+    # Check for user's groups if necessary
+    if not can_change:
+        try:
+            logger.debug("COUCOU G-2")
+            gop = GroupObjectPermission.objects.filter(group__user=user, content_type=content_type, permission=perm, object_pk=obj.pk)
+            logger.debug("COUCOU G-3")
+            if gop and len(gop)>0:
+                logger.debug("COUCOU G-4")
+                can_change = True
+            logger.debug("COUCOU G-5")
+        except:
+            logger.debug("COUCOU G-6")
+            can_change = False
+        logger.debug("COUCOU G-7 can_change =")
+        logger.debug(can_change)
+    # End
+    return can_change
+    
\ No newline at end of file
--- a/src/ldt/ldt/security/utils.py	Thu Apr 11 10:15:51 2013 +0200
+++ b/src/ldt/ldt/security/utils.py	Fri Apr 12 12:46:02 2013 +0200
@@ -58,12 +58,15 @@
     model_name = obj_list[0].__class__.__name__.lower()
     ctype = ContentType.objects.get(model=model_name)
     cls = ctype.model_class()
-
+    
+    # We don't use obj.values_list('pk', flat=True) because the full queryset will be calculated and used after anyway.
+    pk_list = [item.pk for item in obj_list]
     if model_name in [cls_name.lower() for cls_name in settings.USE_GROUP_PERMISSIONS] or model_name == 'group':
         to_check = True
-        change_list = get_objects_for_user(user, '%s.change_%s' % (cls._meta.app_label, model_name))
+        # Filter SUPER usefull : avoid to load ALL objects. We only check permissions on obj_list's objects
+        change_list = get_objects_for_user(user, '%s.change_%s' % (cls._meta.app_label, model_name)).filter(pk__in=pk_list)
     else:
-        to_check = False        
+        to_check = False
         
     for obj in obj_list:
         if not to_check or obj in change_list: