diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2018-02-14 12:39:03 +0100 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2018-02-15 17:20:19 +0100 |
commit | 038c7ce8bbb1d40a99c98811f1c267a6218b22c2 (patch) | |
tree | df7cf20de56e13c9660d14219d7ee5d825bb2909 | |
parent | 365546bcd78bed54c6ab2d7f375b86cde8caa66f (diff) | |
download | Ishtar-038c7ce8bbb1d40a99c98811f1c267a6218b22c2.tar.bz2 Ishtar-038c7ce8bbb1d40a99c98811f1c267a6218b22c2.zip |
Archaeological site: search view (refs #3913)
- add site to profile
- allow alternate label in menus for sites
- add entry in menu
- basic configuration of site model
-rw-r--r-- | archaeological_operations/forms.py | 43 | ||||
-rw-r--r-- | archaeological_operations/ishtar_menu.py | 96 | ||||
-rw-r--r-- | archaeological_operations/models.py | 5 | ||||
-rw-r--r-- | archaeological_operations/urls.py | 8 | ||||
-rw-r--r-- | archaeological_operations/views.py | 12 | ||||
-rw-r--r-- | archaeological_operations/wizards.py | 18 | ||||
-rw-r--r-- | ishtar_common/context_processors.py | 3 | ||||
-rw-r--r-- | ishtar_common/forms.py | 144 | ||||
-rw-r--r-- | ishtar_common/menu_base.py | 8 | ||||
-rw-r--r-- | ishtar_common/migrations/0028_auto_20180214_1144.py | 49 | ||||
-rw-r--r-- | ishtar_common/models.py | 70 | ||||
-rw-r--r-- | ishtar_common/templates/base.html | 2 | ||||
-rw-r--r-- | ishtar_common/wizards.py | 10 |
13 files changed, 341 insertions, 127 deletions
diff --git a/archaeological_operations/forms.py b/archaeological_operations/forms.py index 4f5ac0435..38efb269f 100644 --- a/archaeological_operations/forms.py +++ b/archaeological_operations/forms.py @@ -1245,6 +1245,49 @@ class OperationDeletionForm(FinalForm): confirm_msg = " " confirm_end_msg = _(u"Would you like to delete this operation?") +######### +# Sites # +######### + + +class SiteSelect(TableSelect): + search_vector = forms.CharField(label=_(u"Full text search")) + reference = forms.CharField(label=_(u"Reference"), max_length=200, + required=False) + name = forms.CharField(label=_(u"Name"), max_length=200, required=False) + periods = forms.ChoiceField(label=_(u"Periods"), choices=[], required=False) + remains = forms.ChoiceField(label=_(u"Remains"), choices=[], required=False) + TYPES = [ + FieldType('periods', models.Period), + FieldType('remains', models.RemainType), + ] + + +class SiteFormSelection(IshtarForm): + SEARCH_AND_SELECT = True + associated_models = {'pk': models.ArchaeologicalSite} + currents = {'pk': models.ArchaeologicalSite} + pk = forms.IntegerField( + label="", required=False, + widget=widgets.DataTable( + reverse_lazy('get-site'), SiteSelect, + models.ArchaeologicalSite, + source_full=reverse_lazy('get-site-full')), + validators=[valid_id(models.Operation)]) + + @classmethod + def form_label(cls): + return unicode(_(u"{} search")).format( + get_current_profile().get_site_label() + ) + + def clean(self): + cleaned_data = self.cleaned_data + if 'pk' not in cleaned_data or not cleaned_data['pk']: + raise forms.ValidationError(_(u"You should select an item.")) + return cleaned_data + + #################################### # Source management for operations # #################################### diff --git a/archaeological_operations/ishtar_menu.py b/archaeological_operations/ishtar_menu.py index 4ad0c58a3..5c2cca383 100644 --- a/archaeological_operations/ishtar_menu.py +++ b/archaeological_operations/ishtar_menu.py @@ -21,11 +21,103 @@ from django.utils.translation import ugettext_lazy as _, pgettext_lazy from ishtar_common.menu_base import SectionItem, MenuItem -import models +from ishtar_common.models import IshtarSiteProfile +from archaeological_operations import models -# be carreful: each access_controls must be relevant with check_rights in urls +# be careful: each access_controls must be relevant with check_rights in urls + +""" +MenuItem( + 'operation_creation', _(u"Creation"), + model=models.Operation, + access_controls=['add_operation', + 'add_own_operation']), +MenuItem( + 'operation_modification', _(u"Modification"), + model=models.Operation, + access_controls=['change_operation', + 'change_own_operation']), +MenuItem( + 'operation_closing', _(u"Closing"), + model=models.Operation, + access_controls=['close_operation']), +MenuItem( + 'operation_deletion', _(u"Deletion"), + model=models.Operation, + access_controls=['change_operation', + 'change_own_operation']), +SectionItem( + 'admin_act_operations', + _(u"Administrative act"), + profile_restriction='files', + childs=[ + MenuItem( + 'operation_administrativeactop_search', + _(u"Search"), + model=models.AdministrativeAct, + access_controls=[ + 'change_administrativeact']), + MenuItem( + 'operation_administrativeactop', + _(u"Creation"), + model=models.AdministrativeAct, + access_controls=['change_administrativeact']), + MenuItem( + 'operation_administrativeactop_modification', + _(u"Modification"), + model=models.AdministrativeAct, + access_controls=['change_administrativeact']), + MenuItem( + 'operation_administrativeactop_deletion', + _(u"Deletion"), + model=models.AdministrativeAct, + access_controls=['change_administrativeact']), + MenuItem( + 'operation_administrativeact_document', + _(u"Documents"), + model=models.AdministrativeAct, + access_controls=['change_administrativeact']), + ],), +SectionItem( + 'operation_source', _(u"Documentation"), + childs=[ + MenuItem('operation_source_search', + _(u"Search"), + model=models.OperationSource, + access_controls=['view_operation', + 'view_own_operation']), + MenuItem('operation_source_creation', + _(u"Creation"), + model=models.OperationSource, + access_controls=['change_operation', + 'change_own_operation']), + MenuItem('operation_source_modification', + _(u"Modification"), + model=models.OperationSource, + access_controls=['change_operation', + 'change_own_operation']), + MenuItem('operation_source_deletion', + _(u"Deletion"), + model=models.OperationSource, + access_controls=['change_operation', + 'change_own_operation']), + ]) + +""" MENU_SECTIONS = [ + (25, SectionItem( + 'site_management', IshtarSiteProfile.get_default_site_label, + css='menu-site', + profile_restriction='archaeological_site', + childs=[ + MenuItem( + 'site_search', _(u"Search"), + model=models.ArchaeologicalSite, + access_controls=['view_archaeologicalsite', + 'view_own_archaeologicalsite']), + ]), + ), (30, SectionItem( 'operation_management', _(u"Operation"), css='menu-operation', diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py index 06d9b5af0..899ff0707 100644 --- a/archaeological_operations/models.py +++ b/archaeological_operations/models.py @@ -89,6 +89,11 @@ post_delete.connect(post_save_cache, sender=ReportState) class ArchaeologicalSite(BaseHistorizedItem): + SHOW_URL = 'show-site' + TABLE_COLS = ['reference', 'name', 'periods', 'remains'] + SLUG = 'site' + BASE_SEARCH_VECTORS = ["reference", "name"] + M2M_SEARCH_VECTORS = ["periods__name", "remains__name"] reference = models.CharField(_(u"Reference"), max_length=20, unique=True) name = models.CharField(_(u"Name"), max_length=200, null=True, blank=True) diff --git a/archaeological_operations/urls.py b/archaeological_operations/urls.py index 08687ae14..00880e303 100644 --- a/archaeological_operations/urls.py +++ b/archaeological_operations/urls.py @@ -152,6 +152,14 @@ urlpatterns = [ url(r'new-archaeologicalsite/(?:(?P<parent_name>[^/]+)/)?' r'(?:(?P<limits>[^/]+)/)?$', views.new_archaeologicalsite, name='new-archaeologicalsite'), + url(r'get-site/(?P<type>.+)?$', + views.get_site, name='get-site'), + url(r'get-site-full/(?P<type>.+)?$', + views.get_site, name='get-site-full', kwargs={'full': True}), + url(r'site_search/(?P<step>.+)?$', + check_rights(['view_archaeologicalsite', + 'view_own_archaeologicalsite'])( + views.site_search_wizard), name='site_search'), url(r'autocomplete-patriarche/$', views.autocomplete_patriarche, name='autocomplete-patriarche'), url(r'operation_administrativeact_document/$', diff --git a/archaeological_operations/views.py b/archaeological_operations/views.py index a4cb1f673..d20c14dfa 100644 --- a/archaeological_operations/views.py +++ b/archaeological_operations/views.py @@ -307,6 +307,18 @@ operation_deletion_wizard = OperationDeletionWizard.as_view( label=_(u"Operation deletion"), url_name='operation_deletion',) + +# archaeological sites + +get_site = get_item(models.ArchaeologicalSite, 'get_site', 'site') + +site_search_wizard = SiteSearch.as_view( + [('general-site_search', SiteFormSelection)], + label=_(u"{} search"), + url_name='site_search',) + +# operation sources + operation_source_search_wizard = SearchWizard.as_view([ ('selec-operation_source_search', OperationSourceFormSelection)], label=_(u"Operation: source search"), diff --git a/archaeological_operations/wizards.py b/archaeological_operations/wizards.py index 24c1af45b..01c9cbc2e 100644 --- a/archaeological_operations/wizards.py +++ b/archaeological_operations/wizards.py @@ -27,13 +27,16 @@ from django.http import Http404 from django.shortcuts import render from django.utils.translation import ugettext_lazy as _ +from ishtar_common.models import get_current_profile +from archaeological_files.models import File +from archaeological_operations import models + from ishtar_common.forms import reverse_lazy -from ishtar_common.wizards import Wizard, ClosingWizard, DeletionWizard, \ - SourceWizard -import models from forms import GenerateDocForm -from archaeological_files.models import File +from ishtar_common.wizards import Wizard, ClosingWizard, DeletionWizard, \ + SourceWizard, SearchWizard + logger = logging.getLogger(__name__) @@ -445,6 +448,13 @@ class OperationEditAdministrativeActWizard(OperationAdministrativeActWizard): return self.get_current_object().operation +class SiteSearch(SearchWizard): + def get_label(self): + return unicode(_(u"Search {}")).format( + get_current_profile().get_site_label() + ) + + class AdministrativeActDeletionWizard(ClosingWizard): wizard_templates = { 'final-operation_administrativeactop_deletion': diff --git a/ishtar_common/context_processors.py b/ishtar_common/context_processors.py index 93d524d2b..437ceb677 100644 --- a/ishtar_common/context_processors.py +++ b/ishtar_common/context_processors.py @@ -68,7 +68,4 @@ def get_base_context(request): dct['EXTRA_JS'] += "\n" + "\n".join(media.render_js()) if settings.EXTRA_VERSION: dct['VERSION'] += "-" + unicode(settings.EXTRA_VERSION) - profile = get_current_profile() - if profile: - dct['raw_css'] = profile.get_raw_css() return dct diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py index eb548f70c..13e8457f6 100644 --- a/ishtar_common/forms.py +++ b/ishtar_common/forms.py @@ -263,7 +263,78 @@ class IshtarForm(forms.Form): widget.options['todayHighlight'] = 'true' -class TableSelect(IshtarForm): +class FieldType(object): + def __init__(self, key, model, is_multiple=False, extra_args=None): + self.key = key + self.model = model + self.is_multiple = is_multiple + self.extra_args = extra_args + + def get_choices(self, initial=None): + args = { + 'empty_first': not self.is_multiple, + 'initial': initial + } + if self.extra_args: + args.update(self.extra_args) + return self.model.get_types(**args) + + def get_help(self): + args = {} + if self.extra_args: + args.update(self.extra_args) + return self.model.get_help(**args) + + +class ManageOldType(IshtarForm): + TYPES = [] # FieldType list + + def __init__(self, *args, **kwargs): + """ + init_data is used to manage deactivated items in list when editing + old data + """ + prefix = kwargs.get('prefix') or '' + self.init_data = {} + if 'data' in kwargs and kwargs['data']: + for k in kwargs['data']: + if prefix not in k: + continue + new_k = k[len(prefix) + 1:] + if hasattr(kwargs['data'], 'getlist'): + items = kwargs['data'].getlist(k) + else: + items = [kwargs['data'][k]] + for val in items: + if not val: + continue + if new_k not in self.init_data: + self.init_data[new_k] = [] + self.init_data[new_k].append(val) + if 'initial' in kwargs and kwargs['initial']: + for k in kwargs['initial']: + if k not in self.init_data or not self.init_data[k]: + if hasattr(kwargs['initial'], 'getlist'): + items = kwargs['initial'].getlist(k) + else: + items = [kwargs['initial'][k]] + for val in items: + if not val: + continue + if k not in self.init_data: + self.init_data[k] = [] + self.init_data[k].append(val) + self.init_data = MultiValueDict(self.init_data) + super(ManageOldType, self).__init__(*args, **kwargs) + for field in self.TYPES: + if field.key not in self.fields: + continue + self.fields[field.key].choices = field.get_choices( + initial=self.init_data.get(field.key)) + self.fields[field.key].help_text = field.get_help() + + +class TableSelect(ManageOldType): def __init__(self, *args, **kwargs): super(TableSelect, self).__init__(*args, **kwargs) # no field is required for search @@ -361,77 +432,6 @@ def get_data_from_formset(data): return values -class FieldType(object): - def __init__(self, key, model, is_multiple=False, extra_args=None): - self.key = key - self.model = model - self.is_multiple = is_multiple - self.extra_args = extra_args - - def get_choices(self, initial=None): - args = { - 'empty_first': not self.is_multiple, - 'initial': initial - } - if self.extra_args: - args.update(self.extra_args) - return self.model.get_types(**args) - - def get_help(self): - args = {} - if self.extra_args: - args.update(self.extra_args) - return self.model.get_help(**args) - - -class ManageOldType(IshtarForm): - TYPES = [] # FieldType list - - def __init__(self, *args, **kwargs): - """ - init_data is used to manage deactivated items in list when editing - old data - """ - prefix = kwargs.get('prefix') or '' - self.init_data = {} - if 'data' in kwargs and kwargs['data']: - for k in kwargs['data']: - if prefix not in k: - continue - new_k = k[len(prefix) + 1:] - if hasattr(kwargs['data'], 'getlist'): - items = kwargs['data'].getlist(k) - else: - items = [kwargs['data'][k]] - for val in items: - if not val: - continue - if new_k not in self.init_data: - self.init_data[new_k] = [] - self.init_data[new_k].append(val) - if 'initial' in kwargs and kwargs['initial']: - for k in kwargs['initial']: - if k not in self.init_data or not self.init_data[k]: - if hasattr(kwargs['initial'], 'getlist'): - items = kwargs['initial'].getlist(k) - else: - items = [kwargs['initial'][k]] - for val in items: - if not val: - continue - if k not in self.init_data: - self.init_data[k] = [] - self.init_data[k].append(val) - self.init_data = MultiValueDict(self.init_data) - super(ManageOldType, self).__init__(*args, **kwargs) - for field in self.TYPES: - if field.key not in self.fields: - continue - self.fields[field.key].choices = field.get_choices( - initial=self.init_data.get(field.key)) - self.fields[field.key].help_text = field.get_help() - - class DocumentGenerationForm(forms.Form): """ Form to generate document by choosing the template diff --git a/ishtar_common/menu_base.py b/ishtar_common/menu_base.py index 7913bd470..13eb46f99 100644 --- a/ishtar_common/menu_base.py +++ b/ishtar_common/menu_base.py @@ -23,13 +23,19 @@ from ishtar_common.models import get_current_profile class SectionItem: def __init__(self, idx, label, childs=[], profile_restriction=None, css=''): self.idx = idx - self.label = label + self._label = label self.childs = childs self.available = False self.items = {} self.profile_restriction = profile_restriction self.css = css + @property + def label(self): + if callable(self._label): + return self._label() + return self._label + def check_profile_restriction(self): if self.profile_restriction: profile = get_current_profile() diff --git a/ishtar_common/migrations/0028_auto_20180214_1144.py b/ishtar_common/migrations/0028_auto_20180214_1144.py new file mode 100644 index 000000000..fdfd636f5 --- /dev/null +++ b/ishtar_common/migrations/0028_auto_20180214_1144.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-02-14 11:44 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ishtar_common', '0027_auto_20180205_1726'), + ] + + operations = [ + migrations.RemoveField( + model_name='ishtarsiteprofile', + name='base_color', + ), + migrations.RemoveField( + model_name='ishtarsiteprofile', + name='context_record_color', + ), + migrations.RemoveField( + model_name='ishtarsiteprofile', + name='files_color', + ), + migrations.RemoveField( + model_name='ishtarsiteprofile', + name='find_color', + ), + migrations.RemoveField( + model_name='ishtarsiteprofile', + name='mapping_color', + ), + migrations.RemoveField( + model_name='ishtarsiteprofile', + name='warehouse_color', + ), + migrations.AddField( + model_name='ishtarsiteprofile', + name='archaeological_site', + field=models.BooleanField(default=False, verbose_name='Archaeological site module'), + ), + migrations.AddField( + model_name='ishtarsiteprofile', + name='archaeological_site_label', + field=models.CharField(choices=[(b'site', 'Site'), (b'entity', 'Archaeological entity')], default=b'site', max_length=200, verbose_name='Archaeological site type'), + ), + ] diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 674e42538..74b2f4221 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -1464,6 +1464,7 @@ CURRENCY = ((u"€", _(u"Euro")), (u"$", _(u"US dollar"))) FIND_INDEX_SOURCE = ((u"O", _(u"Operations")), (u"CR", _(u"Context records"))) +SITE_LABELS = [('site', _(u"Site")), ('entity', _(u"Archaeological entity"))] class IshtarSiteProfile(models.Model, Cached): @@ -1471,18 +1472,16 @@ class IshtarSiteProfile(models.Model, Cached): label = models.TextField(_(u"Name")) slug = models.SlugField(_(u"Slug"), unique=True) description = models.TextField(_(u"Description"), null=True, blank=True) - base_color = models.CharField( - _(u"CSS color code for base module"), - default=u'rgba(0, 0, 0, 0)', max_length=200) files = models.BooleanField(_(u"Files module"), default=False) - files_color = models.CharField( - _(u"CSS color code for files module"), - default=u'rgba(0, 32, 210, 0.1)', max_length=200) + archaeological_site = models.BooleanField( + _(u"Archaeological site module"), default=False) + archaeological_site_label = models.CharField( + _(u"Archaeological site type"), max_length=200, + choices=SITE_LABELS, + default='site' + ) context_record = models.BooleanField(_(u"Context records module"), default=False) - context_record_color = models.CharField( - _(u"CSS color code for context record module"), - default=u'rgba(210,200,0,0.2)', max_length=200) find = models.BooleanField(_(u"Finds module"), default=False, help_text=_(u"Need context records module")) find_index = models.CharField( @@ -1490,21 +1489,12 @@ class IshtarSiteProfile(models.Model, Cached): choices=FIND_INDEX_SOURCE, help_text=_(u"To prevent irrelevant indexes, change this parameter " u"only if there is no find in the database")) - find_color = models.CharField( - _(u"CSS color code for find module"), - default=u'rgba(210,0,0,0.15)', max_length=200) warehouse = models.BooleanField( _(u"Warehouses module"), default=False, help_text=_(u"Need finds module")) - warehouse_color = models.CharField( - _(u"CSS code for warehouse module"), default=u'rgba(10,20,200,0.15)', - max_length=200) preservation = models.BooleanField(_(u"Preservation module"), default=False) mapping = models.BooleanField(_(u"Mapping module"), default=False) - mapping_color = models.CharField( - _(u"CSS code for mapping module"), default=u'rgba(72, 236, 0, 0.15)', - max_length=200) homepage = models.TextField( _(u"Home page"), null=True, blank=True, help_text=_(u"Homepage of Ishtar - if not defined a default homepage " @@ -1579,18 +1569,26 @@ class IshtarSiteProfile(models.Model, Cached): def __unicode__(self): return unicode(self.label) - def get_raw_css(self): - css = '' - for attr, css_name in (('base_color', 'operation'), - ('files_color', 'file'), - ('context_record_color', 'context-record'), - ('find_color', 'find'), - ('warehouse_color', 'warehouse')): - css += ''' -.menu-%s{ - background-color: %s; -}''' % (css_name, getattr(self, attr)) - return css + @classmethod + def get_current_profile(cls, force=False): + cache_key, value = get_cache(cls, ['is-current-profile']) + if value and not force: + return value + q = cls.objects.filter(active=True) + if not q.count(): + obj = cls.objects.create( + label="Default profile", slug='default', active=True) + else: + obj = q.all()[0] + cache.set(cache_key, obj, settings.CACHE_TIMEOUT) + return obj + + @classmethod + def get_default_site_label(cls): + return cls.get_current_profile().get_site_label() + + def get_site_label(self): + return unicode(dict(SITE_LABELS)[self.archaeological_site_label]) def save(self, *args, **kwargs): raw = False @@ -1621,17 +1619,7 @@ class IshtarSiteProfile(models.Model, Cached): def get_current_profile(force=False): - cache_key, value = get_cache(IshtarSiteProfile, ['is-current-profile']) - if value and not force: - return value - q = IshtarSiteProfile.objects.filter(active=True) - if not q.count(): - obj = IshtarSiteProfile.objects.create( - label="Default profile", slug='default', active=True) - else: - obj = q.all()[0] - cache.set(cache_key, obj, settings.CACHE_TIMEOUT) - return obj + return IshtarSiteProfile.get_current_profile(force=force) def cached_site_changed(sender, **kwargs): diff --git a/ishtar_common/templates/base.html b/ishtar_common/templates/base.html index 8608448e7..0b385267d 100644 --- a/ishtar_common/templates/base.html +++ b/ishtar_common/templates/base.html @@ -57,8 +57,6 @@ {% endcompress %} {% block extra_head %} {% endblock %} - {% comment %}{% if raw_css %}<style media="screen" type="text/css"> - {{raw_css |safe}}</style>{% endif %}{% endcomment %} </head> <body{% if current_theme%} id='{{current_theme}}'{%endif%}> {% include "navbar.html" %} diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py index e82b32671..114b47712 100644 --- a/ishtar_common/wizards.py +++ b/ishtar_common/wizards.py @@ -139,6 +139,9 @@ class Wizard(NamedUrlWizardView): saved_args = {} # argument to pass on object save + def get_label(self): + return self.label + ''' # buggy and unecessary... def __init__(self, *args, **kwargs): @@ -232,7 +235,7 @@ class Wizard(NamedUrlWizardView): step = self.steps.first current_step = self.steps.current dct = {'current_step_label': self.form_list[current_step].form_label, - 'wizard_label': self.label, + 'wizard_label': self.get_label(), 'current_object': self.get_current_object(), 'is_search': bool( [k for k in self.main_item_select_keys @@ -1216,13 +1219,16 @@ class SearchWizard(NamedUrlWizardView): templates = ['ishtar/wizard/search.html'] return templates + def get_label(self): + return self.label + def get_context_data(self, form, **kwargs): context = super(SearchWizard, self).get_context_data(form) self.request.session['CURRENT_ACTION'] = self.get_wizard_name() current_step = self.steps.current context.update({'current_step': self.form_list[current_step], 'is_search': True, - 'wizard_label': self.label}) + 'wizard_label': self.get_label()}) return context |