diff --git a/.env.example b/.env.example index cf39121..37ed087 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,20 @@ DOMAIN=localhost DEMO=false + +STATIC_ROOT=/tmp/static/ +MEDIA_ROOT=/tmp/media/ +ALLOWED_HOSTS=localhost,localhost:8000,127.0.0.1, +DOMAIN=localhost +DEBUG=True +EMAIL_HOST="mail.example.org" +EMAIL_HOST_USER="fillme_noreply" +EMAIL_HOST_PASSWORD="fillme_passwd" +EMAIL_PORT=587 +EMAIL_USE_TLS=True +EMAIL_BACKEND="django.core.mail.backends.smtp.EmailBackend" +EMAIL_FILE_PATH="/tmp/app-messages" +ENABLE_EMAIL=false +PREDEFINED_TOKEN='5018dd65-9abd-4a62-8896-80f34ac66150' +# TODO review these vars +#SNAPSHOTS_DIR=/path/to/TODO +#EVIDENCES_DIR=/path/to/TODO diff --git a/api/views.py b/api/views.py index 175fe3e..69da2a2 100644 --- a/api/views.py +++ b/api/views.py @@ -1,33 +1,27 @@ import json -from django.conf import settings +from uuid import uuid4 + from django.urls import reverse_lazy +from django.http import JsonResponse from django.shortcuts import get_object_or_404, redirect from django.utils.translation import gettext_lazy as _ from django.views.decorators.csrf import csrf_exempt -from django.core.exceptions import ValidationError from django_tables2 import SingleTableView -from django.views.generic.base import View from django.views.generic.edit import ( CreateView, DeleteView, UpdateView, ) -from django.http import JsonResponse -from uuid import uuid4 +from utils.save_snapshots import move_json, save_in_disk from dashboard.mixins import DashboardView from evidence.models import Annotation from evidence.parse import Build -from user.models import User from api.models import Token from api.tables import TokensTable -def save_in_disk(data, user): - pass - - @csrf_exempt def NewSnapshot(request): # Accept only posts @@ -60,15 +54,16 @@ def NewSnapshot(request): ).first() if exist_annotation: - raise ValidationError("error: the snapshot {} exist".format(data['uuid'])) + txt = "error: the snapshot {} exist".format(data['uuid']) + return JsonResponse({'status': txt}, status=500) # Process snapshot - # save_in_disk(data, tk.user) + path_name = save_in_disk(data, tk.owner.institution.name) try: Build(data, tk.owner) - except Exception: - return JsonResponse({'status': 'fail'}, status=200) + except Exception as err: + return JsonResponse({'status': f"fail: {err}"}, status=500) annotation = Annotation.objects.filter( uuid=data['uuid'], @@ -80,19 +75,20 @@ def NewSnapshot(request): if not annotation: - return JsonResponse({'status': 'fail'}, status=200) + return JsonResponse({'status': 'fail'}, status=500) + + url_args = reverse_lazy("device:details", args=(annotation.value,)) + url = request.build_absolute_uri(url_args) - url = "{}://{}{}".format( - request.scheme, - settings.DOMAIN, - reverse_lazy("device:details", args=(annotation.value,)) - ) response = { "status": "success", "dhid": annotation.value[:6].upper(), "url": url, + # TODO replace with public_url when available "public_url": url } + move_json(path_name, tk.owner.institution.name) + return JsonResponse(response, status=200) diff --git a/dashboard/mixins.py b/dashboard/mixins.py index aa63d36..af01a1b 100644 --- a/dashboard/mixins.py +++ b/dashboard/mixins.py @@ -1,4 +1,5 @@ from django.urls import resolve +from django.conf import settings from django.shortcuts import get_object_or_404, redirect, Http404 from django.utils.translation import gettext_lazy as _ from django.core.exceptions import PermissionDenied @@ -32,6 +33,7 @@ class DashboardView(LoginRequiredMixin): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context.update({ + "commit_id": settings.COMMIT, 'title': self.title, 'subtitle': self.subtitle, 'breadcrumb': self.breadcrumb, diff --git a/dashboard/views.py b/dashboard/views.py index b34e2a6..f056523 100644 --- a/dashboard/views.py +++ b/dashboard/views.py @@ -69,23 +69,17 @@ class SearchView(InventaryMixin): if not matches.size(): return self.search_hids(query, offset, limit) - annotations = [] + devices = [] for x in matches: - annotations.extend(self.get_annotations(x)) + devices.append(self.get_annotations(x)) - devices = [Device(id=x) for x in set(annotations)] count = matches.size() return devices, count def get_annotations(self, xp): snap = xp.document.get_data() uuid = json.loads(snap).get('uuid') - - return Annotation.objects.filter( - type=Annotation.Type.SYSTEM, - owner=self.request.user.institution, - uuid=uuid - ).values_list("value", flat=True).distinct() + return Device.get_annotation_from_uuid(uuid, self.request.user.institution) def search_hids(self, query, offset, limit): qry = Q() diff --git a/device/forms.py b/device/forms.py index b2f0d3c..6c4d6e2 100644 --- a/device/forms.py +++ b/device/forms.py @@ -1,5 +1,6 @@ from django import forms from utils.device import create_annotation, create_doc, create_index +from utils.save_snapshots import move_json, save_in_disk DEVICE_TYPES = [ @@ -55,9 +56,12 @@ class BaseDeviceFormSet(forms.BaseFormSet): doc = create_doc(row) if not commit: return doc - + + path_name = save_in_disk(doc, self.user.institution.name, place="placeholder") create_index(doc, self.user) create_annotation(doc, user, commit=commit) + move_json(path_name, self.user.institution.name, place="placeholder") + return doc diff --git a/device/models.py b/device/models.py index 926e447..1f43476 100644 --- a/device/models.py +++ b/device/models.py @@ -90,9 +90,11 @@ class Device: def get_hids(self): annotations = self.get_annotations() + algos = list(ALGOS.keys()) + algos.append('CUSTOM_ID') self.hids = list(set(annotations.filter( type=Annotation.Type.SYSTEM, - key__in=ALGOS.keys(), + key__in=algos, ).values_list("value", flat=True))) def get_evidences(self): @@ -118,9 +120,32 @@ class Device: def get_unassigned(cls, institution, offset=0, limit=None): sql = """ - SELECT DISTINCT t1.value from evidence_annotation as t1 - left join lot_devicelot as t2 on t1.value = t2.device_id - where t2.device_id is null and owner_id=={institution} and type=={type} + WITH RankedAnnotations AS ( + SELECT + t1.value, + t1.key, + ROW_NUMBER() OVER ( + PARTITION BY t1.uuid + ORDER BY + CASE + WHEN t1.key = 'CUSTOM_ID' THEN 1 + WHEN t1.key = 'hidalgo1' THEN 2 + ELSE 3 + END, + t1.created DESC + ) AS row_num + FROM evidence_annotation AS t1 + LEFT JOIN lot_devicelot AS t2 ON t1.value = t2.device_id + WHERE t2.device_id IS NULL + AND t1.owner_id = {institution} + AND t1.type = {type} + ) + SELECT DISTINCT + value + FROM + RankedAnnotations + WHERE + row_num = 1 """.format( institution=institution.id, type=Annotation.Type.SYSTEM, @@ -144,18 +169,83 @@ class Device: def get_unassigned_count(cls, institution): sql = """ - SELECT count(DISTINCT t1.value) from evidence_annotation as t1 - left join lot_devicelot as t2 on t1.value = t2.device_id - where t2.device_id is null and owner_id=={institution} and type=={type}; + WITH RankedAnnotations AS ( + SELECT + t1.value, + t1.key, + ROW_NUMBER() OVER ( + PARTITION BY t1.uuid + ORDER BY + CASE + WHEN t1.key = 'CUSTOM_ID' THEN 1 + WHEN t1.key = 'hidalgo1' THEN 2 + ELSE 3 + END, + t1.created DESC + ) AS row_num + FROM evidence_annotation AS t1 + LEFT JOIN lot_devicelot AS t2 ON t1.value = t2.device_id + WHERE t2.device_id IS NULL + AND t1.owner_id = {institution} + AND t1.type = {type} + ) + SELECT + COUNT(DISTINCT value) + FROM + RankedAnnotations + WHERE + row_num = 1 """.format( institution=institution.id, type=Annotation.Type.SYSTEM, ) - with connection.cursor() as cursor: cursor.execute(sql) return cursor.fetchall()[0][0] + @classmethod + def get_annotation_from_uuid(cls, uuid, institution): + sql = """ + WITH RankedAnnotations AS ( + SELECT + t1.value, + t1.key, + ROW_NUMBER() OVER ( + PARTITION BY t1.uuid + ORDER BY + CASE + WHEN t1.key = 'CUSTOM_ID' THEN 1 + WHEN t1.key = 'hidalgo1' THEN 2 + ELSE 3 + END, + t1.created DESC + ) AS row_num + FROM evidence_annotation AS t1 + LEFT JOIN lot_devicelot AS t2 ON t1.value = t2.device_id + WHERE t2.device_id IS NULL + AND t1.owner_id = {institution} + AND t1.type = {type} + AND t1.uuid = '{uuid}' + ) + SELECT DISTINCT + value + FROM + RankedAnnotations + WHERE + row_num = 1; + """.format( + uuid=uuid.replace("-", ""), + institution=institution.id, + type=Annotation.Type.SYSTEM, + ) + + annotations = [] + with connection.cursor() as cursor: + cursor.execute(sql) + annotations = cursor.fetchall() + + return cls(id=annotations[0][0]) + @property def is_websnapshot(self): if not self.last_evidence: diff --git a/device/templates/details.html b/device/templates/details.html index ee14f75..d5a7448 100644 --- a/device/templates/details.html +++ b/device/templates/details.html @@ -2,9 +2,46 @@ {% load i18n %} {% block content %} -