summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
Diffstat (limited to 'ishtar_common')
-rw-r--r--ishtar_common/models.py3
-rw-r--r--ishtar_common/models_common.py49
-rw-r--r--ishtar_common/templates/ishtar/blocks/window_field_flex_multiple.html6
-rw-r--r--ishtar_common/templates/ishtar/blocks/window_nav.html6
-rw-r--r--ishtar_common/templates/ishtar/sheet.html8
-rw-r--r--ishtar_common/templatetags/ishtar_helpers.py14
-rw-r--r--ishtar_common/templatetags/window_field.py12
-rw-r--r--ishtar_common/utils.py13
-rw-r--r--ishtar_common/views_item.py83
9 files changed, 164 insertions, 30 deletions
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index 59248fa43..442e67429 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -3619,7 +3619,7 @@ class Document(
_TABLE_COLS = [
"title",
- "source_type",
+ "source_type__label",
"cache_related_label",
"authors__cached_label",
"associated_url",
@@ -3658,6 +3658,7 @@ class Document(
COL_LABELS = {
"authors__cached_label": _("Authors"),
"complete_identifier": _("Identifier"),
+ "source_type__label": _("Type")
}
CACHED_LABELS = ["cache_related_label"]
diff --git a/ishtar_common/models_common.py b/ishtar_common/models_common.py
index 58eac91e2..e55a21e0c 100644
--- a/ishtar_common/models_common.py
+++ b/ishtar_common/models_common.py
@@ -9,6 +9,7 @@ import copy
from collections import OrderedDict
import datetime
import json
+import locale
import logging
import os
import pyqrcode
@@ -39,7 +40,8 @@ from django.db.models.signals import post_save, post_delete, m2m_changed
from django.template.defaultfilters import slugify
from django.utils.safestring import SafeText, mark_safe
from django.utils.translation import activate, deactivate
-from ishtar_common.utils import ugettext_lazy as _, pgettext_lazy, get_image_path
+from ishtar_common.utils import ugettext_lazy as _, pgettext_lazy, get_image_path, \
+ human_date
from simple_history.models import HistoricalRecords as BaseHistoricalRecords
from simple_history.signals import (
post_create_historical_record,
@@ -2536,6 +2538,10 @@ class DocumentItem:
),
}
+ def documents_list(self) -> list:
+ Document = apps.get_model("ishtar_common", "Document")
+ return self.get_associated_main_item_list("documents", Document)
+
def public_representation(self):
images = []
if getattr(self, "main_image", None):
@@ -3247,6 +3253,9 @@ class MainItem(ShortMenuItem):
QUICK_ACTIONS = []
SERIALIZE_EXCLUDE = ["search_vector"]
+ SERIALIZE_PROPERTIES = ["external_id", "multi_polygon_geojson", "point_2d_geojson"]
+ SERIALIZE_CALL = {}
+ SERIALIZE_DATES = []
def full_serialize(self) -> dict:
"""
@@ -3268,20 +3277,56 @@ class MainItem(ShortMenuItem):
elif field.many_to_many:
values = getattr(self, field.name)
if values.count():
- values = [str(v) for v in values]
+ values = [str(v) for v in values.all()]
else:
values = []
full_result[field.name] = values
else:
serialize_fields.append(field.name)
+
result = json.loads(serialize(
"json",
[self],
fields=serialize_fields
))
full_result.update(result[0]["fields"])
+ for prop in self.SERIALIZE_PROPERTIES:
+ if prop not in full_result:
+ full_result[prop] = getattr(self, prop)
+ if "point_2d_geojson" in full_result:
+ full_result["point_2d"] = True
+ if "multi_polygon_geojson" in full_result:
+ full_result["multi_polygon"] = True
+ for prop in self.SERIALIZE_DATES:
+ dt = getattr(self, prop) or ""
+ if dt:
+ dt = human_date(dt)
+ full_result[prop] = dt
+ for k in self.SERIALIZE_CALL:
+ full_result[k] = getattr(self, self.SERIALIZE_CALL[k])()
+ full_result["SLUG"] = self.SLUG
+ full_result["pk"] = f"external_{self.pk}"
+ full_result["id"] = f"external_{self.id}"
return full_result
+ def get_associated_main_item_list(self, attr, model) -> list:
+ items = getattr(self, attr)
+ if not items.count():
+ return []
+ lst = []
+ table_cols = model.TABLE_COLS
+ if callable(table_cols):
+ table_cols = table_cols()
+ for colname in table_cols:
+ if colname in model.COL_LABELS:
+ lst.append(str(model.COL_LABELS[colname]))
+ else:
+ lst.append(model._meta.get_field(colname).verbose_name)
+ lst = [lst]
+ for values in items.values_list(*table_cols):
+ lst.append(["-" if v is None else v for v in values])
+ return lst
+
@classmethod
def class_verbose_name(cls):
return cls._meta.verbose_name
diff --git a/ishtar_common/templates/ishtar/blocks/window_field_flex_multiple.html b/ishtar_common/templates/ishtar/blocks/window_field_flex_multiple.html
index abf03ead1..1587963c5 100644
--- a/ishtar_common/templates/ishtar/blocks/window_field_flex_multiple.html
+++ b/ishtar_common/templates/ishtar/blocks/window_field_flex_multiple.html
@@ -1,8 +1,8 @@
-{% load i18n %}{% if data.count %}
+{% load i18n %}{% if data.count or external %}
<dl class="col-12 {% if size == 2 %}col-lg-6{% else %}col-md-6 col-lg-3{% endif %} flex-wrap">
<dt>{% trans caption %}</dt>
- <dd>{% for d in data.all %}
+ <dd>{% if not external %}{% for d in data.all %}
{% if forloop.counter0 %} ; {% endif %}{{ d }}
- {% endfor %}</dd>
+ {% endfor %}{% else %}{{data}}{% endif %}</dd>
</dl>
{% endif %}
diff --git a/ishtar_common/templates/ishtar/blocks/window_nav.html b/ishtar_common/templates/ishtar/blocks/window_nav.html
index 1d8121faf..a1ec01dcb 100644
--- a/ishtar_common/templates/ishtar/blocks/window_nav.html
+++ b/ishtar_common/templates/ishtar/blocks/window_nav.html
@@ -1,4 +1,5 @@
{% load i18n ishtar_helpers %}
+{% if not item.is_external %}
<div class="row toolbar">
{% if current_user.is_superuser %}
{% if previous or next %}
@@ -112,4 +113,7 @@
$(document).ready(function(){
register_qa_on_sheet();
});
-</script> \ No newline at end of file
+</script>
+{% else %}
+<h3><i class="fa fa-globe" aria-hidden="true"></i> {{item.current_source}}</h3>
+{% endif %} \ No newline at end of file
diff --git a/ishtar_common/templates/ishtar/sheet.html b/ishtar_common/templates/ishtar/sheet.html
index b0f82941f..4596d8ec6 100644
--- a/ishtar_common/templates/ishtar/sheet.html
+++ b/ishtar_common/templates/ishtar/sheet.html
@@ -79,19 +79,19 @@
var last_window='{{window_id}}';
jQuery(document).ready(function(){
- if (! get_next_table_id({{item.pk}})){
+ if (! get_next_table_id("{{item.pk}}")){
jQuery('.next_page').hide();
}
- if (! get_previous_table_id({{item.pk}})){
+ if (! get_previous_table_id("{{item.pk}}")){
jQuery('.previous_page').hide();
}
jQuery(".next_page").click(function() {
- load_window("{{current_window_url}}" + get_next_table_id({{item.pk}}) + "/",
+ load_window("{{current_window_url}}" + get_next_table_id("{{item.pk}}") + "/",
'', function(){hide_window("{{window_id}}");},
true);
});
jQuery(".previous_page").click(function() {
- load_window("{{current_window_url}}" + get_previous_table_id({{item.pk}}) + "/",
+ load_window("{{current_window_url}}" + get_previous_table_id("{{item.pk}}") + "/",
'', function(){hide_window("{{window_id}}");},
true);
});
diff --git a/ishtar_common/templatetags/ishtar_helpers.py b/ishtar_common/templatetags/ishtar_helpers.py
index ade89bdc0..250b5719d 100644
--- a/ishtar_common/templatetags/ishtar_helpers.py
+++ b/ishtar_common/templatetags/ishtar_helpers.py
@@ -25,10 +25,16 @@ def safe_or(item, args):
result = True
current_item = item
for sub in arg.split("."):
- if not hasattr(current_item, sub) or not getattr(current_item, sub):
- result = False
- break
- current_item = getattr(current_item, sub)
+ if isinstance(current_item, dict):
+ if sub not in current_item:
+ result = False
+ break
+ current_item = current_item[sub]
+ else:
+ if not hasattr(current_item, sub) or not getattr(current_item, sub):
+ result = False
+ break
+ current_item = getattr(current_item, sub)
if result:
return True
diff --git a/ishtar_common/templatetags/window_field.py b/ishtar_common/templatetags/window_field.py
index b21f2b9e6..cffa2a54f 100644
--- a/ishtar_common/templatetags/window_field.py
+++ b/ishtar_common/templatetags/window_field.py
@@ -98,12 +98,20 @@ def field_multiple(caption, data, li=False, size=None):
@register.simple_tag
def field_multiple_obj(caption, item, attr, li=False, size=None):
- data = getattr(item, attr) if hasattr(item, attr) else ""
+ data, external = "", False
+ if isinstance(item, dict):
+ if attr in item:
+ data = " ; ".join(item[attr])
+ if data:
+ external = True
+ else:
+ data = getattr(item, attr) if hasattr(item, attr) else ""
if not hasattr(item, '_step') or attr not in item.history_m2m \
or not item.history_m2m[attr]:
t = loader.get_template('ishtar/blocks/window_field_flex_multiple.html')
return t.render(
- {'caption': caption, 'data': data, 'li': li, "size": size}
+ {'caption': caption, 'data': data, 'li': li, "size": size,
+ "external": external}
)
field = getattr(item.instance.__class__, attr)
if hasattr(field, "remote_field"):
diff --git a/ishtar_common/utils.py b/ishtar_common/utils.py
index 3a349c04b..80d5af9d6 100644
--- a/ishtar_common/utils.py
+++ b/ishtar_common/utils.py
@@ -27,6 +27,7 @@ import hashlib
from importlib import import_module
import io
from jinja2 import Template
+import locale
import os
import random
import re
@@ -2111,6 +2112,18 @@ def get_image_path(instance, filename):
return instance._get_image_path(filename)
+def human_date(value):
+ language_code = settings.LANGUAGE_CODE.split("-")
+ language_code = language_code[0] + "_" + language_code[1].upper()
+ for language_suffix in (".utf8", ""):
+ try:
+ locale.setlocale(locale.LC_TIME, language_code + language_suffix)
+ break
+ except locale.Error:
+ pass
+ return value.strftime(settings.DATE_FORMAT)
+
+
class IshtarFileSystemStorage(FileSystemStorage):
def exists(self, name):
path_name = self.path(name)
diff --git a/ishtar_common/views_item.py b/ishtar_common/views_item.py
index 7ddfa179a..468312046 100644
--- a/ishtar_common/views_item.py
+++ b/ishtar_common/views_item.py
@@ -33,7 +33,7 @@ from django.db.models.functions import ExtractYear
from django.db.utils import ProgrammingError
from django import forms
from django.forms.models import model_to_dict
-from django.http import HttpResponse
+from django.http import HttpResponse, Http404
from django.shortcuts import render
from django.template import loader
from django.urls import reverse, NoReverseMatch
@@ -283,6 +283,52 @@ def display_item(model, extra_dct=None, show_url=None):
return func
+def show_source_item(request, source_id, model, name, base_dct, extra_dct):
+ try:
+ __, source_id, external_id = source_id.split("-")
+ source_id, external_id = int(source_id), int(external_id)
+ except ValueError:
+ raise Http404()
+ models_rest.ApiExternalSource.objects.get()
+ # TODO: check permissions
+ try:
+ src = models_rest.ApiExternalSource.objects.get(
+ pk=source_id)
+ except models_rest.ApiExternalSource.DoesNotExist:
+ return HttpResponse("{}", content_type="text/plain")
+ url = src.url
+ if not url.endswith("/"):
+ url += "/"
+ url += f"api/get/{model.SLUG}/{external_id}/"
+ try:
+ response = requests.get(
+ url,
+ timeout=20,
+ headers={"Authorization": f"Token {src.key}"},
+ )
+ except requests.exceptions.Timeout:
+ return HttpResponse("{}", content_type="text/plain")
+ item = response.json()
+ dct = deepcopy(base_dct)
+ if not item:
+ return HttpResponse("{}", content_type="text/plain")
+ item["is_external"] = True
+ item["current_source"] = src.name
+ dct["item"], dct["item_name"] = item, name
+ dct["is_external"] = True
+
+ if extra_dct:
+ dct.update(extra_dct(request, dct))
+
+ permissions = ["permission_view_document"]
+ for p in permissions:
+ dct[p] = True
+
+ tpl = loader.get_template(f"ishtar/sheet_{name}_window.html")
+ content = tpl.render(dct, request)
+ return HttpResponse(content, content_type="application/xhtml")
+
+
def show_item(model, name, extra_dct=None, model_for_perms=None):
def func(request, pk, **dct):
check_model = model
@@ -298,10 +344,6 @@ def show_item(model, name, extra_dct=None, model_for_perms=None):
query_own = model.get_query_owns(request.user.ishtaruser)
if query_own:
q = q.filter(query_own).distinct()
- try:
- item = q.get(pk=pk)
- except (ObjectDoesNotExist, ValueError):
- return HttpResponse("")
doc_type = "type" in dct and dct.pop("type")
url_name = (
"/".join(reverse("show-" + name, args=["0", ""]).split("/")[:-2]) + "/"
@@ -315,12 +357,15 @@ def show_item(model, name, extra_dct=None, model_for_perms=None):
date = None
if "date" in dct:
date = dct.pop("date")
- dct["sheet_id"] = "%s-%d" % (name, item.pk)
- dct["window_id"] = "%s-%d-%s" % (
- name,
- item.pk,
- datetime.datetime.now().strftime("%M%s"),
- )
+ dct["sheet_id"] = f"{name}-{pk}"
+ dct["window_id"] = f"{name}-{pk}-{datetime.datetime.now().strftime('%M%s')}"
+ if pk.startswith("source-"):
+ return show_source_item(
+ request, pk, model, name, dct, extra_dct)
+ try:
+ item = q.get(pk=pk)
+ except (ObjectDoesNotExist, ValueError):
+ return HttpResponse("")
# list current perms
if hasattr(request.user, "ishtaruser") and request.user.ishtaruser:
@@ -2359,7 +2404,7 @@ def get_distant_item(
try:
src = models_rest.ApiExternalSource.objects.get(
pk=external_source_id)
- except models_rest.ApiExternalSource.DoesNotExist:
+ except (models_rest.ApiExternalSource.DoesNotExist, ValueError):
return HttpResponse("{}", content_type="text/plain")
url = src.url
url += reverse(f"api-search-{model}")
@@ -2377,6 +2422,18 @@ def get_distant_item(
)
except requests.exceptions.Timeout:
return HttpResponse("{}", content_type="text/plain")
- return HttpResponse(json.dumps(response.json()), content_type="application/json")
+ dct = response.json()
+ if "rows" in dct:
+ for row in dct["rows"]:
+ if "id" in row:
+ try:
+ idx = int(row['id'])
+ except ValueError:
+ continue
+ source_id = f"source-{external_source_id}-{idx}"
+ row["id"] = source_id
+ if "link" in row:
+ row["link"] = row["link"].replace(str(idx), source_id)
+ return HttpResponse(json.dumps(dct), content_type="application/json")