summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2016-08-16 16:57:14 +0200
committerÉtienne Loks <etienne.loks@iggdrasil.net>2016-08-16 16:58:35 +0200
commit9b7699ff154f1736c9ed0a93d061812c8296a86f (patch)
tree2ddde4a8b28819f78b4bdd3c6a2c6f5e1f0434d9
parent6f4a3e5256652d0e8205a2000252dea964e7ad4a (diff)
downloadIshtar-9b7699ff154f1736c9ed0a93d061812c8296a86f.tar.bz2
Ishtar-9b7699ff154f1736c9ed0a93d061812c8296a86f.zip
Account management: fix edit - can delete an account (refs #2977)
-rw-r--r--ishtar_common/forms_common.py53
-rw-r--r--ishtar_common/ishtar_menu.py13
-rw-r--r--ishtar_common/models.py3
-rw-r--r--ishtar_common/urls.py8
-rw-r--r--ishtar_common/views.py64
-rw-r--r--ishtar_common/widgets.py4
-rw-r--r--ishtar_common/wizards.py5
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