diff options
| author | Étienne Loks <etienne.loks@peacefrogs.net> | 2011-06-24 14:37:16 +0200 | 
|---|---|---|
| committer | Étienne Loks <etienne.loks@peacefrogs.net> | 2011-06-24 14:37:16 +0200 | 
| commit | 95773b4ccd0beaa31f76c93a7c9b5e24211401dc (patch) | |
| tree | 6b4fc14f42da9d91ab2bb4b989ffeeb42947392f /ishtar/ishtar_base/views.py | |
| parent | 7af17b15fa5cb03050b0fe90d38ab9f37dc51e74 (diff) | |
| download | Ishtar-95773b4ccd0beaa31f76c93a7c9b5e24211401dc.tar.bz2 Ishtar-95773b4ccd0beaa31f76c93a7c9b5e24211401dc.zip | |
Sources creation for Operation (refs #497) - restructuration (refs #57)
Diffstat (limited to 'ishtar/ishtar_base/views.py')
| -rw-r--r-- | ishtar/ishtar_base/views.py | 581 | 
1 files changed, 581 insertions, 0 deletions
| diff --git a/ishtar/ishtar_base/views.py b/ishtar/ishtar_base/views.py new file mode 100644 index 000000000..9e998c2dc --- /dev/null +++ b/ishtar/ishtar_base/views.py @@ -0,0 +1,581 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2010-2011  Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +""" +Furnitures views +""" + +import tidy +import re +import csv +import json +import datetime +import optparse +import cStringIO as StringIO +from tempfile import NamedTemporaryFile +import ho.pisa as pisa + +from django.http import HttpResponse, Http404 +from django.template import RequestContext, loader +from django.template.defaultfilters import slugify +from django.shortcuts import render_to_response, redirect +from django.utils.translation import ugettext, ugettext_lazy as _ +from django.core.exceptions import ObjectDoesNotExist +from django.core.urlresolvers import reverse, NoReverseMatch +from django.db.models import Q +from django.core import serializers + +from ishtar import settings +if settings.XHTML2ODT_PATH: +    import sys +    sys.path.append(settings.XHTML2ODT_PATH) +    from xhtml2odt import xhtml2odt + +from menus import menu +import forms_main as ishtar_forms +import models + +CSV_OPTIONS = {'delimiter':';', 'quotechar':'"', 'quoting':csv.QUOTE_ALL} +ENCODING = settings.ENCODING or 'utf-8' + +def index(request): +    """ +    Main page +    """ +    dct = {} +    return render_to_response('index.html', dct, +                              context_instance=RequestContext(request)) + +def update_current_item(request): +    if not request.is_ajax() and not request.method == 'POST': +        raise Http404 +    if 'value' in request.POST and 'item' in request.POST: +        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 +        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_type=None): +    if not request.user.has_perm('ishtar_base.view_person', models.Person) and \ +       not request.user.has_perm('ishtar_base.view_own_person', models.Person) : +        return HttpResponse(mimetype='text/plain') +    if not request.GET.get('term'): +        return HttpResponse(mimetype='text/plain') +    q = request.GET.get('term') +    limit = request.GET.get('limit', 20) +    try: +        limit = int(limit) +    except ValueError: +        return HttpResponseBadRequest() +    query = Q() +    for q in q.split(' '): +        query = query & (Q(name__icontains=q) | Q(surname__icontains=q) | \ +                         Q(email__icontains=q)) +    if person_type: +        try: +            typs = [int(tp) for tp in person_type.split('_') if tp] +            typ = models.PersonType.objects.filter(pk__in=typs).all() +            query = query & Q(person_type__in=typ) +        except (ValueError, ObjectDoesNotExist): +            pass +    limit = 20 +    persons = models.Person.objects.filter(query)[:limit] +    data = json.dumps([{'id':person.pk, 'value':unicode(person)} +                                for person in persons if person]) +    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') +    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)) +        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]) +    return HttpResponse(data, mimetype='text/plain') + +def autocomplete_file(request): +    if not request.user.has_perm('ishtar_base.view_file', models.File) and \ +       not request.user.has_perm('ishtar_base.view_own_file', models.File) : +        return HttpResponse(mimetype='text/plain') +    if not request.GET.get('term'): +        return HttpResponse(mimetype='text/plain') +    q = request.GET.get('term') +    query = Q() +    for q in q.split(' '): +        extra = Q(internal_reference__icontains=q) | \ +                Q(towns__name__icontains=q) +        try: +            value = int(q) +            extra = extra | Q(year=q) | Q(numeric_reference=q) +        except ValueError: +            pass +        query = query & extra +    limit = 20 +    files = models.File.objects.filter(query)[:limit] +    data = json.dumps([{'id':file.pk, 'value':unicode(file)} +                                          for file in files]) +    return HttpResponse(data, mimetype='text/plain') + +from types import NoneType + +def format_val(val): +    if type(val) == NoneType: +        return u"" +    if type(val) == bool: +        if val: +            return unicode(_(u"True")) +        else: +            return unicode(_(u"False")) +    return unicode(val) + +HIERARCHIC_LEVELS = 5 +HIERARCHIC_FIELDS = ['period', 'unit', 'material'] +def get_item(model, func_name, default_name, extra_request_keys=[], +                                                    bool_fields=[]): +    """ +    Generic treatment of tables +    """ +    def func(request, data_type='json', **dct): +        if 'type' in dct: +            data_type = dct.pop('type') +        if not data_type: +            data_type = 'json' +        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.update(extra_request_keys) +        request_items = request.method == 'POST' and request.POST or request.GET +        dct = {} +        try: +            old = 'old' in request_items and int(request_items['old']) +        except ValueError: +            return HttpResponse(None, mimetype='text/plain') +        for k in request_keys: +            q = request_items.get(k) +            if not q: +                continue +            dct[request_keys[k]] = q +        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]} +            if (not dct or data_type == 'csv') and func_name in request.session: +                dct = request.session[func_name] +        else: +            request.session[func_name] = dct +        for k in bool_fields: +            if k in dct: +                if dct[k] == u"1": +                    dct.pop(k) +                else: +                    dct[k] = dct[k] == u"2" and True or False +        # manage hierarchic conditions +        or_reqs = [] +        for k in HIERARCHIC_FIELDS: +            for req in dct.copy(): +                if req.endswith(k + '__pk'): +                    val = dct.pop(req) +                    reqs = Q(**{req:val}) +                    req = req[:-2] + '__' +                    for idx in xrange(HIERARCHIC_LEVELS): +                        req = req[:-2] + 'parent__pk' +                        q = Q(**{req:val}) +                        reqs = reqs | q +                    or_reqs.append(reqs) +        query = Q(**dct) +        for or_req in or_reqs: +            query = query & or_req +        items = model.objects.filter(query) +        q = request_items.get('sidx') +        # manage tables +        if q and q in request_keys: +            k = request_keys[q] +            if k.endswith("__pk"): +                k = k[:-len("__pk")] + "__label" +            q = request_items.get('sord') +            sign = q and q == u'desc' and "-" or '' +            items = items.order_by(sign + k) +        datas = [] +        if old: +            items = [item.get_previous(old) for item in items] +        for item in items: +            data = [item.pk] +            for k in model.TABLE_COLS: +                vals = [item] +                for ky in k.split('.'): +                    new_vals = [] +                    for val in vals: +                        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 +                    new_vals = [] +                    for val in vals: +                        new_vals += list(val.all()) +                    vals = new_vals +                data.append(", ".join([format_val(v) for v in vals]) or u"") +            datas.append(data) +        link_template = "<a 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], '']) +                except NoReverseMatch: +                    lnk = '' +                res = {'id':data[0], 'link':lnk} +                for idx, value in enumerate(data[1:]): +                    if value: +                        res[model.TABLE_COLS[idx].split('.')[-1]] = value +                rows.append(res) +            data = json.dumps({ +                "records":len(items), +                "rows":rows +            }) +            return HttpResponse(data, mimetype='text/plain') +        elif data_type == "csv": +            response = HttpResponse(mimetype='text/csv') +            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 +            writer = csv.writer(response, **CSV_OPTIONS) +            col_names = [] +            for field_name in model.TABLE_COLS: +                try: +                    field = model._meta.get_field(field_name) +                except: +                    col_names.append(u"".encode(ENCODING)) +                    continue +                col_names.append(unicode(field.verbose_name).encode(ENCODING)) +            writer.writerow(col_names) +            for data in datas: +                writer.writerow([val.encode(ENCODING) for val in data[1:]]) +            return response +        return HttpResponse(None, mimetype='text/plain') + +    return func + +def show_item(model, name): +    def func(request, pk, **dct): +        try: +            item = model.objects.get(pk=pk) +        except ObjectDoesNotExist: +            return HttpResponse(None) +        doc_type = 'type' in dct and dct.pop('type') +        date = 'date' in dct and dct.pop('date') +        dct['window_id'] = "%s-%d-%s" % (name, item.pk, +                                      datetime.datetime.now().strftime('%M%s')) +        if date: +            try: +                date = datetime.datetime.strptime(date, '%Y-%m-%dT%H:%M:%S.%f') +                item = item.get_previous(date=date) +                assert item != None +            except (ValueError, AssertionError): +                return HttpResponse(None, mimetype='text/plain') +            dct['previous'] = item._previous +            dct['next'] = item._next +        else: +            historized = item.history.all() +            if historized: +                item.history_date = historized[0].history_date +            if len(historized) > 1: +                dct['previous'] = historized[1].history_date +        dct['item'], dct['item_name'] = item, name +        context_instance = RequestContext(request) +        context_instance.update(dct) +        n = datetime.datetime.now() +        filename = u'%s_%s_%s' % (name, slugify(unicode(item)), +                                  n.strftime('%Y%m%d-%H%M%S')) +        if doc_type == "odt" and settings.XHTML2ODT_PATH and \ +           settings.ODT_TEMPLATE: +            tpl = loader.get_template('sheet_%s.html' % name) +            content = tpl.render(context_instance) +            try: +                tidy_options = dict(output_xhtml=1, add_xml_decl=1, indent=1, +                        tidy_mark=0, output_encoding='utf8', doctype='auto', +                        wrap=0, char_encoding='utf8') +                html = str(tidy.parseString(content.encode('utf-8'), +                                            **tidy_options)) +                html = html.replace(" ", " ") +                html = re.sub('<pre([^>]*)>\n', '<pre\\1>', html) + +                odt = NamedTemporaryFile() +                options = optparse.Values() +                options.with_network = True +                for k, v in (('input', ''), +                             ('output', odt.name), +                             ('template', settings.ODT_TEMPLATE), +                             ('with_network', True), +                             ('top_header_level', 1), +                             ('img_width', '8cm'), +                             ('img_height', '6cm'), +                             ('verbose', False), +                             ('replace_keyword', 'ODT-INSERT'), +                             ('cut_start', 'ODT-CUT-START'), +                             ('htmlid', None), +                             ('url', "#")): +                    setattr(options, k, v) +                odtfile = xhtml2odt.ODTFile(options) +                odtfile.open() +                odtfile.import_xhtml(html) +                odtfile = odtfile.save() +            except xhtml2odt.ODTExportError, ex: +                return HttpResponse(content, content_type="application/xhtml") +            response = HttpResponse( +                            mimetype='application/vnd.oasis.opendocument.text') +            response['Content-Disposition'] = 'attachment; filename=%s.odt' % \ +                                                                       filename +            response.write(odtfile) +            return response +        elif doc_type == 'pdf': +            tpl = loader.get_template('sheet_%s_pdf.html' % name) +            content = tpl.render(context_instance) +            result = StringIO.StringIO() +            html = content.encode('utf-8') +            html = html.replace("<table", "<pdf:nextpage/><table repeat='1'") +            pdf = pisa.pisaDocument(StringIO.StringIO(html), result) +            response = HttpResponse(result.getvalue(), +                                    mimetype='application/pdf') +            response['Content-Disposition'] = 'attachment; filename=%s.pdf' % \ +                                                                       filename +            if not pdf.err: +                return response +            return HttpResponse(content, content_type="application/xhtml") +        else: +            tpl = loader.get_template('sheet_%s_window.html' % name) +            content = tpl.render(context_instance) +            return HttpResponse(content, content_type="application/xhtml") +    return func + +def revert_item(model): +    def func(request, pk, date, **dct): +        try: +            item = model.objects.get(pk=pk) +            date = datetime.datetime.strptime(date, '%Y-%m-%dT%H:%M:%S.%f') +            item.rollback(date) +        except (ObjectDoesNotExist, ValueError, HistoryError): +            return HttpResponse(None, mimetype='text/plain') +        return HttpResponse("True", mimetype='text/plain') +    return func + + +get_file = get_item(models.File, 'get_file', 'file') +show_file = show_item(models.File, 'file') +revert_file = revert_item(models.File) + +def autocomplete_operation(request, non_closed=True): +    if not request.user.has_perm('ishtar_base.view_operation', models.Operation)\ +       and not request.user.has_perm('ishtar_base.view_own_operation', +                                                              models.Operation): +        return HttpResponse(mimetype='text/plain') +    if not request.GET.get('term'): +        return HttpResponse(mimetype='text/plain') +    q = request.GET.get('term') +    query = Q() +    for q in q.split(' '): +        extra = Q(towns__name__icontains=q) +        try: +            value = int(q) +            extra = extra | Q(year=q) | Q(operation_code=q) +        except ValueError: +            pass +        query = query & extra +    if non_closed: +        query = query & Q(end_date__isnull=True) +    limit = 15 +    operations = models.Operation.objects.filter(query)[:limit] +    data = json.dumps([{'id':operation.pk, 'value':unicode(operation)} +                                          for operation in operations]) +    return HttpResponse(data, mimetype='text/plain') + +get_operation = get_item(models.Operation, 'get_operation', 'operation') +show_operation = show_item(models.Operation, 'operation') +revert_operation = revert_item(models.Operation) + +get_administrativeactfile = get_item(models.AdministrativeAct, +        'get_administrativeactfile', 'administrativeactfile', +      extra_request_keys={'associated_file__towns':'associated_file__towns__pk', +                          'operation__towns':'operation__towns__pk', +                          'act_type__intented_to':'act_type__intented_to'}) +get_administrativeactop = get_item(models.AdministrativeAct, +        'get_administrativeactop', 'administrativeactop', +      extra_request_keys={'associated_file__towns':'associated_file__towns__pk', +                          'operation__towns':'operation__towns__pk', +                          'act_type__intented_to':'act_type__intented_to'}) + +def autocomplete_organization(request, orga_type=None): +    if not request.user.has_perm('ishtar_base.view_organization', +                                 models.Organization) and \ +       not request.user.has_perm('ishtar_base.view_own_organization', +                                 models.Organization): +        return HttpResponse(mimetype='text/plain') +    if not request.GET.get('term'): +        return HttpResponse(mimetype='text/plain') +    q = request.GET.get('term') +    query = Q() +    for q in q.split(' '): +        extra = Q(name__icontains=q) +        query = query & extra +    if orga_type: +        try: +            typs = [int(tp) for tp in orga_type.split('_') if tp] +            typ = models.OrganizationType.objects.filter(pk__in=typs).all() +            query = query & Q(organization_type__in=typ) +        except (ValueError, ObjectDoesNotExist): +            pass +    limit = 15 +    organizations = models.Organization.objects.filter(query)[:limit] +    data = json.dumps([{'id':org.pk, 'value':unicode(org)} +                                          for org in organizations]) +    return HttpResponse(data, mimetype='text/plain') + +show_contextrecord = show_item(models.ContextRecord, 'contextrecord') +get_contextrecord = get_item(models.ContextRecord, +        'get_contextrecord', 'contextrecord', +      extra_request_keys={'parcel__town':'parcel__town__pk', +                  'operation__year':'operation__year__contains', +                  'datings__period':'datings__period__pk'},) +get_archaeologicalitem = get_item(models.Item, +        'get_archaeologicalitem', 'item', +        bool_fields = ['base_items__is_isolated'], +      extra_request_keys={ +'base_items__context_record__parcel__town': +                'base_items__context_record__parcel__town', +'base_items__context_record__operation__year': +                'base_items__context_record__operation__year__contains', +'base_items__context_record__operation__code_patriarche': +               'base_items__context_record__operation__code_patriarche', +'dating__period':'dating__period__pk', +'base_items__item__description':'base_items__item__description__icontains', +'base_items__is_isolated':'base_items__is_isolated'}) + +def autocomplete_warehouse(request): +    if not request.user.has_perm('ishtar_base.view_warehouse', models.Warehouse)\ +       and not request.user.has_perm('ishtar_base.view_own_warehouse', +                                     models.Warehouse) : +        return HttpResponse(mimetype='text/plain') +    if not request.GET.get('term'): +        return HttpResponse(mimetype='text/plain') +    q = request.GET.get('term') +    query = Q() +    for q in q.split(' '): +        extra = Q(name__icontains=q) | \ +                Q(warehouse_type__label__icontains=q) +        query = query & extra +    limit = 15 +    warehouses = models.Warehouse.objects.filter(query)[:limit] +    data = json.dumps([{'id':warehouse.pk, 'value':unicode(warehouse)} +                                          for warehouse in warehouses]) +    return HttpResponse(data, mimetype='text/plain') + +def autocomplete_author(request): +    if not request.user.has_perm('ishtar_base.view_author', models.Author)\ +       and not request.user.has_perm('ishtar_base.view_own_author', +                                     models.Warehouse) : +        return HttpResponse(mimetype='text/plain') +    if not request.GET.get('term'): +        return HttpResponse(mimetype='text/plain') +    q = request.GET.get('term') +    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) +        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]) +    return HttpResponse(data, mimetype='text/plain') + +def new_item(model): +    def func(request, parent_name): +        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) +        frm = getattr(ishtar_forms, model_name + 'Form') +        dct = {'title':unicode(_(u'New %s' % model_name.lower()))} +        if request.method == 'POST': +            dct['form'] = frm(request.POST) +            if dct['form'].is_valid(): +                new_item = dct['form'].save(request.user) +                dct['new_item_label'] = unicode(new_item) +                dct['new_item_pk'] = new_item.pk +                dct['parent_name'] = parent_name +                dct['parent_pk'] = parent_name +                if '_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)) +        else: +            dct['form'] = frm() +        return render_to_response('window.html', dct, +                                  context_instance=RequestContext(request)) +    return func + +new_warehouse = new_item(models.Warehouse) +new_person = new_item(models.Person) +new_organization = new_item(models.Organization) +new_author = new_item(models.Author) + +def action(request, action_slug, obj_id=None, *args, **kwargs): +    """ +    Action management +    """ +    if not check_permission(request, action_slug, obj_id): +        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: +        return globals_dct[action_slug](request, dct, obj_id, *args, **kwargs) +    elif hasattr(ishtar_forms, action_slug + "_wizard"): +        return getattr(ishtar_forms, action_slug+"_wizard")(request, *args, +                                                            **kwargs) +    return render_to_response('index.html', dct, +                              context_instance=RequestContext(request)) + | 
