diff options
Diffstat (limited to 'ishtar_common')
-rw-r--r-- | ishtar_common/forms_common.py | 72 | ||||
-rw-r--r-- | ishtar_common/migrations/0054_auto_20180525_1249.py | 24 | ||||
-rw-r--r-- | ishtar_common/models.py | 39 | ||||
-rw-r--r-- | ishtar_common/templates/blocks/bs_form_snippet.html | 4 | ||||
-rw-r--r-- | ishtar_common/templates/ishtar/forms/profile.html | 51 | ||||
-rw-r--r-- | ishtar_common/templates/ishtar/wizard/default_wizard.html | 2 | ||||
-rw-r--r-- | ishtar_common/templatetags/table_form.py | 4 | ||||
-rw-r--r-- | ishtar_common/urls.py | 3 | ||||
-rw-r--r-- | ishtar_common/views.py | 36 | ||||
-rw-r--r-- | ishtar_common/wizards.py | 15 |
10 files changed, 218 insertions, 32 deletions
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: |