diff options
| author | Étienne Loks <etienne.loks@iggdrasil.net> | 2019-02-26 20:14:22 +0100 | 
|---|---|---|
| committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2019-04-24 19:38:57 +0200 | 
| commit | c33e49777af11ad8cadc311833136cbaf5872962 (patch) | |
| tree | c644209eb81804406bfc5f014713dc1f62bc5ad4 | |
| parent | 01945a4aeca368458236cf022b64be2b3539e66b (diff) | |
| download | Ishtar-c33e49777af11ad8cadc311833136cbaf5872962.tar.bz2 Ishtar-c33e49777af11ad8cadc311833136cbaf5872962.zip | |
QR code: QR code export, display on ODT and PDF
| -rw-r--r-- | archaeological_context_records/models.py | 4 | ||||
| -rw-r--r-- | archaeological_finds/models_finds.py | 6 | ||||
| -rw-r--r-- | archaeological_finds/templates/ishtar/sheet_find.html | 2 | ||||
| -rw-r--r-- | archaeological_operations/models.py | 8 | ||||
| -rw-r--r-- | archaeological_operations/tests.py | 36 | ||||
| -rw-r--r-- | archaeological_warehouse/models.py | 4 | ||||
| -rw-r--r-- | example_project/settings.py | 4 | ||||
| -rw-r--r-- | ishtar_common/models.py | 3 | ||||
| -rw-r--r-- | ishtar_common/static/media/style_basic.css | 14 | ||||
| -rw-r--r-- | ishtar_common/templates/ishtar/blocks/window_nav.html | 9 | ||||
| -rw-r--r-- | ishtar_common/templates/ishtar/sheet.html | 31 | ||||
| -rw-r--r-- | ishtar_common/urls.py | 2 | ||||
| -rw-r--r-- | ishtar_common/views.py | 31 | ||||
| -rw-r--r-- | ishtar_common/views_item.py | 3 | 
14 files changed, 127 insertions, 30 deletions
| diff --git a/archaeological_context_records/models.py b/archaeological_context_records/models.py index cd2b5f382..6dad4f600 100644 --- a/archaeological_context_records/models.py +++ b/archaeological_context_records/models.py @@ -271,8 +271,10 @@ class CRBulkView(object):  class ContextRecord(BulkUpdatedItem, BaseHistorizedItem, QRCodeItem, GeoItem,                      OwnPerms, ValueGetter, ShortMenuItem, RelationItem): -    SHOW_URL = 'show-contextrecord'      SLUG = 'contextrecord' +    APP = "archaeological-context-records" +    MODEL = "context-record" +    SHOW_URL = 'show-contextrecord'      EXTERNAL_ID_KEY = 'context_record_external_id'      EXTERNAL_ID_DEPENDENCIES = ['base_finds']      TABLE_COLS = ['label', 'operation__common_name', 'town__name', diff --git a/archaeological_finds/models_finds.py b/archaeological_finds/models_finds.py index 084e2b8d7..e93580418 100644 --- a/archaeological_finds/models_finds.py +++ b/archaeological_finds/models_finds.py @@ -702,9 +702,11 @@ def query_loan(is_true=True):  class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, QRCodeItem,             OwnPerms, MainItem): -    EXTERNAL_ID_KEY = 'find_external_id' -    SHOW_URL = 'show-find'      SLUG = 'find' +    APP = "archaeological-finds" +    MODEL = "find" +    SHOW_URL = 'show-find' +    EXTERNAL_ID_KEY = 'find_external_id'      TABLE_COLS = ['external_id', 'label',                    'base_finds__context_record__town__name',                    'base_finds__context_record__operation__common_name', diff --git a/archaeological_finds/templates/ishtar/sheet_find.html b/archaeological_finds/templates/ishtar/sheet_find.html index 1b383e4e5..7644acb60 100644 --- a/archaeological_finds/templates/ishtar/sheet_find.html +++ b/archaeological_finds/templates/ishtar/sheet_find.html @@ -27,6 +27,7 @@  {% with can_view_documents=permission_view_own_document|or_:permission_view_document %}  {% with display_documents=can_view_documents|and_:item.documents.count %} +{% if output != "ODT" and output != "PDF"%}  <ul class="nav nav-tabs" id="{{window_id}}-tabs" role="tablist">      <li class="nav-item">          <a class="nav-link active" id="{{window_id}}-basefind-tab" @@ -79,6 +80,7 @@      </li>      {% endif %}  </ul> +{% endif %}  <div class="tab-content" id="{{window_id}}-tab-content"> diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py index a09798f1f..aa1e2dcb4 100644 --- a/archaeological_operations/models.py +++ b/archaeological_operations/models.py @@ -109,9 +109,11 @@ post_delete.connect(post_save_cache, sender=RecordQualityType)  class ArchaeologicalSite(BaseHistorizedItem, QRCodeItem, GeoItem, OwnPerms,                           ValueGetter, ShortMenuItem): +    SLUG = 'site' +    APP = "archaeological-operations" +    MODEL = "archaeological-site"      SHOW_URL = 'show-site'      TABLE_COLS = ['reference', 'name', 'towns_label', 'periods', 'remains'] -    SLUG = 'site'      LONG_SLUG = 'archaeologicalsite'      BASE_SEARCH_VECTORS = [ @@ -511,10 +513,12 @@ class OperationManager(models.GeoManager):  class Operation(ClosedItem, BaseHistorizedItem, QRCodeItem, GeoItem, OwnPerms,\                  ValueGetter, ShortMenuItem, DashboardFormItem, RelationItem): +    SLUG = 'operation' +    APP = "archaeological-operations" +    MODEL = "operation"      SHOW_URL = 'show-operation'      TABLE_COLS = ['year', 'towns_label', 'common_name', 'operation_type',                    'start_date', 'excavation_end_date', 'remains'] -    SLUG = 'operation'      # search parameters      BOOL_FIELDS = ['end_date__isnull', 'virtual_operation', diff --git a/archaeological_operations/tests.py b/archaeological_operations/tests.py index 01418141d..14577e119 100644 --- a/archaeological_operations/tests.py +++ b/archaeological_operations/tests.py @@ -2547,3 +2547,39 @@ class SiteTest(TestCase, OperationInitTest):          search = {'search_vector': 'reference="reference*"'}          response = c.get(reverse('get-site'), search)          self.assertEqual(json.loads(response.content)['recordsTotal'], 1) + + +class GenerateQRCode(OperationInitTest, TestCase): +    fixtures = FILE_FIXTURES + +    def setUp(self): +        self.username, self.password, self.user = create_superuser() +        self.operation = self.create_operation(self.user)[0] + +    def test_display(self): +        if self.operation.qrcode.name: +            self.operation.qrcode = None +            self.operation.save() +        operation = models.Operation.objects.get(pk=self.operation.pk) +        self.assertIn(operation.qrcode.name, ["", None]) +        c = Client() +        url = reverse('qrcode-item', args=[ +            'archaeological-operations', 'operation', operation.pk]) +        response = c.get(url) +        self.assertEqual(response.status_code, 302) +        c.login(username=self.username, password=self.password) +        response = c.get(url) +        self.assertEqual(response.status_code, 200) +        self.assertEqual(response['Content-Type'], "image/png") +        operation = models.Operation.objects.get(pk=self.operation.pk) +        self.assertIsNotNone(operation.qrcode.name) + +    def test_generation(self): +        self.assertIsNone(self.operation.qrcode.name) +        self.operation.generate_qrcode() +        self.assertIsNotNone(self.operation.qrcode.name) +        self.assertTrue( +            self.operation.qrcode.name.startswith( +                "operation/2010/OP2010-1/qrcode" +            ) +        ) diff --git a/archaeological_warehouse/models.py b/archaeological_warehouse/models.py index 115f0d7ea..6e2df520e 100644 --- a/archaeological_warehouse/models.py +++ b/archaeological_warehouse/models.py @@ -50,6 +50,8 @@ post_delete.connect(post_save_cache, sender=WarehouseType)  class Warehouse(Address, GeoItem, QRCodeItem, DashboardFormItem, OwnPerms,                  ShortMenuItem):      SLUG = 'warehouse' +    APP = "archaeological-warehouse" +    MODEL = "warehouse"      SHOW_URL = 'show-warehouse'      TABLE_COLS = ['name', 'warehouse_type']      BASE_SEARCH_VECTORS = ['name', 'warehouse_type__label', "external_id", @@ -325,6 +327,8 @@ post_delete.connect(post_save_cache, sender=ContainerType)  class Container(LightHistorizedItem, QRCodeItem, GeoItem, OwnPerms):      SLUG = 'container' +    APP = "archaeological-warehouse" +    MODEL = "container"      SHOW_URL = 'show-container'      TABLE_COLS = ['reference', 'container_type__label', 'cached_location',                    'cached_division', 'old_reference'] diff --git a/example_project/settings.py b/example_project/settings.py index 9c742eedf..54872e3ec 100644 --- a/example_project/settings.py +++ b/example_project/settings.py @@ -231,8 +231,8 @@ USE_BACKGROUND_TASK = False  # Ishtar custom  ISHTAR_MAP_MAX_ITEMS = 50000 -ISHTAR_QRCODE_VERSION = 10  # density of the QR code -ISHTAR_QRCODE_SCALE = 3  # scale of the QR code +ISHTAR_QRCODE_VERSION = 8  # density of the QR code +ISHTAR_QRCODE_SCALE = 2  # scale of the QR code  SRID = 27572  SURFACE_SRID = 2154 diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 9b5185be4..247ab4f61 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -1572,6 +1572,7 @@ class FixAssociated(object):  class QRCodeItem(models.Model, ImageContainerModel): +    HAS_QR_CODE = True      qrcode = models.ImageField(upload_to=get_image_path, blank=True, null=True,                                 max_length=255) @@ -1582,7 +1583,7 @@ class QRCodeItem(models.Model, ImageContainerModel):          url = self.get_absolute_url()          site = Site.objects.get_current()          if request: -            scheme = self.request.scheme +            scheme = request.scheme          else:              if secure:                  scheme = "https" diff --git a/ishtar_common/static/media/style_basic.css b/ishtar_common/static/media/style_basic.css index bfd89dfca..051543ea9 100644 --- a/ishtar_common/static/media/style_basic.css +++ b/ishtar_common/static/media/style_basic.css @@ -54,10 +54,18 @@ td{      margin:0;      padding:0;      padding-top:4px; -    text-align:right; +    text-align: right;      border:1px solid #EEE;      border-top:none;      font-size:0.9em; +    background-color: #ddd; +} + +.window-table-head td{ +    text-align: left; +    border:0 solid transparent; +    font-size: 1em; +    background-color: transparent;  }  .link{ @@ -92,10 +100,6 @@ p{      margin:0.2em;  } -td{ -    background-color: #ddd; -} -  #pdffooter, #pdfheader{      text-align:center;  } diff --git a/ishtar_common/templates/ishtar/blocks/window_nav.html b/ishtar_common/templates/ishtar/blocks/window_nav.html index a53e62b0d..92fa15352 100644 --- a/ishtar_common/templates/ishtar/blocks/window_nav.html +++ b/ishtar_common/templates/ishtar/blocks/window_nav.html @@ -71,15 +71,18 @@                     aria-labelledby="dropdown-sheet-export-{{window_id}}">                    <a class="dropdown-item" href='{% url show_url item.pk "odt" %}'                       title='{% trans "Export as OpenOffice.org file"%}'> -                      ODT <i class="fa fa-file-word-o" aria-hidden="true"></i> +                      <i class="fa fa-file-word-o" aria-hidden="true"></i> ODT                    </a>                    <a class="dropdown-item" href='{% url show_url item.pk "pdf" %}'                       title='{% trans "Export as PDF file"%}'> -                      PDF <i class="fa fa-file-pdf-o" aria-hidden="true"></i> +                      <i class="fa fa-file-pdf-o" aria-hidden="true"></i> PDF                    </a>{% for template_name, template_url in extra_templates %}                    <a class="dropdown-item" href='{{template_url}}'> -                      {{template_name}} <i class="fa fa-file-word-o" aria-hidden="true"></i> +                      <i class="fa fa-file-word-o" aria-hidden="true"></i> {{template_name}}                    </a>{% endfor %} +                  {% if item.HAS_QR_CODE %}<a class="dropdown-item" href='{% url "qrcode-item" item.APP item.MODEL item.pk %}' target="_blank"> +                     <i class="fa fa-qrcode" aria-hidden="true"></i> {% trans "QR Code" %}  +                  </a>{% endif %}                </div>            </div> diff --git a/ishtar_common/templates/ishtar/sheet.html b/ishtar_common/templates/ishtar/sheet.html index e937f1474..6b9c97948 100644 --- a/ishtar_common/templates/ishtar/sheet.html +++ b/ishtar_common/templates/ishtar/sheet.html @@ -8,28 +8,37 @@  </head>  <body>  {% endblock %} -    <div class="card sheet" id="{{window_id}}"> + +    {% if output != "ODT" and output != "PDF" %}      <div class="card-header" data-sheet-id="{{sheet_id}}" role="tab" id='head-{{window_id}}'>        <div class="row">            <div class="col-9"> -              {% if output != "ODT" and output != "PDF"%}                <h5 class="mb-0">                  <a class="card-label" data-toggle="collapse"                      href="#collapse-{{window_id}}" aria-expanded="true"                     aria-controls="collapse-{{window_id}}"> -              {% else %} -              <h2> -              {% endif %} +    {% else %} +      {% if item.qrcode.name %} +      <table class="window-table-head"> +        <tr> +          <td> <img class="qrcode" src="{{BASE_URL}}{{item.qrcode.url}}"> </td> +          <td> +      {% endif %} +            <h2> +    {% endif %}                      {% block head_title %}{% endblock %} -              {% if output == "ODT" or output == "PDF"%} -              </h2> -              {% else %} +    {% if output == "ODT" or output == "PDF" %} +            </h2> +      {% if item.qrcode.name %} +          </td> +        </tr> +      </table> +      {% endif %} +    {% else %}                  </a>                </h5> -              {% endif %}            </div> -          {% if output != "ODT" and output != "PDF"%}            <div class='col-2 text-center'>                <a href='#' class='previous_page'>                  <span class="fa-stack"> @@ -53,8 +62,8 @@                </span>              </a>            </div> -          {% endif %}        </div> +      {% endif %}        {% block header_title %}{% endblock %}      </div> diff --git a/ishtar_common/urls.py b/ishtar_common/urls.py index aea419d08..957b1bfb3 100644 --- a/ishtar_common/urls.py +++ b/ishtar_common/urls.py @@ -40,6 +40,8 @@ urlpatterns = [      url(r'shortcut_menu/', views.shortcut_menu, name='shortcut-menu'),      url(r'display/(?P<item_type>\w+)/(?P<pk>\d+)/',          views.DisplayItemView.as_view(), name='display-item'), +    url(r'qrcode/(?P<app>[-a-z]+)/(?P<model_name>[-a-z]+)/(?P<pk>\d+)/', +        views.QRCodeView.as_view(), name='qrcode-item'),      url(r'person_search/(?P<step>.+)?$',          check_rights(['add_person'])(              views.person_search_wizard), name='person_search'), diff --git a/ishtar_common/views.py b/ishtar_common/views.py index 61bae69e2..5f5b0be42 100644 --- a/ishtar_common/views.py +++ b/ishtar_common/views.py @@ -19,12 +19,14 @@  import csv  import datetime +import importlib  import json  import logging -import importlib +import os +import unicodecsv  import unicodedata -import unicodecsv +from django.apps import apps  from django.conf import settings  from django.contrib.auth import logout  from django.contrib.auth.decorators import login_required @@ -38,7 +40,7 @@ from django.http import HttpResponse, Http404, HttpResponseRedirect, \  from django.shortcuts import redirect, render  from django.utils.decorators import method_decorator  from django.utils.translation import ugettext, ugettext_lazy as _ -from django.views.generic import ListView, UpdateView, TemplateView +from django.views.generic import ListView, TemplateView, View  from django.views.generic.edit import CreateView, DeleteView, FormView, \      UpdateView  from extra_views import ModelFormSetView @@ -1010,6 +1012,29 @@ class DisplayItemView(IshtarMixin, LoginRequiredMixin, TemplateView):          return data +class QRCodeView(IshtarMixin, LoginRequiredMixin, View): +    def get(self, request, *args, **kwargs): +        model_name = "".join( +            [part.capitalize() for part in kwargs.get('model_name').split('-')] +        ) +        app = kwargs.get('app').replace('-', "_") +        try: +            model = apps.get_model(app, model_name) +            item = model.objects.get(pk=kwargs.get("pk")) +            assert hasattr(item, 'qrcode') +        except (LookupError, model.DoesNotExist, AssertionError): +            raise Http404() + +        if not item.qrcode or not item.qrcode.name: +            item.generate_qrcode(request=self.request) + +        if not item.qrcode or not item.qrcode.name:  # generation has failed +            raise Http404() + +        with open(settings.MEDIA_ROOT + os.sep + item.qrcode.name, "rb") as f: +            return HttpResponse(f.read(), content_type="image/png") + +  class GlobalVarEdit(IshtarMixin, AdminLoginRequiredMixin, ModelFormSetView):      template_name = 'ishtar/formset.html'      model = models.GlobalVar diff --git a/ishtar_common/views_item.py b/ishtar_common/views_item.py index ffbbbb936..16128feba 100644 --- a/ishtar_common/views_item.py +++ b/ishtar_common/views_item.py @@ -218,6 +218,9 @@ def show_item(model, name, extra_dct=None, model_for_perms=None):                      item.history_date = historized[0].history_date                  if len(historized) > 1:                      dct['previous'] = historized[1].history_date +        if doc_type in ("odt", "pdf") and hasattr(item, 'qrcode') \ +                and (not item.qrcode or not item.qrcode.name): +            item.generate_qrcode(request=request)          dct['item'], dct['item_name'] = item, name          # add context          if extra_dct: | 
