diff options
| -rw-r--r-- | ishtar_common/forms_common.py | 53 | ||||
| -rw-r--r-- | ishtar_common/ishtar_menu.py | 13 | ||||
| -rw-r--r-- | ishtar_common/models.py | 3 | ||||
| -rw-r--r-- | ishtar_common/urls.py | 8 | ||||
| -rw-r--r-- | ishtar_common/views.py | 64 | ||||
| -rw-r--r-- | ishtar_common/widgets.py | 4 | ||||
| -rw-r--r-- | ishtar_common/wizards.py | 5 | 
7 files changed, 130 insertions, 20 deletions
| diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py index 1d8dc2092..a9873cb0a 100644 --- a/ishtar_common/forms_common.py +++ b/ishtar_common/forms_common.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- -# Copyright (C) 2010-2015  Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2010-2016  Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet>  # This program is free software: you can redistribute it and/or modify  # it under the terms of the GNU Affero General Public License as @@ -306,6 +306,51 @@ class SimplePersonForm(NewItemForm):          self.fields['raw_name'].widget.attrs['readonly'] = True +class PersonUserSelect(PersonSelect): +    ishtaruser__isnull = forms.NullBooleanField( +        label=_(u"Already has an account"), initial=False) + + +class PersonUserFormSelection(PersonFormSelection): +    form_label = _(u"Person search") +    associated_models = {'pk': models.Person} +    currents = {'pk': models.Person} +    pk = forms.IntegerField( +        label="", +        widget=widgets.JQueryJqGrid(reverse_lazy('get-person'), +                                    PersonUserSelect, models.Person), +        validators=[models.valid_id(models.Person)]) + + +class IshtarUserSelect(TableSelect): +    username = forms.CharField(label=_(u"Username"), max_length=200) +    name = forms.CharField(label=_(u"Name"), max_length=200) +    surname = forms.CharField(label=_(u"Surname"), max_length=50) +    email = forms.CharField(label=_(u"Email"), max_length=75) +    person_types = forms.ChoiceField(label=_(u"Type"), choices=[]) +    attached_to = forms.IntegerField( +        label=_("Organization"), +        widget=widgets.JQueryAutoComplete( +            reverse_lazy('autocomplete-organization'), +            associated_model=models.Organization), +        validators=[models.valid_id(models.Organization)]) + +    def __init__(self, *args, **kwargs): +        super(IshtarUserSelect, self).__init__(*args, **kwargs) +        self.fields['person_types'].choices = models.PersonType.get_types() + + +class AccountFormSelection(forms.Form): +    form_label = _(u"Account search") +    associated_models = {'pk': models.IshtarUser} +    currents = {'pk': models.IshtarUser} +    pk = forms.IntegerField( +        label="", +        widget=widgets.JQueryJqGrid(reverse_lazy('get-ishtaruser'), +                                    IshtarUserSelect, models.IshtarUser), +        validators=[models.valid_id(models.IshtarUser)]) + +  class BasePersonForm(forms.ModelForm):      class Meta:          model = models.Person @@ -427,11 +472,11 @@ class AccountForm(forms.Form):                  raise forms.ValidationError(_(u"You must provide a correct "                                                u"password."))          # check username unicity -        usernames = models.IshtarUser.objects.filter( +        q = models.IshtarUser.objects.filter(              username=cleaned_data.get('username'))          if cleaned_data.get('pk'): -            usernames.exclude(pk=cleaned_data.get('pk')) -        if usernames.count(): +            q = q.exclude(person__pk=cleaned_data.get('pk')) +        if q.count():              raise forms.ValidationError(_(u"This username already exists."))          return cleaned_data diff --git a/ishtar_common/ishtar_menu.py b/ishtar_common/ishtar_menu.py index 30cba6735..39bf7c1d6 100644 --- a/ishtar_common/ishtar_menu.py +++ b/ishtar_common/ishtar_menu.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- -# Copyright (C) 2010-2015 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2010-2016 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet>  # This program is free software: you can redistribute it and/or modify  # it under the terms of the GNU Affero General Public License as @@ -28,9 +28,14 @@ import models  MENU_SECTIONS = [      (5, SectionItem('admin', _(u"Administration"),       childs=[ -        MenuItem('account_management', _(u"Account management"), -                 model=models.IshtarUser, -                 access_controls=['add_ishtaruser', ]), +        SectionItem( +            'account', _(u"Account"), +            childs=[MenuItem('account_management', _(u"Add/modify"), +                             model=models.IshtarUser, +                             access_controls=['add_ishtaruser', ]), +                    MenuItem('account_deletion', _(u"Deletion"), +                             model=models.IshtarUser, +                             access_controls=['add_ishtaruser', ]), ]),          MenuItem('admin-globalvar', _(u"Global variables"),                   model=models.GlobalVar,                   access_controls=['add_globalvar', ]), diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 3c46573dd..a4d7f70d9 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -2336,6 +2336,9 @@ class Person(Address, Merge, OwnPerms, ValueGetter):  class IshtarUser(User): +    TABLE_COLS = ('username', 'person__name', 'person__surname', +                  'person__email', 'person__person_types_list', +                  'person__attached_to')      person = models.ForeignKey(Person, verbose_name=_(u"Person"), unique=True,                                 related_name='ishtaruser') diff --git a/ishtar_common/urls.py b/ishtar_common/urls.py index a3bcaffb5..30b5741d9 100644 --- a/ishtar_common/urls.py +++ b/ishtar_common/urls.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- -# Copyright (C) 2010-2015 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2010-2016 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet>  # This program is free software: you can redistribute it and/or modify  # it under the terms of the GNU Affero General Public License as @@ -81,9 +81,15 @@ urlpatterns = patterns(          check_rights(['change_organization', 'change_own_organization'])(              views.OrganizationPersonEdit.as_view()),          name='organization_person_edit'), +    url(r'get-ishtaruser/(?P<type>.+)?$', +        views.get_ishtaruser, +        name='get-ishtaruser'),      url(r'account_management/(?P<step>.+)?$',          check_rights(['add_ishtaruser'])(              views.account_management_wizard), name='account_management'), +    url(r'account_deletion/(?P<step>.+)?$', +        check_rights(['add_ishtaruser'])( +            views.account_deletion_wizard), name='account_deletion'),      url(r'^import-new/$',          check_rights(['change_import'])(              views.NewImportView.as_view()), name='new_import'), diff --git a/ishtar_common/views.py b/ishtar_common/views.py index 2d0976be1..01811ed2d 100644 --- a/ishtar_common/views.py +++ b/ishtar_common/views.py @@ -38,6 +38,7 @@ from django.contrib.auth.decorators import login_required  from django.core.exceptions import ObjectDoesNotExist  from django.core.urlresolvers import reverse, NoReverseMatch  from django.db.models import Q, ImageField +from django.db.models.fields import FieldDoesNotExist  from django.forms.models import modelformset_factory  from django.http import HttpResponse, Http404, HttpResponseRedirect, \      HttpResponseBadRequest @@ -148,12 +149,18 @@ organization_deletion_wizard = wizards.OrganizationDeletionWizard.as_view(      url_name='organization_deletion',)  account_management_wizard = wizards.AccountWizard.as_view( -    [('selec-account_management', forms.PersonFormSelection), +    [('selec-account_management', forms.PersonUserFormSelection),       ('account-account_management', forms.AccountForm),       ('final-account_management', forms.FinalAccountForm)],      label=_(u"Account management"),      url_name='account_management',) +account_deletion_wizard = wizards.IshtarUserDeletionWizard.as_view( +    [('selec-account_deletion', forms.AccountFormSelection), +     ('final-account_deletion', FinalDeleteForm)], +    label=_(u"Account deletion"), +    url_name='account_deletion',) +  def get_autocomplete_generic(model, extra={'available': True}):      def func(request): @@ -447,14 +454,19 @@ def get_item(model, func_name, default_name, extra_request_keys=[],                      if k in reversed_bool_fields:                          dct[k] = not dct[k]                      # check also for empty value with image field -                    c_field = model._meta.get_field(k.split('__')[0]) -                    if k.endswith('__isnull') and \ -                       isinstance(c_field, ImageField): -                        if dct[k]: -                            or_reqs.append( -                                (k, {k.split('__')[0] + '__exact': ''})) -                        else: -                            dct[k.split('__')[0] + '__regex'] = '.{1}.*' +                    field_name = k.split('__')[0] +                    # TODO: can be improved in later evrsion of Django +                    try: +                        c_field = model._meta.get_field(field_name) +                        if k.endswith('__isnull') and \ +                           isinstance(c_field, ImageField): +                            if dct[k]: +                                or_reqs.append( +                                    (k, {k.split('__')[0] + '__exact': ''})) +                            else: +                                dct[k.split('__')[0] + '__regex'] = '.{1}.*' +                    except FieldDoesNotExist: +                        pass          for k in dated_fields:              if k in dct:                  if not dct[k]: @@ -527,6 +539,7 @@ def get_item(model, func_name, default_name, extra_request_keys=[],              query = query & and_req          items = model.objects.filter(query).distinct() +        # print(items.query)          q = request_items.get('sidx')          # table cols @@ -614,7 +627,14 @@ def get_item(model, func_name, default_name, extra_request_keys=[],                  my_vals = []                  for k in keys:                      vals = [item] +                    # foreign key may be splited by "." or "__" +                    splitted_k = []                      for ky in k.split('.'): +                        if '__' in ky: +                            splitted_k += ky.split('__') +                        else: +                            splitted_k.append(ky) +                    for ky in splitted_k:                          new_vals = []                          for val in vals:                              if hasattr(val, 'all'):  # manage related objects @@ -685,7 +705,16 @@ def get_item(model, func_name, default_name, extra_request_keys=[],                          table_col = table_cols[idx]                          if type(table_col) not in (list, tuple):                              table_col = [table_col] -                        k = "__".join([tc.split('.')[-1] for tc in table_col]) +                        tab_cols = [] +                        # foreign key may be splited by "." or "__" +                        for tc in table_col: +                            if '.' in tc: +                                tab_cols.append(tc.split('.')[-1]) +                            elif '__' in tc: +                                tab_cols.append(tc.split('__')[-1]) +                            else: +                                tab_cols.append(tc) +                        k = "__".join(tab_cols)                          res[k] = value                  rows.append(res)              data = json.dumps({ @@ -941,11 +970,26 @@ show_person = show_item(models.Person, 'person')  get_person = get_item(      models.Person,      'get_person', 'person', +    reversed_bool_fields=['ishtaruser__isnull'],      extra_request_keys={          'name': ['name__icontains', 'raw_name__icontains'],          'surname': ['surname__icontains', 'raw_name__icontains'],          'attached_to': 'attached_to__pk',          'person_types': 'person_types__pk__in', +        'ishtaruser__isnull': 'ishtaruser__isnull' +    }) + +get_ishtaruser = get_item( +    models.IshtarUser, +    'get_ishtaruser', 'ishtaruser', +    extra_request_keys={ +        'username': ['username__icontains'], +        'name': ['person__name__icontains', 'person__raw_name__icontains'], +        'surname': ['person__surname__icontains', +                    'person__raw_name__icontains'], +        'email': ['person__email'], +        'attached_to': 'person__attached_to__pk', +        'person_types': 'person__person_types__pk__in',      }) diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py index 6d9600d0c..83fb23caf 100644 --- a/ishtar_common/widgets.py +++ b/ishtar_common/widgets.py @@ -539,7 +539,9 @@ class JQueryJqGrid(forms.RadioSelect):                  col_names = [col_names]              for col_name in col_names:                  field = self.associated_model -                keys = col_name.split('.') +                keys = col_name.split('__') +                if '.' in col_name: +                    keys = col_name.split('.')                  f_name = ''                  for key in keys:                      if hasattr(field, 'rel') and field.rel: diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py index 97bb6fb37..f028c15d8 100644 --- a/ishtar_common/wizards.py +++ b/ishtar_common/wizards.py @@ -1132,6 +1132,11 @@ class PersonDeletionWizard(DeletionWizard):          'final-person_deletion': 'ishtar/wizard/wizard_person_deletion.html'} +class IshtarUserDeletionWizard(DeletionWizard): +    model = models.IshtarUser +    fields = model.TABLE_COLS + +  class OrganizationWizard(Wizard):      model = models.Organization | 
