summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2018-05-28 16:58:42 +0200
committerÉtienne Loks <etienne.loks@iggdrasil.net>2018-06-12 08:49:36 +0200
commitf5634457ef7882cbc9fcb30d0e12a61d4f13498a (patch)
treec616f2686db785b7b1103beb85636d1891cc354c
parent4fba7337a52de2efd795b24cb9cd2797b1427987 (diff)
downloadIshtar-f5634457ef7882cbc9fcb30d0e12a61d4f13498a.tar.bz2
Ishtar-f5634457ef7882cbc9fcb30d0e12a61d4f13498a.zip
User profile form: duplicate, delete and edit
-rw-r--r--archaeological_warehouse/migrations/0018_auto_20180528_1141.py21
-rw-r--r--ishtar_common/forms_common.py72
-rw-r--r--ishtar_common/migrations/0054_auto_20180525_1249.py24
-rw-r--r--ishtar_common/models.py39
-rw-r--r--ishtar_common/templates/blocks/bs_form_snippet.html4
-rw-r--r--ishtar_common/templates/ishtar/forms/profile.html51
-rw-r--r--ishtar_common/templates/ishtar/wizard/default_wizard.html2
-rw-r--r--ishtar_common/templatetags/table_form.py4
-rw-r--r--ishtar_common/urls.py3
-rw-r--r--ishtar_common/views.py36
-rw-r--r--ishtar_common/wizards.py15
11 files changed, 239 insertions, 32 deletions
diff --git a/archaeological_warehouse/migrations/0018_auto_20180528_1141.py b/archaeological_warehouse/migrations/0018_auto_20180528_1141.py
new file mode 100644
index 000000000..16fd954e4
--- /dev/null
+++ b/archaeological_warehouse/migrations/0018_auto_20180528_1141.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.10 on 2018-05-28 11:41
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('archaeological_warehouse', '0017_auto_20180509_1747'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='warehousedivisionlink',
+ name='warehouse',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='divisions', to='archaeological_warehouse.Warehouse'),
+ ),
+ ]
diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py
index af16e6deb..edea0cde2 100644
--- a/ishtar_common/forms_common.py
+++ b/ishtar_common/forms_common.py
@@ -771,6 +771,7 @@ class ProfileForm(ManageOldType):
profile_type = forms.ChoiceField(label=_(u"Type"), choices=[],
required=False)
area = widgets.Select2MultipleField(label=_(u"Areas"), required=False)
+ name = forms.CharField(label=_(u"Name"), required=False)
pk = forms.IntegerField(label=" ", widget=forms.HiddenInput, required=False)
TYPES = [
@@ -798,37 +799,88 @@ class FinalAccountForm(forms.Form):
class ProfilePersonForm(forms.Form):
+ """
+ Edit the current profile
+ """
current_profile = forms.ChoiceField(label=_(u"Current profile"),
choices=[])
+ name = forms.CharField(label=_(u"Name"), required=False)
+ profile_type = forms.ChoiceField(label=_(u"Profile type"), required=False,
+ disabled=True, choices=[])
+ duplicate_profile = forms.BooleanField(
+ label=_(u"Duplicate this profile"), required=False)
+ delete_profile = forms.BooleanField(
+ label=_(u"Delete this profile"), required=False,
+ )
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user')
choices, initial = [], kwargs.get('initial', {})
- for profile in self.user.ishtaruser.person.profiles.all():
+ current_profile = None
+ for profile in self.user.ishtaruser.person.profiles.order_by(
+ 'name', 'profile_type__label').all():
if profile.current:
+ current_profile = profile
initial['current_profile'] = profile.pk
choices.append((profile.pk, unicode(profile)))
+ if current_profile:
+ initial['name'] = current_profile.name or \
+ current_profile.profile_type
+ initial['profile_type'] = current_profile.profile_type.pk
kwargs['initial'] = initial
super(ProfilePersonForm, self).__init__(*args, **kwargs)
self.fields['current_profile'].choices = choices
- def save(self, session):
- q = models.UserProfile.objects.filter(
- person__ishtaruser=self.user.ishtaruser, current=True)
- for profile in q.all():
- profile.current = False
- profile.save()
+ if not current_profile or \
+ not self.user.ishtaruser.person.profiles.filter(
+ profile_type=current_profile.profile_type).exclude(
+ pk=current_profile.pk).count():
+ # cannot delete the current profile if no profile of this type is
+ # available
+ self.fields.pop('delete_profile')
+
+ if not current_profile:
+ return
+ self.fields['profile_type'].choices = [
+ (current_profile.profile_type.pk, current_profile.profile_type.name)
+ ]
+ def save(self, session):
q = models.UserProfile.objects.filter(
person__ishtaruser=self.user.ishtaruser,
- pk=int(self.cleaned_data['current_profile'])
- )
+ pk=self.cleaned_data['current_profile'])
if not q.count():
return
profile = q.all()[0]
+
+ # manage deletion
+ if self.cleaned_data.get('delete_profile', None):
+ q = self.user.ishtaruser.person.profiles.filter(
+ profile_type=profile.profile_type).exclude(
+ pk=profile.pk)
+ if not q.count():
+ # cannot delete the current profile if no profile of this type
+ # is available
+ return
+ new_current = q.all()[0]
+ new_current.current = True
+ new_current.save()
+ profile.delete()
+ return
+
+ name = self.cleaned_data['name']
+
+ # manage duplication
+ if self.cleaned_data.get('duplicate_profile', None):
+ profile_name = profile.name or profile.profile_type.label
+ if name == profile_name:
+ name += unicode(_(u" (duplicate)"))
+ profile.duplicate(name=name)
+ return
+
profile.current = True
+ profile.name = name
profile.save()
-
clean_session_cache(session)
diff --git a/ishtar_common/migrations/0054_auto_20180525_1249.py b/ishtar_common/migrations/0054_auto_20180525_1249.py
new file mode 100644
index 000000000..46f63b5c0
--- /dev/null
+++ b/ishtar_common/migrations/0054_auto_20180525_1249.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.10 on 2018-05-25 12:49
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('ishtar_common', '0053_auto_20180523_1504'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='userprofile',
+ name='name',
+ field=models.CharField(blank=True, default='', max_length=100, verbose_name='Name'),
+ ),
+ migrations.AlterUniqueTogether(
+ name='userprofile',
+ unique_together=set([('name', 'profile_type', 'person')]),
+ ),
+ ]
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index a5bf6cf3a..b31338a2d 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -2792,6 +2792,7 @@ post_delete.connect(post_save_cache, sender=ProfileType)
class UserProfile(models.Model):
+ name = models.CharField(_(u"Name"), blank=True, default=u"", max_length=100)
profile_type = models.ForeignKey(
ProfileType, verbose_name=_(u"Profile type"))
areas = models.ManyToManyField("Area", verbose_name=_(u"Areas"),
@@ -2803,9 +2804,10 @@ class UserProfile(models.Model):
class Meta:
verbose_name = _(u"User profile")
verbose_name_plural = _(u"User profiles")
+ unique_together = (('name', 'profile_type', 'person'),)
def __unicode__(self):
- lbl = unicode(self.profile_type)
+ lbl = self.name or unicode(self.profile_type)
if not self.areas.count():
return lbl
return u"{} ({})".format(lbl, u", ".join(
@@ -2824,6 +2826,34 @@ class UserProfile(models.Model):
def area_labels(self):
return u", ".join([unicode(area) for area in self.areas.all()])
+ def duplicate(self, **kwargs):
+ areas = [area for area in self.areas.all()]
+ new_item = self
+ new_item.pk = None
+ for key in kwargs:
+ setattr(new_item, key, kwargs[key])
+ new_item.save()
+ for area in areas:
+ new_item.areas.add(area)
+ return new_item
+
+ def save(self, force_insert=False, force_update=False, using=None,
+ update_fields=None):
+ super(UserProfile, self).save(
+ force_insert=force_insert, force_update=force_update, using=using,
+ update_fields=update_fields)
+
+ # only one current profile per user
+ if not self.current:
+ return
+ q = UserProfile.objects.filter(
+ person=self.person, current=True).exclude(pk=self.pk)
+ if not q.count():
+ return
+ for p in q.all():
+ p.current = False
+ p.save()
+
class IshtarUser(FullSearch):
TABLE_COLS = ('username', 'person__name', 'person__surname',
@@ -2864,8 +2894,8 @@ class IshtarUser(FullSearch):
def current_profile_name(self):
q = UserProfile.objects.filter(current=True, person__ishtaruser=self)
if q.count():
- return q.values('profile_type__label').all()[0][
- 'profile_type__label']
+ vals = q.values('profile_type__label', 'name').all()[0]
+ return vals['name'] or vals['profile_type__label']
profile = self.person.current_profile
if not profile:
return u""
@@ -2885,6 +2915,9 @@ class IshtarUser(FullSearch):
admin, created = ProfileType.objects.get_or_create(
txt_idx='administrator')
if user.is_superuser:
+ if UserProfile.objects.filter(
+ profile_type=admin, person=person).count():
+ return
UserProfile.objects.get_or_create(
profile_type=admin, person=person,
defaults={'current': True})
diff --git a/ishtar_common/templates/blocks/bs_form_snippet.html b/ishtar_common/templates/blocks/bs_form_snippet.html
index 818c654d1..47779cdc1 100644
--- a/ishtar_common/templates/blocks/bs_form_snippet.html
+++ b/ishtar_common/templates/blocks/bs_form_snippet.html
@@ -64,9 +64,9 @@
{% if forloop.counter0 %}
</div>{% endif %}
<h3>{{field.name|from_dict:form.HEADERS|call:'render'}}</h3>
-<div class="form-row">
+<div class="form-row{% if odd %} odd{% endif %}">
{% elif not search and not forloop.counter0 or search and forloop.counter0 == 1 %}
- <div class="form-row">
+ <div class="form-row{% if odd %} odd{% endif %}">
{% endif %}
{% include "blocks/bs_field_snippet.html" %}
{% if forloop.last %}
diff --git a/ishtar_common/templates/ishtar/forms/profile.html b/ishtar_common/templates/ishtar/forms/profile.html
new file mode 100644
index 000000000..02f50be7b
--- /dev/null
+++ b/ishtar_common/templates/ishtar/forms/profile.html
@@ -0,0 +1,51 @@
+{% extends "ishtar/form.html" %}
+{% load i18n inline_formset table_form %}
+{% block extra_head %}
+<script type='text/javascript'>
+var base_profile_url = "{% url 'profile' %}";
+$(document).ready(function(){
+ $("#id_current_profile").change(function(){
+ var profile_id = $("#id_current_profile option:selected").val();
+ window.location.href = base_profile_url + profile_id + "/";
+ });
+});
+</script>
+{% endblock %}
+
+{% block content %}
+<h2>{{page_name}}</h2>
+<div class='form'>
+
+ {% if form.non_field_errors %}
+ <div class="alert alert-danger" role="alert">
+ {{form.non_field_errors}}
+ </div>
+ {% endif %}
+
+ {% for hidden in form.hidden_fields %}
+ {{hidden}}
+ {% if hidden.errors %}<div class="invalid-feedback">
+ {{ hidden.errors }}
+ </div>{% endif %}
+ {% endfor %}
+
+ <div class="form-row">
+ {% for field in form.visible_fields %}
+ {% if forloop.counter0 == 0 %}
+ <div class="form-group col-lg-12">
+ {{field|safe}}
+ </div>
+ </div>
+ <div class="form-row">
+ {% elif field.name == 'delete_profile' %}
+ </div>
+ <div class="form-row col-lg-6 alert alert-danger">
+ {% include "blocks/bs_field_snippet.html" %}
+ {% else %}
+ {% include "blocks/bs_field_snippet.html" %}
+ {% endif %}
+ {% endfor %}
+ </div>
+</div>
+{% endblock %}
+
diff --git a/ishtar_common/templates/ishtar/wizard/default_wizard.html b/ishtar_common/templates/ishtar/wizard/default_wizard.html
index a7a705f59..6707124f9 100644
--- a/ishtar_common/templates/ishtar/wizard/default_wizard.html
+++ b/ishtar_common/templates/ishtar/wizard/default_wizard.html
@@ -25,7 +25,7 @@
</div>
{% endif %}
{% for formsetform in wizard.form.forms %}
- {% bs_form formsetform %}
+ {% bs_form formsetform forloop.counter0 %}
{% endfor %}
<button class="btn btn-success" name="formset_modify" value="{{wizard.steps.current}}">
{% trans "Add/Modify" %}
diff --git a/ishtar_common/templatetags/table_form.py b/ishtar_common/templatetags/table_form.py
index 0ebd8443e..0aee9919b 100644
--- a/ishtar_common/templatetags/table_form.py
+++ b/ishtar_common/templatetags/table_form.py
@@ -8,8 +8,8 @@ register = Library()
@register.inclusion_tag('blocks/bs_form_snippet.html')
-def bs_form(form):
- return {'form': form}
+def bs_form(form, position=0):
+ return {'form': form, 'odd': position % 2}
@register.inclusion_tag('blocks/table_form_snippet.html')
diff --git a/ishtar_common/urls.py b/ishtar_common/urls.py
index 90784ec96..5a3ed217d 100644
--- a/ishtar_common/urls.py
+++ b/ishtar_common/urls.py
@@ -122,7 +122,8 @@ urlpatterns = [
kwargs={'all_pages': True}),
url(r'^import-step-by-step/(?P<pk>[0-9]+)/(?P<line_number>[0-9]+)/$',
views.ImportStepByStepView.as_view(), name='import_step_by_step'),
- url(r'^profile/', views.ProfileEdit.as_view(), name='profile'),
+ url(r'^profile(?:/(?P<pk>[0-9]+))?/$', views.ProfileEdit.as_view(),
+ name='profile'),
]
menu = Menu(None)
diff --git a/ishtar_common/views.py b/ishtar_common/views.py
index f6468afd0..c9a2d92dd 100644
--- a/ishtar_common/views.py
+++ b/ishtar_common/views.py
@@ -71,8 +71,9 @@ from archaeological_finds.forms import DashboardTreatmentForm, \
from ishtar_common.forms import FinalForm, FinalDeleteForm
from ishtar_common.widgets import JQueryAutoComplete
-from ishtar_common.utils import get_random_item_image_link, shortify, \
- get_all_field_names, get_field_labels_from_path
+from ishtar_common.utils import clean_session_cache, \
+ get_all_field_names, get_field_labels_from_path, \
+ get_random_item_image_link, shortify
from ishtar_common import forms_common as forms
from ishtar_common import wizards
from ishtar_common.models import HistoryError, PRIVATE_FIELDS, \
@@ -1756,11 +1757,6 @@ class LoginRequiredMixin(object):
def dispatch(self, request, *args, **kwargs):
return super(LoginRequiredMixin, self).dispatch(request, *args,
**kwargs)
- if kwargs.get('pk') and not self.request.user.is_staff and \
- not str(kwargs['pk']) == str(self.request.user.company.pk):
- return redirect(reverse('index'))
- return super(LoginRequiredMixin, self).dispatch(request, *args,
- **kwargs)
class AdminLoginRequiredMixin(LoginRequiredMixin):
@@ -1772,9 +1768,28 @@ class AdminLoginRequiredMixin(LoginRequiredMixin):
class ProfileEdit(LoginRequiredMixin, FormView):
- template_name = 'ishtar/form.html'
+ template_name = 'ishtar/forms/profile.html'
form_class = forms.ProfilePersonForm
+ def dispatch(self, request, *args, **kwargs):
+ if kwargs.get('pk'):
+ try:
+ profile = models.UserProfile.objects.get(
+ pk=kwargs['pk'], person__ishtaruser__user_ptr=request.user)
+ except models.UserProfile.DoesNotExist:
+ # cannot edit a profile that is not yours...
+ return redirect(reverse('index'))
+ current_changed = False
+ # the profile edited became the current profile
+ if not profile.current:
+ current_changed = True
+ profile.current = True
+ # force post-save in case of many current profile
+ profile.save()
+ if current_changed:
+ clean_session_cache(request.session)
+ return super(ProfileEdit, self).dispatch(request, *args, **kwargs)
+
def get_success_url(self):
return reverse('profile')
@@ -1783,6 +1798,11 @@ class ProfileEdit(LoginRequiredMixin, FormView):
kwargs['user'] = self.request.user
return kwargs
+ def get_context_data(self, **kwargs):
+ data = super(ProfileEdit, self).get_context_data(**kwargs)
+ data['page_name'] = _(u"Current profile")
+ return data
+
def form_valid(self, form):
form.save(self.request.session)
return HttpResponseRedirect(self.get_success_url())
diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py
index a6d0befd5..3e153c9dd 100644
--- a/ishtar_common/wizards.py
+++ b/ishtar_common/wizards.py
@@ -1619,7 +1619,6 @@ class AccountWizard(Wizard):
model = models.Person
formset_pop_deleted = False
wizard_done_window = reverse_lazy('show-person')
- modification = True
def get_formated_datas(self, forms):
datas = super(AccountWizard, self).get_formated_datas(forms)
@@ -1695,6 +1694,8 @@ class AccountWizard(Wizard):
profile.delete()
continue
+ name = data.get('name', None)
+
profile_type_id = data.get('profile_type', None)
if not profile_type_id:
continue
@@ -1704,13 +1705,17 @@ class AccountWizard(Wizard):
)
except models.ProfileType.DoesNotExist:
continue
+
+ if not name:
+ name = profile_type.label
+
if profile:
- if profile_type != profile.profile_type:
- profile.profile_type = profile_type
- profile.save()
+ profile.name = name
+ profile.profile_type = profile_type
+ profile.save()
else:
profile = models.UserProfile.objects.create(
- profile_type=profile_type, person=person)
+ profile_type=profile_type, person=person, name=name)
area_pks = data.get('area', None)
areas = []
if area_pks: