diff options
| -rw-r--r-- | archaeological_operations/models.py | 9 | ||||
| -rw-r--r-- | archaeological_operations/tests.py | 105 | ||||
| -rw-r--r-- | archaeological_operations/views.py | 14 | ||||
| -rw-r--r-- | ishtar_common/models.py | 16 | ||||
| -rw-r--r-- | ishtar_common/tests.py | 4 | ||||
| -rw-r--r-- | ishtar_common/utils.py | 2 | ||||
| -rw-r--r-- | ishtar_common/wizards.py | 18 | 
7 files changed, 152 insertions, 16 deletions
| diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py index c342fb2a4..9655ca387 100644 --- a/archaeological_operations/models.py +++ b/archaeological_operations/models.py @@ -698,11 +698,18 @@ class Operation(ClosedItem, BaseHistorizedItem, ImageModel, OwnPerms,      @classmethod      def get_query_owns(cls, ishtaruser): +        profile = ishtaruser.current_profile +        town_ids = [] +        if profile: +            town_ids = [town['pk'] +                        for town in profile.query_towns.values('pk').all()]          return (              Q(in_charge=ishtaruser.person) |              Q(scientist=ishtaruser.person) |              Q(collaborators__pk=ishtaruser.person.pk) | -            Q(history_creator=ishtaruser.user_ptr)) & Q(end_date__isnull=True) +            Q(history_creator=ishtaruser.user_ptr) | +            Q(towns__pk__in=town_ids) +               ) & Q(end_date__isnull=True)      def is_active(self):          return not bool(self.end_date) diff --git a/archaeological_operations/tests.py b/archaeological_operations/tests.py index 7cfa83435..299ed49f8 100644 --- a/archaeological_operations/tests.py +++ b/archaeological_operations/tests.py @@ -41,7 +41,8 @@ from ishtar_common.models import OrganizationType, Organization, ItemKey, \      ImporterType, IshtarUser, TargetKey, ImporterModel, IshtarSiteProfile, \      Town, ImporterColumn, Person, Author, SourceType, AuthorType, \      DocumentTemplate, PersonType, TargetKeyGroup, JsonDataField, \ -    JsonDataSection, ImportTarget, FormaterType, CustomForm, ExcludedField +    JsonDataSection, ImportTarget, FormaterType, CustomForm, ExcludedField, \ +    UserProfile, ProfileType, Area  from archaeological_files.models import File, FileType  from archaeological_context_records.models import Unit, ContextRecord @@ -1372,6 +1373,20 @@ class OperationSearchTest(TestCase, OperationInitTest):          self.alt_username, self.alt_password, self.alt_user = create_user()          self.alt_user.user_permissions.add(Permission.objects.get(              codename='view_own_operation')) +        self.alt_user.user_permissions.add(Permission.objects.get( +            codename='change_own_operation')) +        self.alt_username2, self.alt_password2, self.alt_user2 = create_user( +            username='luke', password='iamyourfather' +        ) +        profile = UserProfile.objects.create( +            profile_type=ProfileType.objects.get(txt_idx='collaborator'), +            person=self.alt_user2.ishtaruser.person +        ) +        town = Town.objects.create(name='Tatouine', numero_insee='66000') +        area = Area.objects.create(label='Galaxie', txt_idx='galaxie') +        area.towns.add(town) +        profile.areas.add(area) +          self.orgas = self.create_orgas(self.user)          self.operations = self.create_operation(self.user, self.orgas[0])          self.operations += self.create_operation(self.alt_user, self.orgas[0]) @@ -1407,7 +1422,6 @@ class OperationSearchTest(TestCase, OperationInitTest):          result = json.loads(response.content)          self.assertEqual(result['recordsTotal'], 1) -      def create_relations(self):          rel1 = models.RelationType.objects.create(              symmetrical=True, label='Include', txt_idx='include') @@ -1504,19 +1518,102 @@ class OperationSearchTest(TestCase, OperationInitTest):          self.assertEqual(response.status_code, 200)          self.assertEqual(json.loads(response.content)['recordsTotal'], 1) -    def testOwnSearch(self): + +class OperationPermissionTest(TestCase, OperationInitTest): +    fixtures = FILE_FIXTURES + +    def setUp(self): +        IshtarSiteProfile.objects.get_or_create( +            slug='default', active=True) +        self.username, self.password, self.user = create_superuser() +        self.alt_username, self.alt_password, self.alt_user = create_user() +        self.alt_user.user_permissions.add(Permission.objects.get( +            codename='view_own_operation')) +        self.alt_user.user_permissions.add(Permission.objects.get( +            codename='change_own_operation')) +        self.alt_username2, self.alt_password2, self.alt_user2 = create_user( +            username='luke', password='iamyourfather' +        ) +        profile = UserProfile.objects.create( +            profile_type=ProfileType.objects.get(txt_idx='collaborator'), +            person=self.alt_user2.ishtaruser.person, +            current=True +        ) +        town = Town.objects.create(name='Tatouine', numero_insee='66000') +        area = Area.objects.create(label='Galaxie', txt_idx='galaxie') +        area.towns.add(town) +        profile.areas.add(area) + +        self.orgas = self.create_orgas(self.user) +        self.operations = self.create_operation(self.user, self.orgas[0]) +        self.operations += self.create_operation(self.alt_user, self.orgas[0]) +        self.operations[1].towns.add(town) +        self.item = self.operations[0] + +    def test_own_search(self): +        # no result when no authentification          c = Client()          response = c.get(reverse('get-operation'), {'year': '2010'}) -        # no result when no authentification          self.assertTrue(not json.loads(response.content)) + +        # possession +        c = Client()          c.login(username=self.alt_username, password=self.alt_password)          response = c.get(reverse('get-operation'), {'year': '2010'})          # only one "own" operation available +        self.assertTrue(json.loads(response.content)) +        self.assertTrue(json.loads(response.content)['recordsTotal'] == 1) +        response = c.get(reverse('get-operation'), +                         {'operator': self.orgas[0].pk}) +        self.assertTrue(json.loads(response.content)['recordsTotal'] == 1) + +        # area filter +        c = Client() +        c.login(username=self.alt_username2, password=self.alt_password2) +        response = c.get(reverse('get-operation'), {'year': '2010'}) +        # only one "own" operation available +        self.assertTrue(json.loads(response.content))          self.assertTrue(json.loads(response.content)['recordsTotal'] == 1)          response = c.get(reverse('get-operation'),                           {'operator': self.orgas[0].pk})          self.assertTrue(json.loads(response.content)['recordsTotal'] == 1) +    def test_own_modify(self): +        operation_pk1 = self.operations[0].pk +        operation_pk2 = self.operations[1].pk + +        # no result when no authentification +        c = Client() +        response = c.get(reverse('operation_modify', args=[operation_pk2])) +        self.assertRedirects(response, "/") + +        modif_url = '/operation_modification/general-operation_modification' + +        # possession +        c = Client() +        c.login(username=self.alt_username, password=self.alt_password) +        response = c.get(reverse('operation_modify', args=[operation_pk2]), +                         follow=True) +        self.assertRedirects(response, modif_url) +        response = c.get(modif_url) +        self.assertEqual(response.status_code, 200) +        response = c.get(reverse('operation_modify', args=[operation_pk1]), +                         follow=True) +        self.assertRedirects(response, "/") + +        # area filter +        c = Client() +        c.login(username=self.alt_username2, password=self.alt_password2) +        response = c.get(reverse('operation_modify', args=[operation_pk2]), +                         follow=True) +        self.assertRedirects(response, modif_url) +        response = c.get(modif_url) +        self.assertEqual(response.status_code, 200) +        response = c.get(reverse('operation_modify', args=[operation_pk1]), +                         follow=True) +        self.assertRedirects(response, "/") + +  class DashboardTest(TestCase, OperationInitTest):      fixtures = FILE_FIXTURES diff --git a/archaeological_operations/views.py b/archaeological_operations/views.py index fcd6c3252..e7e624c05 100644 --- a/archaeological_operations/views.py +++ b/archaeological_operations/views.py @@ -22,7 +22,7 @@ import json  from django.conf import settings  from django.core.urlresolvers import reverse  from django.db.models import Q -from django.http import HttpResponse +from django.http import HttpResponse, HttpResponseRedirect  from django.shortcuts import render, redirect  from django.utils.translation import ugettext_lazy as _, pgettext_lazy @@ -58,6 +58,8 @@ from archaeological_operations.wizards import has_associated_file, \      AdministrativeActDeletionWizard, SiteWizard, SiteModificationWizard, \      SiteDeletionWizard +from ishtar_common.utils import put_session_message +  def autocomplete_patriarche(request):      if (not request.user.has_perm('ishtar_common.view_operation', @@ -303,7 +305,15 @@ operation_modification_wizard = OperationModificationWizard.as_view(  def operation_modify(request, pk): -    operation_modification_wizard(request) +    try: +        operation_modification_wizard(request) +    except IndexError:  # no step available +        put_session_message( +            request.session.session_key, +            _(u"You don't have sufficient permissions to do this action."), +            'warning' +        ) +        return HttpResponseRedirect("/")      OperationModificationWizard.session_set_value(          request, 'selec-operation_modification', 'pk', pk, reset=True)      return redirect(reverse('operation_modification', diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 67c4422f6..2ebe07961 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -2693,6 +2693,15 @@ class UserProfile(models.Model):              [unicode(area) for area in self.areas.all()]))      @property +    def query_towns(self): +        return Town.objects.filter( +            Q(areas__profiles=self) | Q(areas__parent__profiles=self) | +            Q(areas__parent__parent__profiles=self) | +            Q(areas__parent__parent__parent__profiles=self) | +            Q(areas__parent__parent__parent__parent__profiles=self) +        ) + +    @property      def area_labels(self):          return u", ".join([unicode(area) for area in self.areas.all()]) @@ -2743,6 +2752,10 @@ class IshtarUser(FullSearch):              return u""          return unicode(profile) +    @property +    def current_profile(self): +        return self.person.current_profile +      @classmethod      def set_superuser(cls, user):          q = cls.objects.filter(user_ptr=user) @@ -3141,7 +3154,8 @@ m2m_changed.connect(town_child_changed, sender=Town.children.through)  class Area(HierarchicalType): -    towns = models.ManyToManyField(Town, verbose_name=_(u"Towns"), blank=True) +    towns = models.ManyToManyField(Town, verbose_name=_(u"Towns"), blank=True, +                                   related_name='areas')      parent = models.ForeignKey(          'self', blank=True, null=True, verbose_name=_(u"Parent"),          help_text=_(u"Only four level of parent are managed.") diff --git a/ishtar_common/tests.py b/ishtar_common/tests.py index 4ee47d723..0d606476d 100644 --- a/ishtar_common/tests.py +++ b/ishtar_common/tests.py @@ -79,9 +79,7 @@ def create_superuser():      return username, password, user -def create_user(): -    username = 'username678' -    password = 'dcbqj756aaa456!@%' +def create_user(username='username678', password='dcbqj756aaa456!@%'):      q = User.objects.filter(username=username)      if q.count():          return username, password, q.all()[0] diff --git a/ishtar_common/utils.py b/ishtar_common/utils.py index b03e794d0..01b35dcef 100644 --- a/ishtar_common/utils.py +++ b/ishtar_common/utils.py @@ -381,7 +381,7 @@ def put_session_message(session_key, message, message_type):      messages = []      if 'messages' in session:          messages = session['messages'][:] -    messages.append((message, message_type)) +    messages.append((unicode(message), message_type))      session['messages'] = messages      session.save() diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py index 5f3da1130..9e77a0dda 100644 --- a/ishtar_common/wizards.py +++ b/ishtar_common/wizards.py @@ -43,7 +43,8 @@ from django.utils.safestring import mark_safe  from ishtar_common import models  from ishtar_common.forms import CustomForm, reverse_lazy -from ishtar_common.utils import get_all_field_names, MultiValueDict +from ishtar_common.utils import get_all_field_names, MultiValueDict, \ +    put_session_message  logger = logging.getLogger(__name__) @@ -69,6 +70,11 @@ def check_rights(rights=[], redirect_url='/'):                                                           request.session):                          kwargs['current_right'] = right                          return view_func(request, *args, **kwargs) +            put_session_message( +                request.session.session_key, +                _(u"You don't have sufficient permissions to do this action."), +                'warning' +            )              return HttpResponseRedirect(redirect_url)          return _wrapped_view      return decorator @@ -110,6 +116,8 @@ def _check_right(step, condition=True):  def filter_no_fields_form(form, other_check=None):      def func(self): +        if not hasattr(self.request.user, 'ishtaruser'): +            return False          if issubclass(form, CustomForm):              enabled, exc = form.check_availability_and_excluded_fields(                  self.request.user.ishtaruser) @@ -184,9 +192,11 @@ class Wizard(NamedUrlWizardView):              self.steps = StepsHelper(self)              current_object = self.get_current_object() +            ishtaruser = request.user.ishtaruser \ +                if hasattr(request.user, 'ishtaruser') else None              # not the fisrt step and current object is not owned              if self.steps and self.steps.first != step and\ -                    current_object and not current_object.is_own(request.user): +                    current_object and not current_object.is_own(ishtaruser):                  self.session_reset(request, self.url_name)                  return HttpResponseRedirect('/')              # extra filter on forms @@ -206,8 +216,8 @@ class Wizard(NamedUrlWizardView):      def get_prefix(self, request, *args, **kwargs):          """As the class name can interfere when reused prefix with the url_name          """ -        return self.url_name + super(Wizard, self).get_prefix( -            request, *args, **kwargs) +        return self.url_name + super(Wizard, self).get_prefix(request, *args, +                                                              **kwargs)      def get_wizard_name(self):          """As the class name can interfere when reused, use the url_name""" | 
