diff options
| author | Étienne Loks <etienne.loks@proxience.com> | 2015-08-19 15:12:43 +0200 | 
|---|---|---|
| committer | Étienne Loks <etienne.loks@proxience.com> | 2015-08-19 15:12:43 +0200 | 
| commit | ab53d8cfdcfbbaff8cc5b6bc0e44ee923485d9bb (patch) | |
| tree | 840ab617f2927fec8143f6005cfd2d498d1c738f /ishtar_common/views.py | |
| parent | b4a8dcb2836c202edf250c9953327a9ca5280004 (diff) | |
| download | Ishtar-ab53d8cfdcfbbaff8cc5b6bc0e44ee923485d9bb.tar.bz2 Ishtar-ab53d8cfdcfbbaff8cc5b6bc0e44ee923485d9bb.zip | |
Archaeological files: change planning service management
Diffstat (limited to 'ishtar_common/views.py')
| -rw-r--r-- | ishtar_common/views.py | 496 | 
1 files changed, 278 insertions, 218 deletions
| diff --git a/ishtar_common/views.py b/ishtar_common/views.py index 0058821b2..fc8151d8d 100644 --- a/ishtar_common/views.py +++ b/ishtar_common/views.py @@ -19,14 +19,14 @@  from tidylib import tidy_document as tidy -import re  import csv -import json +import cStringIO as StringIO  import datetime +import ho.pisa as pisa +import json  import optparse -import cStringIO as StringIO +import re  from tempfile import NamedTemporaryFile -import ho.pisa as pisa  import unicodedata  from extra_views import ModelFormSetView @@ -34,17 +34,17 @@ from extra_views import ModelFormSetView  from django.conf import settings  from django.contrib.auth import logout  from django.contrib.auth.decorators import login_required -from django.core import serializers  from django.core.exceptions import ObjectDoesNotExist  from django.core.urlresolvers import reverse, NoReverseMatch -from django.db.models import Q, F, ImageField -from django.forms.models import model_to_dict, modelformset_factory -from django.http import HttpResponse, Http404, HttpResponseRedirect +from django.db.models import Q, ImageField +from django.forms.models import modelformset_factory +from django.http import HttpResponse, Http404, HttpResponseRedirect, \ +    HttpResponseBadRequest  from django.shortcuts import render_to_response, redirect  from django.template import RequestContext, loader  from django.utils.decorators import method_decorator  from django.utils.translation import ugettext, ugettext_lazy as _ -from django.views.generic import ListView, UpdateView, CreateView +from django.views.generic import ListView, UpdateView  from django.views.generic.edit import CreateView, DeleteView  from xhtml2odt import xhtml2odt @@ -56,11 +56,14 @@ from archaeological_operations.forms import DashboardForm as DashboardFormOpe  from ishtar_common.forms import FinalForm, FinalDeleteForm  from ishtar_common import forms_common as forms  from ishtar_common import wizards +from ishtar_common.models import HistoryError +  import models -CSV_OPTIONS = {'delimiter':';', 'quotechar':'"', 'quoting':csv.QUOTE_ALL} +CSV_OPTIONS = {'delimiter': ';', 'quotechar': '"', 'quoting': csv.QUOTE_ALL}  ENCODING = settings.ENCODING or 'utf-8' +  def index(request):      """      Main page @@ -68,69 +71,70 @@ def index(request):      dct = {}      try:          return render_to_response('index.html', dct, -                              context_instance=RequestContext(request)) +                                  context_instance=RequestContext(request))      except NoReverseMatch:          # probably rights exception (rights revoked)          logout(request)          return render_to_response('index.html', dct, -                              context_instance=RequestContext(request)) +                                  context_instance=RequestContext(request)) + +person_search_wizard = wizards.SearchWizard.as_view( +    [('general-person_search', forms.PersonFormSelection)], +    label=_(u"Person search"), +    url_name='person_search',) + +person_creation_wizard = wizards.PersonWizard.as_view( +    [('identity-person_creation', forms.SimplePersonForm), +     ('person_type-person_creation', forms.PersonTypeForm), +     ('final-person_creation', FinalForm)], +    label=_(u"New person"), +    url_name='person_creation') + +person_modification_wizard = wizards.PersonModifWizard.as_view( +    [('selec-person_modification', forms.PersonFormSelection), +     ('identity-person_modification', forms.SimplePersonForm), +     ('person_type-person_creation', forms.PersonTypeForm), +     ('final-person_modification', FinalForm)], +    label=_(u"Person modification"), +    url_name='person_modification') + +person_deletion_wizard = wizards.PersonDeletionWizard.as_view( +    [('selec-person_deletion', forms.PersonFormSelection), +     ('final-person_deletion', FinalDeleteForm)], +    label=_(u"Person deletion"), +    url_name='person_deletion',) + +organization_search_wizard = wizards.SearchWizard.as_view( +    [('general-organization_search', forms.OrganizationFormSelection)], +    label=_(u"Organization search"), +    url_name='organization_search',) + +organization_creation_wizard = wizards.OrganizationWizard.as_view( +    [('identity-organization_creation', forms.OrganizationForm), +     ('final-organization_creation', FinalForm)], +    label=_(u"New organization"), +    url_name='organization_creation') + +organization_modification_wizard = wizards.OrganizationModifWizard.as_view( +    [('selec-organization_modification', forms.OrganizationFormSelection), +     ('identity-organization_modification', forms.OrganizationForm), +     ('final-organization_modification', FinalForm)], +    label=_(u"Organization modification"), +    url_name='organization_modification') + +organization_deletion_wizard = wizards.OrganizationDeletionWizard.as_view( +    [('selec-organization_deletion', forms.OrganizationFormSelection), +     ('final-organization_deletion', FinalDeleteForm)], +    label=_(u"Organization deletion"), +    url_name='organization_deletion',) + +account_management_wizard = wizards.AccountWizard.as_view( +    [('selec-account_management', forms.PersonFormSelection), +     ('account-account_management', forms.AccountForm), +     ('final-account_management', forms.FinalAccountForm)], +    label=_(u"Account management"), +    url_name='account_management',) -person_search_wizard = wizards.SearchWizard.as_view([ -                        ('general-person_search', forms.PersonFormSelection)], -                        label=_(u"Person search"), -                        url_name='person_search',) - -person_creation_wizard = wizards.PersonWizard.as_view([ -                        ('identity-person_creation', forms.SimplePersonForm), -                        ('person_type-person_creation', forms.PersonTypeForm), -                        ('final-person_creation', FinalForm)], -                         label=_(u"New person"), -                         url_name='person_creation') - -person_modification_wizard = wizards.PersonModifWizard.as_view([ -                      ('selec-person_modification', forms.PersonFormSelection), -                      ('identity-person_modification', forms.SimplePersonForm), -                      ('person_type-person_creation', forms.PersonTypeForm), -                      ('final-person_modification', FinalForm)], -                       label=_(u"Person modification"), -                       url_name='person_modification') - -person_deletion_wizard = wizards.PersonDeletionWizard.as_view([ -          ('selec-person_deletion', forms.PersonFormSelection), -          ('final-person_deletion', FinalDeleteForm)], -                      label=_(u"Person deletion"), -                      url_name='person_deletion',) - -organization_search_wizard = wizards.SearchWizard.as_view([ -        ('general-organization_search', forms.OrganizationFormSelection)], -        label=_(u"Organization search"), -        url_name='organization_search',) - -organization_creation_wizard = wizards.OrganizationWizard.as_view([ -                    ('identity-organization_creation', forms.OrganizationForm), -                    ('final-organization_creation', FinalForm)], -                     label=_(u"New organization"), -                     url_name='organization_creation') - -organization_modification_wizard = wizards.OrganizationModifWizard.as_view([ -          ('selec-organization_modification', forms.OrganizationFormSelection), -          ('identity-organization_modification', forms.OrganizationForm), -          ('final-organization_modification', FinalForm)], -                       label=_(u"Organization modification"), -                       url_name='organization_modification') - -organization_deletion_wizard = wizards.OrganizationDeletionWizard.as_view([ -          ('selec-organization_deletion', forms.OrganizationFormSelection), -          ('final-organization_deletion', FinalDeleteForm)], -                      label=_(u"Organization deletion"), -                      url_name='organization_deletion',) - -account_management_wizard = wizards.AccountWizard.as_view([ -                    ('selec-account_management', forms.PersonFormSelection), -                    ('account-account_management', forms.AccountForm), -                    ('final-account_management', forms.FinalAccountForm)], -                     label=_(u"Account management"), -                     url_name='account_management',)  def update_current_item(request):      if not request.is_ajax() and not request.method == 'POST': @@ -139,15 +143,18 @@ def update_current_item(request):          request.session[request.POST['item']] = request.POST['value']      return HttpResponse('ok') +  def check_permission(request, action_slug, obj_id=None):      if action_slug not in menu.items: -        #! TODO +        # TODO          return True      if obj_id:          return menu.items[action_slug].is_available(request.user, obj_id)      return menu.items[action_slug].can_be_available(request.user) -def autocomplete_person(request, person_types=None, is_ishtar_user=None): + +def autocomplete_person(request, person_types=None, attached_to=None, +                        is_ishtar_user=None):      if not request.user.has_perm('ishtar_common.view_person', models.Person) and \         not request.user.has_perm('ishtar_common.view_own_person', models.Person) \         and not request.user.ishtaruser.has_right('person_search'): @@ -162,9 +169,13 @@ def autocomplete_person(request, person_types=None, is_ishtar_user=None):          return HttpResponseBadRequest()      query = Q()      for q in q.split(' '): -        query = query & (Q(name__icontains=q) | Q(surname__icontains=q) | \ -                 Q(email__icontains=q) | Q(attached_to__name__icontains=q)) -    if person_types and unicode(person_types) !=  '0': +        query = query & (Q(name__icontains=q) | Q(surname__icontains=q) | +                         Q(email__icontains=q) | +                         Q(attached_to__name__icontains=q)) +    if attached_to: +        query = query & Q(attached_to__pk__in=attached_to.split('_')) + +    if person_types and unicode(person_types) != '0':          try:              typs = [int(tp) for tp in person_types.split('_') if tp]              typ = models.PersonType.objects.filter(pk__in=typs).all() @@ -175,48 +186,51 @@ def autocomplete_person(request, person_types=None, is_ishtar_user=None):          query = query & Q(ishtaruser__isnull=False)      limit = 20      persons = models.Person.objects.filter(query)[:limit] -    data = json.dumps([{'id':person.pk, 'value':unicode(person)} -                                for person in persons if person]) +    data = json.dumps([{'id': person.pk, 'value': unicode(person)} +                       for person in persons if person])      return HttpResponse(data, mimetype='text/plain') +  def autocomplete_department(request):      if not request.GET.get('term'):          return HttpResponse(mimetype='text/plain')      q = request.GET.get('term') -    q = unicodedata.normalize("NFKD", q).encode('ascii','ignore') +    q = unicodedata.normalize("NFKD", q).encode('ascii', 'ignore')      query = Q()      for q in q.split(' '):          extra = (Q(label__icontains=q) | Q(number__istartswith=q))          query = query & extra      limit = 20      departments = models.Department.objects.filter(query)[:limit] -    data = json.dumps([{'id':department.pk, 'value':unicode(department)} -                                          for department in departments]) +    data = json.dumps([{'id': department.pk, 'value': unicode(department)} +                       for department in departments])      return HttpResponse(data, mimetype='text/plain') +  def autocomplete_town(request):      if not request.GET.get('term'):          return HttpResponse(mimetype='text/plain')      q = request.GET.get('term') -    q = unicodedata.normalize("NFKD", q).encode('ascii','ignore') +    q = unicodedata.normalize("NFKD", q).encode('ascii', 'ignore')      query = Q()      for q in q.split(' '):          extra = Q(name__icontains=q)          if settings.COUNTRY == 'fr': -            extra = (extra | Q(numero_insee__istartswith=q) | \ -                    Q(departement__label__istartswith=q)) +            extra = (extra | Q(numero_insee__istartswith=q) | +                     Q(departement__label__istartswith=q))          query = query & extra      limit = 20      towns = models.Town.objects.filter(query)[:limit] -    data = json.dumps([{'id':town.pk, 'value':unicode(town)} -                                          for town in towns]) +    data = json.dumps([{'id': town.pk, 'value': unicode(town)} +                       for town in towns])      return HttpResponse(data, mimetype='text/plain') +  def autocomplete_advanced_town(request, department_id=None, state_id=None):      if not request.GET.get('term'):          return HttpResponse(mimetype='text/plain')      q = request.GET.get('term') -    q = unicodedata.normalize("NFKD", q).encode('ascii','ignore') +    q = unicodedata.normalize("NFKD", q).encode('ascii', 'ignore')      query = Q()      for q in q.split(' '):          extra = Q(name__icontains=q) @@ -236,25 +250,24 @@ def autocomplete_advanced_town(request, department_id=None, state_id=None):          val = town.name          if hasattr(town, 'numero_insee'):              val += " (%s)" % town.numero_insee -        result.append({'id':town.pk, 'value':val}) +        result.append({'id': town.pk, 'value': val})      data = json.dumps(result)      return HttpResponse(data, mimetype='text/plain') +  def department_by_state(request, state_id=''):      if not state_id:          data = []      else:          departments = models.Department.objects.filter(state__number=state_id) -        data = json.dumps([{'id':department.pk, 'number':department.number, -                            'value':unicode(department)} -                                          for department in departments]) +        data = json.dumps([{'id': department.pk, 'number': department.number, +                            'value': unicode(department)} +                           for department in departments])      return HttpResponse(data, mimetype='text/plain') -from types import NoneType -  def format_val(val): -    if type(val) == NoneType: +    if val is None:          return u""      if type(val) == bool:          if val: @@ -267,33 +280,33 @@ HIERARCHIC_LEVELS = 5  HIERARCHIC_FIELDS = ['periods', 'period', 'unit', 'material_type',                       'conservatory_state']  PRIVATE_FIELDS = ('id', 'history_modifier', 'order') + +  def get_item(model, func_name, default_name, extra_request_keys=[], -            base_request={}, bool_fields=[], reversed_bool_fields=[], -            dated_fields=[], associated_models=[], relative_session_names={}, -            specific_perms=[]): +             base_request={}, bool_fields=[], reversed_bool_fields=[], +             dated_fields=[], associated_models=[], relative_session_names={}, +             specific_perms=[]):      """      Generic treatment of tables      """      def func(request, data_type='json', full=False, **dct):          # check rights -        own = True # more restrictive by default +        own = True  # more restrictive by default          allowed = False          for perm, lbl in model._meta.permissions:              # if not specific any perm is relevant (read right)              if specific_perms and perm not in specific_perms:                  continue              if request.user.has_perm(model._meta.app_label + '.' + perm) \ -             or (request.user.is_authenticated() -                 and request.user.ishtaruser.has_right(perm)): +                    or (request.user.is_authenticated() +                        and request.user.ishtaruser.has_right(perm)):                  allowed = True                  if "_own_" not in perm:                      own = False -                    break # max right reach -        EMPTY, mimetype = '', 'text/plain' +                    break  # max right reach +        EMPTY = ''          if 'type' in dct:              data_type = dct.pop('type') -            if data_type == 'csv': -               mimetype = 'text/csv'          if not data_type:              EMPTY = '[]'              data_type = 'json' @@ -301,18 +314,23 @@ def get_item(model, func_name, default_name, extra_request_keys=[],              return HttpResponse(EMPTY, mimetype='text/plain')          fields = [model._meta.get_field_by_name(k)[0]                    for k in model._meta.get_all_field_names()] -        request_keys = dict([(field.name, -            field.name + (hasattr(field, 'rel') and field.rel and '__pk' or '')) -                                for field in fields]) +        request_keys = dict([ +            (field.name, +             field.name + (hasattr(field, 'rel') and field.rel and '__pk' +                           or '')) +            for field in fields])          for associated_model, key in associated_models: -            associated_fields = [associated_model._meta.get_field_by_name(k)[0] -                          for k in associated_model._meta.get_all_field_names()] -            request_keys.update(dict([(key + "__" + field.name, -                key + "__" + field.name + (hasattr(field, 'rel') and -                                           field.rel and '__pk' or '')) -                                            for field in associated_fields])) +            associated_fields = [ +                associated_model._meta.get_field_by_name(k)[0] +                for k in associated_model._meta.get_all_field_names()] +            request_keys.update( +                dict([(key + "__" + field.name, +                       key + "__" + field.name + +                       (hasattr(field, 'rel') and field.rel and '__pk' or '')) +                      for field in associated_fields]))          request_keys.update(extra_request_keys) -        request_items = request.method == 'POST' and request.POST or request.GET +        request_items = request.method == 'POST' and request.POST \ +            or request.GET          dct = base_request.copy()          and_reqs, or_reqs = [], []          try: @@ -327,14 +345,15 @@ def get_item(model, func_name, default_name, extra_request_keys=[],          if not dct and 'submited' not in request_items:              if default_name in request.session and \                 request.session[default_name]: -                dct = {"pk":request.session[default_name]} +                dct = {"pk": request.session[default_name]}              else:                  for name in relative_session_names.keys():                      if name in request.session and request.session[name]:                          k = relative_session_names[name] -                        dct = {k:request.session[name]} +                        dct = {k: request.session[name]}                          break -            if (not dct or data_type == 'csv') and func_name in request.session: +            if (not dct or data_type == 'csv') \ +                    and func_name in request.session:                  dct = request.session[func_name]          else:              request.session[func_name] = dct @@ -351,7 +370,8 @@ def get_item(model, func_name, default_name, extra_request_keys=[],                      if k.endswith('__isnull') and \                         isinstance(c_field, ImageField):                          if dct[k]: -                            or_reqs.append((k, {k.split('__')[0]+'__exact':''})) +                            or_reqs.append( +                                (k, {k.split('__')[0]+'__exact': ''}))                          else:                              dct[k.split('__')[0]+'__regex'] = '.{1}.*'          for k in dated_fields: @@ -362,8 +382,8 @@ def get_item(model, func_name, default_name, extra_request_keys=[],                      items = dct[k].split('/')                      assert len(items) == 3                      dct[k] = datetime.date(*map(lambda x: int(x), -                                                reversed(items)) -                                            ).strftime('%Y-%m-%d') +                                                reversed(items)))\ +                                     .strftime('%Y-%m-%d')                  except AssertionError:                      dct.pop(k)          # manage hierarchic conditions @@ -374,18 +394,18 @@ def get_item(model, func_name, default_name, extra_request_keys=[],                      q = None                      for idx, r in enumerate(req):                          if not idx: -                            q = Q(**{r:val}) +                            q = Q(**{r: val})                          else: -                            q = q | Q(**{r:val}) +                            q = q | Q(**{r: val})                      and_reqs.append(q)                      break                  elif req.endswith(k_hr + '__pk'):                      val = dct.pop(req) -                    reqs = Q(**{req:val}) +                    reqs = Q(**{req: val})                      req = req[:-2] + '__'                      for idx in xrange(HIERARCHIC_LEVELS):                          req = req[:-2] + 'parent__pk' -                        q = Q(**{req:val}) +                        q = Q(**{req: val})                          reqs = reqs | q                      and_reqs.append(reqs)                      break @@ -405,7 +425,7 @@ def get_item(model, func_name, default_name, extra_request_keys=[],          # table cols          table_cols = full and [field.name for field in model._meta.fields                                 if field.name not in PRIVATE_FIELDS] \ -                     or model.TABLE_COLS +            or model.TABLE_COLS          # manage sort tables          manual_sort_key = None          order = request_items.get('sord') @@ -461,14 +481,15 @@ def get_item(model, func_name, default_name, extra_request_keys=[],                  for ky in k.split('.'):                      new_vals = []                      for val in vals: -                        if hasattr(val, 'all'): # manage related objects +                        if hasattr(val, 'all'):  # manage related objects                              val = list(val.all())                              for v in val:                                  new_vals.append(getattr(v, ky))                          elif val:                              new_vals.append(getattr(val, ky))                      vals = new_vals -                if vals and hasattr(vals[0], 'all'): # manage last related objects +                # manage last related objects +                if vals and hasattr(vals[0], 'all'):                      new_vals = []                      for val in vals:                          new_vals += list(val.all()) @@ -478,32 +499,33 @@ def get_item(model, func_name, default_name, extra_request_keys=[],          if manual_sort_key:              # +1 because the id is added as a first col              idx_col = table_cols.index(manual_sort_key) + 1 -            datas = sorted(datas, key=lambda x:x[idx_col]) +            datas = sorted(datas, key=lambda x: x[idx_col])              if sign == '-':                  datas = reversed(datas)              datas = list(datas)[start:end] -        link_template = "<a class='display_details' href='#' onclick='load_window(\"%%s\")'>%s</a>" % \ +        link_template = "<a class='display_details' href='#' "\ +                        "onclick='load_window(\"%%s\")'>%s</a>" % \                          (unicode(_("Details")))          if data_type == "json":              rows = []              for data in datas:                  try:                      lnk = link_template % reverse('show-'+default_name, -                                                      args=[data[0], '']) +                                                  args=[data[0], ''])                  except NoReverseMatch:                      print '"show-' + default_name + "\" args (" + \                            unicode(data[0]) + ") url not available"                      lnk = '' -                res = {'id':data[0], 'link':lnk} +                res = {'id': data[0], 'link': lnk}                  for idx, value in enumerate(data[1:]):                      if value:                          res[table_cols[idx].split('.')[-1]] = value                  rows.append(res)              data = json.dumps({ -                "records":items_nb, -                "rows":rows, -                "page":page_nb, -                "total":(items_nb/row_nb + 1) if row_nb else items_nb, +                "records": items_nb, +                "rows": rows, +                "page": page_nb, +                "total": (items_nb/row_nb + 1) if row_nb else items_nb,              })              return HttpResponse(data, mimetype='text/plain')          elif data_type == "csv": @@ -511,7 +533,8 @@ def get_item(model, func_name, default_name, extra_request_keys=[],              n = datetime.datetime.now()              filename = u'%s_%s.csv' % (default_name,                                         n.strftime('%Y%m%d-%H%M%S')) -            response['Content-Disposition'] = 'attachment; filename=%s'%filename +            response['Content-Disposition'] = 'attachment; filename=%s'\ +                                              % filename              writer = csv.writer(response, **CSV_OPTIONS)              col_names = []              for field_name in table_cols: @@ -529,6 +552,7 @@ def get_item(model, func_name, default_name, extra_request_keys=[],      return func +  def show_item(model, name, extra_dct=None):      def func(request, pk, **dct):          try: @@ -540,15 +564,15 @@ def show_item(model, name, extra_dct=None):                                       ).split('/')[:-2]) + u"/"          dct['current_window_url'] = url_name          date = 'date' in dct and dct.pop('date') -        dct['window_id'] = "%s-%d-%s" % (name, item.pk, -                                      datetime.datetime.now().strftime('%M%s')) +        dct['window_id'] = "%s-%d-%s" % ( +            name, item.pk, datetime.datetime.now().strftime('%M%s'))          if hasattr(item, 'history'):              if date:                  try:                      date = datetime.datetime.strptime(date,                                                        '%Y-%m-%dT%H:%M:%S.%f')                      item = item.get_previous(date=date) -                    assert item != None +                    assert item is not None                  except (ValueError, AssertionError):                      return HttpResponse(None, mimetype='text/plain')                  dct['previous'] = item._previous @@ -565,7 +589,6 @@ def show_item(model, name, extra_dct=None):              dct.update(extra_dct(request, item))          context_instance = RequestContext(request)          context_instance.update(dct) -        n = datetime.datetime.now()          filename = ""          if hasattr(item, 'history_object'):              filename = item.history_object.associated_filename @@ -575,9 +598,9 @@ def show_item(model, name, extra_dct=None):              tpl = loader.get_template('ishtar/sheet_%s.html' % name)              content = tpl.render(context_instance)              try: -                tidy_options = {'output-xhtml':1, 'indent':1, -                                'tidy-mark':0, 'doctype':'auto', -                                'add-xml-decl':1, 'wrap':1} +                tidy_options = {'output-xhtml': 1, 'indent': 1, +                                'tidy-mark': 0, 'doctype': 'auto', +                                'add-xml-decl': 1, 'wrap': 1}                  html, errors = tidy(content, options=tidy_options)                  html = html.encode('utf-8').replace(" ", " ")                  html = re.sub('<pre([^>]*)>\n', '<pre\\1>', html) @@ -602,12 +625,12 @@ def show_item(model, name, extra_dct=None):                  odtfile.open()                  odtfile.import_xhtml(html)                  odtfile = odtfile.save() -            except xhtml2odt.ODTExportError, ex: +            except xhtml2odt.ODTExportError:                  return HttpResponse(content, content_type="application/xhtml")              response = HttpResponse( -                            mimetype='application/vnd.oasis.opendocument.text') +                mimetype='application/vnd.oasis.opendocument.text')              response['Content-Disposition'] = 'attachment; filename=%s.odt' % \ -                                                                       filename +                                              filename              response.write(odtfile)              return response          elif doc_type == 'pdf': @@ -621,7 +644,7 @@ def show_item(model, name, extra_dct=None):              response = HttpResponse(result.getvalue(),                                      mimetype='application/pdf')              response['Content-Disposition'] = 'attachment; filename=%s.pdf' % \ -                                                                       filename +                                              filename              if not pdf.err:                  return response              return HttpResponse(content, content_type="application/xhtml") @@ -631,6 +654,7 @@ def show_item(model, name, extra_dct=None):              return HttpResponse(content, content_type="application/xhtml")      return func +  def revert_item(model):      def func(request, pk, date, **dct):          try: @@ -642,11 +666,12 @@ def revert_item(model):          return HttpResponse("True", mimetype='text/plain')      return func +  def autocomplete_organization(request, orga_type=None):      if (not request.user.has_perm('ishtar_common.view_organization', -                                 models.Organization) and \ -       not request.user.has_perm('ishtar_common.view_own_organization', -                                 models.Organization) +        models.Organization) and +        not request.user.has_perm('ishtar_common.view_own_organization', +                                  models.Organization)         and not request.user.ishtaruser.has_right('person_search')):          return HttpResponse(mimetype='text/plain')      if not request.GET.get('term'): @@ -665,14 +690,15 @@ def autocomplete_organization(request, orga_type=None):              pass      limit = 15      organizations = models.Organization.objects.filter(query)[:limit] -    data = json.dumps([{'id':org.pk, 'value':unicode(org)} -                                          for org in organizations]) +    data = json.dumps([{'id': org.pk, 'value': unicode(org)} +                       for org in organizations])      return HttpResponse(data, mimetype='text/plain') +  def autocomplete_author(request):      if not request.user.has_perm('ishtar_common.view_author', models.Author)\         and not request.user.has_perm('ishtar_common.view_own_author', -                                     models.Author) : +                                     models.Author):          return HttpResponse(mimetype='text/plain')      if not request.GET.get('term'):          return HttpResponse(mimetype='text/plain') @@ -680,23 +706,24 @@ def autocomplete_author(request):      query = Q()      for q in q.split(' '):          extra = Q(person__name__icontains=q) | \ -                Q(person__surname__icontains=q) | \ -                Q(person__email__icontains=q) | \ -                Q(author_type__label__icontains=q) +            Q(person__surname__icontains=q) | \ +            Q(person__email__icontains=q) | \ +            Q(author_type__label__icontains=q)          query = query & extra      limit = 15      authors = models.Author.objects.filter(query)[:limit] -    data = json.dumps([{'id':author.pk, 'value':unicode(author)} -                                          for author in authors]) +    data = json.dumps([{'id': author.pk, 'value': unicode(author)} +                       for author in authors])      return HttpResponse(data, mimetype='text/plain') +  def new_item(model, frm):      def func(request, parent_name, limits=''):          model_name = model._meta.object_name          if not check_permission(request, 'add_'+model_name.lower()):              not_permitted_msg = ugettext(u"Operation not permitted.")              return HttpResponse(not_permitted_msg) -        dct = {'title':unicode(_(u'New %s' % model_name.lower()))} +        dct = {'title': unicode(_(u'New %s' % model_name.lower()))}          if request.method == 'POST':              dct['form'] = frm(request.POST, limits=limits)              if dct['form'].is_valid(): @@ -708,8 +735,9 @@ def new_item(model, frm):                  if dct['parent_pk'] and '_select_' in dct['parent_pk']:                      parents = dct['parent_pk'].split('_')                      dct['parent_pk'] = "_".join([parents[0]] + parents[2:]) -                return render_to_response('window.html', dct, -                                  context_instance=RequestContext(request)) +                return render_to_response( +                    'window.html', dct, +                    context_instance=RequestContext(request))          else:              dct['form'] = frm(limits=limits)          return render_to_response('window.html', dct, @@ -717,24 +745,28 @@ def new_item(model, frm):      return func  new_person = new_item(models.Person, forms.PersonForm) +new_person_noorga = new_item(models.Person, forms.NoOrgaPersonForm)  new_organization = new_item(models.Organization, forms.OrganizationForm)  show_organization = show_item(models.Organization, 'organization') -get_organization = get_item(models.Organization, -        'get_organization', 'organization', -      extra_request_keys={ -                  'name':'name__icontains', -                  'organization_type':'organization_type__pk__in', -                  },) +get_organization = get_item( +    models.Organization, +    'get_organization', 'organization', +    extra_request_keys={ +        'name': 'name__icontains', +        'organization_type': 'organization_type__pk__in', +    })  new_author = new_item(models.Author, forms.AuthorForm)  show_person = show_item(models.Person, 'person') -get_person = get_item(models.Person, -        'get_person', 'person', -      extra_request_keys={ -                  'name':'name__icontains', -                  'surname':'surname__icontains', -                  'attached_to':'attached_to__pk', -                  'person_types':'person_types__pk__in', -                  },) +get_person = get_item( +    models.Person, +    'get_person', 'person', +    extra_request_keys={ +        'name': 'name__icontains', +        'surname': 'surname__icontains', +        'attached_to': 'attached_to__pk', +        'person_types': 'person_types__pk__in', +    }) +  def action(request, action_slug, obj_id=None, *args, **kwargs):      """ @@ -744,7 +776,6 @@ def action(request, action_slug, obj_id=None, *args, **kwargs):          not_permitted_msg = ugettext(u"Operation not permitted.")          return HttpResponse(not_permitted_msg)      request.session['CURRENT_ACTION'] = action_slug -    associated_wizard = action_slug + '_wizard'      dct = {}      globals_dct = globals()      if action_slug in globals_dct: @@ -752,6 +783,7 @@ def action(request, action_slug, obj_id=None, *args, **kwargs):      return render_to_response('index.html', dct,                                context_instance=RequestContext(request)) +  def dashboard_main(request, dct, obj_id=None, *args, **kwargs):      """      Main dashboard @@ -764,9 +796,9 @@ def dashboard_main(request, dct, obj_id=None, *args, **kwargs):          app_list.append((_(u"Context records"), 'contextrecords'))      if 'archaeological_finds' in settings.INSTALLED_APPS:          app_list.append((_(u"Finds"), 'finds')) -    dct = {'app_list':app_list} +    dct = {'app_list': app_list}      return render_to_response('ishtar/dashboards/dashboard_main.html', dct, -                               context_instance=RequestContext(request)) +                              context_instance=RequestContext(request))  DASHBOARD_FORMS = {}  if 'archaeological_files' in settings.INSTALLED_APPS: @@ -775,20 +807,21 @@ if 'archaeological_files' in settings.INSTALLED_APPS:  DASHBOARD_FORMS['operations'] = DashboardFormOpe +  def dashboard_main_detail(request, item_name):      """      Specific tab of the main dashboard      """      if item_name == 'users': -        dct = {'ishtar_users':models.UserDashboard()} +        dct = {'ishtar_users': models.UserDashboard()}          return render_to_response( -                    'ishtar/dashboards/dashboard_main_detail_users.html', -                            dct, context_instance=RequestContext(request)) +            'ishtar/dashboards/dashboard_main_detail_users.html', +            dct, context_instance=RequestContext(request))      form = None -    slicing, date_source, fltr, show_detail  = 'year', None, {}, False -    if (item_name == 'files' and \ -      'archaeological_files' in settings.INSTALLED_APPS) \ -      or item_name == 'operations': +    slicing, date_source, fltr, show_detail = 'year', None, {}, False +    if (item_name == 'files' and +        'archaeological_files' in settings.INSTALLED_APPS) \ +            or item_name == 'operations':          slicing = 'month'      if item_name in DASHBOARD_FORMS:          if request.method == 'POST': @@ -803,16 +836,16 @@ def dashboard_main_detail(request, item_name):          else:              form = DASHBOARD_FORMS[item_name]()      lbl, dashboard = None, None -    if (item_name == 'files' and \ -      'archaeological_files' in settings.INSTALLED_APPS) \ -      or item_name == 'operations': -        dashboard_kwargs = {'slice':slicing, 'fltr':fltr, -                            'show_detail':show_detail} +    if (item_name == 'files' and +        'archaeological_files' in settings.INSTALLED_APPS) \ +            or item_name == 'operations': +        dashboard_kwargs = {'slice': slicing, 'fltr': fltr, +                            'show_detail': show_detail}          # date_source is only relevant when the form has set one          if date_source:              dashboard_kwargs['date_source'] = date_source      if item_name == 'files' and \ -      'archaeological_files' in settings.INSTALLED_APPS: +            'archaeological_files' in settings.INSTALLED_APPS:          from archaeological_files.models import File          lbl, dashboard = (_(u"Archaeological files"),                            models.Dashboard(File, **dashboard_kwargs)) @@ -821,26 +854,29 @@ def dashboard_main_detail(request, item_name):          lbl, dashboard = (_(u"Operations"),                            models.Dashboard(Operation, **dashboard_kwargs))      if item_name == 'contextrecords' and \ -      'archaeological_context_records' in settings.INSTALLED_APPS: +            'archaeological_context_records' in settings.INSTALLED_APPS:          from archaeological_context_records.models import ContextRecord -        lbl, dashboard = (_(u"Context records"), models.Dashboard(ContextRecord, -                                                    slice=slicing, fltr=fltr)) +        lbl, dashboard = ( +            _(u"Context records"), +            models.Dashboard(ContextRecord, slice=slicing, fltr=fltr))      if item_name == 'finds' and \ -       'archaeological_finds' in settings.INSTALLED_APPS: +            'archaeological_finds' in settings.INSTALLED_APPS:          from archaeological_finds.models import Find          lbl, dashboard = (_(u"Finds"), models.Dashboard(Find, -                                                    slice=slicing, fltr=fltr)) +                                                        slice=slicing, +                                                        fltr=fltr))      if not lbl:          raise Http404 -    dct = {'lbl':lbl, 'dashboard':dashboard, -           'item_name':item_name.replace('-', '_'), +    dct = {'lbl': lbl, 'dashboard': dashboard, +           'item_name': item_name.replace('-', '_'),             'VALUE_QUOTE': '' if slicing == "year" else "'", -           'form':form, 'slicing':slicing} +           'form': form, 'slicing': slicing}      n = datetime.datetime.now()      dct['unique_id'] = dct['item_name'] + "_" + \ -                '%d_%d_%d' % (n.minute, n.second, n.microsecond) +        '%d_%d_%d' % (n.minute, n.second, n.microsecond)      return render_to_response('ishtar/dashboards/dashboard_main_detail.html', -                            dct, context_instance=RequestContext(request)) +                              dct, context_instance=RequestContext(request)) +  def reset_wizards(request):      # dynamicaly execute each reset_wizards of each ishtar app @@ -857,18 +893,21 @@ def reset_wizards(request):      return redirect(reverse('start'))  ITEM_PER_PAGE = 20 + +  def merge_action(model, form, key):      def merge(request, page=1):          current_url = key + '_merge'          if not page:              page = 1          page = int(page) -        FormSet = modelformset_factory(model.merge_candidate.through, -                                 form=form, formset=forms.MergeFormSet ,extra=0) +        FormSet = modelformset_factory( +            model.merge_candidate.through, form=form, +            formset=forms.MergeFormSet, extra=0)          q = model.merge_candidate.through.objects -        context = {'current_url':current_url, -                   'current_page':page, -                   'max_page':q.count()/ITEM_PER_PAGE} +        context = {'current_url': current_url, +                   'current_page': page, +                   'max_page': q.count()/ITEM_PER_PAGE}          if page < context["max_page"]:              context['next_page'] = page + 1          if page > 1: @@ -885,25 +924,32 @@ def merge_action(model, form, key):              context['formset'] = FormSet(request.POST, queryset=queryset)              if context['formset'].is_valid():                  context['formset'].merge() -                return redirect(reverse(current_url, kwargs={'page':page})) +                return redirect(reverse(current_url, kwargs={'page': page}))          else:              context['formset'] = FormSet(queryset=queryset) -        return render_to_response('ishtar/merge_'+key+'.html', context, -                              context_instance=RequestContext(request)) +        return render_to_response( +            'ishtar/merge_'+key+'.html', context, +            context_instance=RequestContext(request))      return merge  person_merge = merge_action(models.Person, forms.MergePersonForm, 'person') -organization_merge = merge_action(models.Organization, forms.MergeOrganizationForm, -                            'organization') +organization_merge = merge_action( +    models.Organization, +    forms.MergeOrganizationForm, +    'organization' +) +  class IshtarMixin(object):      page_name = u"" +      def get_context_data(self, **kwargs):          context = super(IshtarMixin, self).get_context_data(**kwargs)          context['page_name'] = self.page_name          return context +  class LoginRequiredMixin(object):      @method_decorator(login_required)      def dispatch(self, request, *args, **kwargs): @@ -915,12 +961,14 @@ class LoginRequiredMixin(object):          return super(LoginRequiredMixin, self).dispatch(request, *args,                                                          **kwargs) +  class AdminLoginRequiredMixin(LoginRequiredMixin):      def dispatch(self, request, *args, **kwargs):          if not request.user.is_staff:              return redirect(reverse('start')) -        return super(AdminLoginRequiredMixin, self).dispatch(request, *args, -                                                        **kwargs) +        return super(AdminLoginRequiredMixin, self).dispatch( +            request, *args, **kwargs) +  class GlobalVarEdit(IshtarMixin, AdminLoginRequiredMixin, ModelFormSetView):      template_name = 'ishtar/formset.html' @@ -930,6 +978,7 @@ class GlobalVarEdit(IshtarMixin, AdminLoginRequiredMixin, ModelFormSetView):      page_name = _(u"Global variables")      fields = ['slug', 'value', 'description'] +  class NewImportView(IshtarMixin, LoginRequiredMixin, CreateView):      template_name = 'ishtar/form.html'      model = models.Import @@ -944,6 +993,7 @@ class NewImportView(IshtarMixin, LoginRequiredMixin, CreateView):          self.object = form.save(user=user)          return HttpResponseRedirect(self.get_success_url()) +  class ImportListView(IshtarMixin, LoginRequiredMixin, ListView):      template_name = 'ishtar/import_list.html'      model = models.Import @@ -952,8 +1002,8 @@ class ImportListView(IshtarMixin, LoginRequiredMixin, ListView):      def get_queryset(self):          user = models.IshtarUser.objects.get(pk=self.request.user.pk) -        return self.model.objects.filter(user=user).exclude(state='AC' -                                        ).order_by('-creation_date') +        return self.model.objects.filter(user=user).exclude( +            state='AC').order_by('-creation_date')      def post(self, request, *args, **kwargs):          for field in request.POST: @@ -972,7 +1022,7 @@ class ImportListView(IshtarMixin, LoginRequiredMixin, ListView):              action = request.POST[field]              if action == 'D':                  return HttpResponseRedirect(reverse('import_delete', -                                                    kwargs={'pk':imprt.pk})) +                                                    kwargs={'pk': imprt.pk}))              elif action == 'A':                  imprt.initialize()              elif action == 'I': @@ -981,12 +1031,15 @@ class ImportListView(IshtarMixin, LoginRequiredMixin, ListView):                  imprt.archive()          return HttpResponseRedirect(reverse(self.current_url)) +  class ImportOldListView(ImportListView):      current_url = 'old_imports' +      def get_queryset(self):          user = models.IshtarUser.objects.get(pk=self.request.user.pk) -        return self.model.objects.filter(user=user, state='AC' -                                        ).order_by('-creation_date') +        return self.model.objects.filter( +            user=user, state='AC').order_by('-creation_date') +  class ImportLinkView(IshtarMixin, LoginRequiredMixin, ModelFormSetView):      template_name = 'ishtar/formset.html' @@ -996,12 +1049,13 @@ class ImportLinkView(IshtarMixin, LoginRequiredMixin, ModelFormSetView):      form_class = forms.TargetKeyForm      def get_queryset(self): -        return self.model.objects.filter(is_set=False, -                   associated_import=self.kwargs['pk']) +        return self.model.objects.filter( +            is_set=False, associated_import=self.kwargs['pk'])      def get_success_url(self):          return reverse('current_imports') +  class ImportDeleteView(IshtarMixin, LoginRequiredMixin, DeleteView):      template_name = 'ishtar/import_delete.html'      model = models.Import @@ -1010,6 +1064,7 @@ class ImportDeleteView(IshtarMixin, LoginRequiredMixin, DeleteView):      def get_success_url(self):          return reverse('current_imports') +  class PersonCreate(LoginRequiredMixin, CreateView):      model = models.Person      form_class = forms.BasePersonForm @@ -1018,6 +1073,7 @@ class PersonCreate(LoginRequiredMixin, CreateView):      def get_success_url(self):          return reverse('person_edit', args=[self.object.pk]) +  class PersonEdit(LoginRequiredMixin, UpdateView):      model = models.Person      form_class = forms.BasePersonForm @@ -1026,6 +1082,7 @@ class PersonEdit(LoginRequiredMixin, UpdateView):      def get_success_url(self):          return reverse('person_edit', args=[self.object.pk]) +  class OrganizationCreate(LoginRequiredMixin, CreateView):      model = models.Organization      form_class = forms.BaseOrganizationForm @@ -1038,6 +1095,7 @@ class OrganizationCreate(LoginRequiredMixin, CreateView):              kwargs.update({'prefix': self.form_class.form_prefix})          return kwargs +  class OrganizationEdit(LoginRequiredMixin, UpdateView):      model = models.Organization      form_class = forms.BaseOrganizationForm @@ -1049,6 +1107,7 @@ class OrganizationEdit(LoginRequiredMixin, UpdateView):              kwargs.update({'prefix': self.form_class.form_prefix})          return kwargs +  class OrganizationPersonCreate(LoginRequiredMixin, CreateView):      model = models.Person      form_class = forms.BaseOrganizationPersonForm @@ -1064,6 +1123,7 @@ class OrganizationPersonCreate(LoginRequiredMixin, CreateView):      def get_success_url(self):          return reverse('organization_person_edit', args=[self.object.pk]) +  class OrganizationPersonEdit(LoginRequiredMixin, UpdateView):      model = models.Person      form_class = forms.BaseOrganizationPersonForm @@ -1072,7 +1132,7 @@ class OrganizationPersonEdit(LoginRequiredMixin, UpdateView):      def get_context_data(self, *args, **kwargs):          data = super(OrganizationPersonEdit, self).get_context_data(*args, -                                                                      **kwargs) +                                                                    **kwargs)          data['relative_label'] = self.relative_label          return data | 
