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 %} -
-
-

{{ object.shortid }}

+
+
+

{{ object.shortid }}

+
+
+ +
+
+ +
+
+
+ +
+
Details
+
+
Phid
+
{{ object.id }}
@@ -228,3 +265,25 @@ }) {% endblock %} + +{% block extrascript %} + +{% endblock %} + diff --git a/dhub/settings.py b/dhub/settings.py index 3b48d2c..5e0131e 100644 --- a/dhub/settings.py +++ b/dhub/settings.py @@ -10,6 +10,7 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/5.0/ref/settings/ """ +import os import xapian from pathlib import Path @@ -35,7 +36,7 @@ assert DOMAIN not in [None, ''], "DOMAIN var is MANDATORY" print("DOMAIN: " + DOMAIN) ALLOWED_HOSTS = config('ALLOWED_HOSTS', default=DOMAIN, cast=Csv()) -assert DOMAIN in ALLOWED_HOSTS, "DOMAIN is not ALLOWED_HOST" +assert DOMAIN in ALLOWED_HOSTS, f"DOMAIN {DOMAIN} is not in ALLOWED_HOSTS {ALLOWED_HOSTS}" CSRF_TRUSTED_ORIGINS = config('CSRF_TRUSTED_ORIGINS', default=f'https://{DOMAIN}', cast=Csv()) @@ -62,6 +63,7 @@ EMAIL_FILE_PATH = config('EMAIL_FILE_PATH', default='/tmp/app-messages') ENABLE_EMAIL = config("ENABLE_EMAIL", default=True, cast=bool) +EVIDENCES_DIR = config("EVIDENCES_DIR", default=os.path.join(BASE_DIR, "db")) # Application definition @@ -156,12 +158,20 @@ AUTH_PASSWORD_VALIDATORS = [ LANGUAGE_CODE = "en-us" -TIME_ZONE = "UTC" +TIME_ZONE = config("TIME_ZONE", default="UTC") USE_I18N = True -USE_TZ = True +USE_TZ = False +if TIME_ZONE == "UTC": + USE_TZ = True + +USE_L10N = True +LANGUAGES = [ + ('es', 'Spanish'), + ('en', 'English'), +] # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/5.0/howto/static-files/ @@ -206,3 +216,4 @@ LOGGING = { SNAPSHOT_PATH="/tmp/" DATA_UPLOAD_MAX_NUMBER_FILES = 1000 +COMMIT = config('COMMIT', default='') diff --git a/docker-compose.yml b/docker-compose.yml index ee59640..d376313 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,9 @@ services: environment: - DEBUG=true - DOMAIN=${DOMAIN:-localhost} - - DEMO=${DEMO:-n} + - ALLOWED_HOSTS=${ALLOWED_HOSTS:-$DOMAIN} + - DEMO=${DEMO:-false} + - PREDEFINED_TOKEN=${PREDEFINED_TOKEN:-} volumes: - .:/opt/devicehub-django ports: diff --git a/docker-reset.sh b/docker-reset.sh index cdbb971..bf14db2 100755 --- a/docker-reset.sh +++ b/docker-reset.sh @@ -9,11 +9,13 @@ set -u set -x main() { + cd "$(dirname "${0}")" + if [ "${DETACH:-}" ]; then detach_arg='-d' fi # remove old database - sudo rm -vf db/* + sudo rm -vfr ./db/* docker compose down -v docker compose build docker compose up ${detach_arg:-} diff --git a/docker/devicehub-django.entrypoint.sh b/docker/devicehub-django.entrypoint.sh index 920cdf0..bdf1008 100644 --- a/docker/devicehub-django.entrypoint.sh +++ b/docker/devicehub-django.entrypoint.sh @@ -12,6 +12,14 @@ check_app_is_there() { } deploy() { + # TODO this is weird, find better workaround + git config --global --add safe.directory /opt/devicehub-django + export COMMIT=$(git log --format="%H %ad" --date=iso -n 1) + + if [ "${DEBUG:-}" = 'true' ]; then + ./manage.py print_settings + fi + # detect if existing deployment (TODO only works with sqlite) if [ -f "${program_dir}/db/db.sqlite3" ]; then echo "INFO: detected EXISTING deployment" @@ -24,11 +32,13 @@ deploy() { INIT_ORG="${INIT_ORG:-example-org}" INIT_USER="${INIT_USER:-user@example.org}" INIT_PASSWD="${INIT_PASSWD:-1234}" + ADMIN='True' + PREDEFINED_TOKEN="${PREDEFINED_TOKEN:-}" ./manage.py add_institution "${INIT_ORG}" # TODO: one error on add_user, and you don't add user anymore - ./manage.py add_user "${INIT_ORG}" "${INIT_USER}" "${INIT_PASSWD}" + ./manage.py add_user "${INIT_ORG}" "${INIT_USER}" "${INIT_PASSWD}" "${ADMIN}" "${PREDEFINED_TOKEN}" - if [ "${DEMO:-}" ]; then + if [ "${DEMO:-}" = 'true' ]; then ./manage.py up_snapshots example/snapshots/ "${INIT_USER}" fi fi @@ -36,7 +46,7 @@ deploy() { runserver() { PORT="${PORT:-8000}" - if [ "${DEBUG:-}" ]; then + if [ "${DEBUG:-}" = 'true' ]; then ./manage.py runserver 0.0.0.0:${PORT} else # TODO diff --git a/evidence/forms.py b/evidence/forms.py index db98f2d..cf90a71 100644 --- a/evidence/forms.py +++ b/evidence/forms.py @@ -9,6 +9,7 @@ from utils.forms import MultipleFileField from device.models import Device from evidence.parse import Build from evidence.models import Annotation +from utils.save_snapshots import move_json, save_in_disk class UploadForm(forms.Form): @@ -48,7 +49,9 @@ class UploadForm(forms.Form): return for ev in self.evidences: + path_name = save_in_disk(ev[1], user.institution.name) Build(ev[1], user) + move_json(path_name, user.institution.name) class UserTagForm(forms.Form): @@ -151,8 +154,11 @@ class ImportForm(forms.Form): if commit: for doc, cred in table: - cred.save() - create_index(doc, self.user) - return table + path_name = save_in_disk(doc, self.user.institution.name, place="placeholder") + + cred.save() + create_index(doc, self.user) + move_json(path_name, self.user.institution.name, place="placeholder") + return table return diff --git a/evidence/models.py b/evidence/models.py index 667945f..35f97aa 100644 --- a/evidence/models.py +++ b/evidence/models.py @@ -67,7 +67,7 @@ class Evidence: for xa in matches: self.doc = json.loads(xa.document.get_data()) - if self.doc.get("software") == "EreuseWorkbench": + if self.doc.get("software") == "workbench-script": dmidecode_raw = self.doc["data"]["dmidecode"] self.dmi = DMIParse(dmidecode_raw) @@ -80,7 +80,7 @@ class Evidence: self.created = self.annotations.last().created def get_components(self): - if self.doc.get("software") != "EreuseWorkbench": + if self.doc.get("software") != "workbench-script": return self.doc.get('components', []) self.set_components() return self.components @@ -92,7 +92,7 @@ class Evidence: return "" return list(self.doc.get('kv').values())[0] - if self.doc.get("software") != "EreuseWorkbench": + if self.doc.get("software") != "workbench-script": return self.doc['device']['manufacturer'] return self.dmi.manufacturer().strip() @@ -104,13 +104,13 @@ class Evidence: return "" return list(self.doc.get('kv').values())[1] - if self.doc.get("software") != "EreuseWorkbench": + if self.doc.get("software") != "workbench-script": return self.doc['device']['model'] return self.dmi.model().strip() def get_chassis(self): - if self.doc.get("software") != "EreuseWorkbench": + if self.doc.get("software") != "workbench-script": return self.doc['device']['model'] chassis = self.dmi.get("Chassis")[0].get("Type", '_virtual') @@ -126,7 +126,8 @@ class Evidence: return Annotation.objects.filter( owner=user.institution, type=Annotation.Type.SYSTEM, - ).order_by("-created").values_list("uuid", flat=True).distinct() + key="hidalgo1", + ).order_by("-created").values_list("uuid", "created").distinct() def set_components(self): snapshot = ParseSnapshot(self.doc).snapshot_json diff --git a/evidence/parse.py b/evidence/parse.py index fa0903c..14f3c1c 100644 --- a/evidence/parse.py +++ b/evidence/parse.py @@ -5,6 +5,8 @@ import hashlib from datetime import datetime from dmidecode import DMIParse +from json_repair import repair_json + from evidence.models import Annotation from evidence.xapian import index from utils.constants import ALGOS, CHASSIS_DH @@ -20,7 +22,12 @@ def get_network_cards(child, nets): def get_mac(lshw): nets = [] try: - get_network_cards(json.loads(lshw), nets) + hw = json.loads(lshw) + except json.decoder.JSONDecodeError: + hw = json.loads(repair_json(lshw)) + + try: + get_network_cards(hw, nets) except Exception as ss: print("WARNING!! {}".format(ss)) return @@ -57,7 +64,7 @@ class Build: } def get_hid_14(self): - if self.json.get("software") == "EreuseWorkbench": + if self.json.get("software") == "workbench-script": hid = self.get_hid(self.json) else: device = self.json['device'] @@ -113,7 +120,8 @@ class Build: # mac = get_mac2(hwinfo_raw) or "" mac = get_mac(lshw) or "" if not mac: - print("WARNING!! No there are MAC address") + print(f"WARNING: Could not retrieve MAC address in snapshot {snapshot['uuid']}" ) + # TODO generate system annotation for that snapshot else: print(f"{manufacturer}{model}{chassis}{serial_number}{sku}{mac}") diff --git a/evidence/parse_details.py b/evidence/parse_details.py index 8465403..57ce4f9 100644 --- a/evidence/parse_details.py +++ b/evidence/parse_details.py @@ -3,6 +3,8 @@ import numpy as np from datetime import datetime from dmidecode import DMIParse +from json_repair import repair_json + from utils.constants import CHASSIS_DH, DATASTORAGEINTERFACE @@ -160,6 +162,7 @@ class ParseSnapshot: continue model = sm.get('model_name') manufacturer = None + hours = sm.get("power_on_time", {}).get("hours", 0) if model and len(model.split(" ")) > 1: mm = model.split(" ") model = mm[-1] @@ -175,6 +178,7 @@ class ParseSnapshot: "size": self.get_data_storage_size(sm), "variant": sm.get("firmware_version"), "interface": self.get_data_storage_interface(sm), + "hours": hours, } ) @@ -478,7 +482,11 @@ class ParseSnapshot: def loads(self, x): if isinstance(x, str): try: - return json.loads(x) + try: + hw = json.loads(lshw) + except json.decoder.JSONDecodeError: + hw = json.loads(repair_json(lshw)) + return hw except Exception as ss: print("WARNING!! {}".format(ss)) return {} diff --git a/evidence/templates/evidences.html b/evidence/templates/evidences.html index c67e9d9..b221d9b 100644 --- a/evidence/templates/evidences.html +++ b/evidence/templates/evidences.html @@ -14,10 +14,13 @@ {% for ev in evidences %} - {{ ev }} + {{ ev.0 }} - + {{ ev.1 }} + + + {% endfor %} diff --git a/login/templates/login.html b/login/templates/login.html index 97ba4cb..a82882e 100644 --- a/login/templates/login.html +++ b/login/templates/login.html @@ -42,4 +42,5 @@ + {% endblock %} diff --git a/login/views.py b/login/views.py index 5bf48a3..beb0368 100644 --- a/login/views.py +++ b/login/views.py @@ -1,5 +1,6 @@ import logging +from django.conf import settings from django.urls import reverse_lazy from django.contrib.auth import views as auth_views from django.contrib.auth import login as auth_login @@ -17,7 +18,7 @@ class LoginView(auth_views.LoginView): extra_context = { 'title': _('Login'), 'success_url': reverse_lazy('dashboard:unassigned_devices'), - # 'commit_id': settings.COMMIT, + 'commit_id': settings.COMMIT, } def get(self, request, *args, **kwargs): @@ -65,7 +66,6 @@ class PasswordResetView(auth_views.PasswordResetView): success_url = reverse_lazy('login:password_reset_done') def form_valid(self, form): - import pdb; pdb.set_trace() try: response = super().form_valid(form) return response diff --git a/lot/models.py b/lot/models.py index 764e134..6c81bfd 100644 --- a/lot/models.py +++ b/lot/models.py @@ -31,7 +31,7 @@ class Lot(models.Model): name = models.CharField(max_length=STR_SIZE, blank=True, null=True) code = models.CharField(max_length=STR_SIZE, blank=True, null=True) description = models.CharField(max_length=STR_SIZE, blank=True, null=True) - closed = models.BooleanField(default=True) + closed = models.BooleanField(default=False) owner = models.ForeignKey(Institution, on_delete=models.CASCADE) user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True) type = models.ForeignKey(LotTag, on_delete=models.CASCADE) diff --git a/lot/templates/lots.html b/lot/templates/lots.html index e091dd4..2aa866d 100644 --- a/lot/templates/lots.html +++ b/lot/templates/lots.html @@ -7,6 +7,16 @@

{{ subtitle }}

+ {% if show_closed %} + + {% trans 'Hide closed lots' %} + + {% else %} + + {% trans 'Show closed lots' %} + + {% endif %} + {% trans 'Add new lot' %} diff --git a/lot/views.py b/lot/views.py index e9bb081..182aade 100644 --- a/lot/views.py +++ b/lot/views.py @@ -131,11 +131,13 @@ class LotsTagsView(DashboardView, TemplateView): tag = get_object_or_404(LotTag, owner=self.request.user.institution, id=self.pk) self.title += " {}".format(tag.name) self.breadcrumb += " {}".format(tag.name) - lots = Lot.objects.filter(owner=self.request.user.institution).filter(type=tag) + show_closed = self.request.GET.get('show_closed', 'false') == 'true' + lots = Lot.objects.filter(owner=self.request.user.institution).filter(type=tag, closed=show_closed) context.update({ 'lots': lots, 'title': self.title, - 'breadcrumb': self.breadcrumb + 'breadcrumb': self.breadcrumb, + 'show_closed': show_closed }) return context diff --git a/requirements.txt b/requirements.txt index 1576d4f..32b8e86 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,4 +10,4 @@ pandas==2.2.2 xlrd==2.0.1 odfpy==1.4.1 pytz==2024.2 - +json-repair==0.30.0 diff --git a/user/management/commands/add_user.py b/user/management/commands/add_user.py index 60f3dd2..6593fee 100644 --- a/user/management/commands/add_user.py +++ b/user/management/commands/add_user.py @@ -17,15 +17,17 @@ class Command(BaseCommand): parser.add_argument('email', type=str, help='email') parser.add_argument('password', type=str, help='password') parser.add_argument('is_admin', nargs='?', default=False, type=str, help='is admin') + parser.add_argument('predefined_token', nargs='?', default='', type=str, help='predefined token') def handle(self, *args, **kwargs): email = kwargs['email'] password = kwargs['password'] is_admin = kwargs['is_admin'] + predefined_token = kwargs['predefined_token'] institution = Institution.objects.get(name=kwargs['institution']) - self.create_user(institution, email, password, is_admin) + self.create_user(institution, email, password, is_admin, predefined_token) - def create_user(self, institution, email, password, is_admin): + def create_user(self, institution, email, password, is_admin, predefined_token): self.u = User.objects.create( institution=institution, email=email, @@ -34,6 +36,10 @@ class Command(BaseCommand): ) self.u.set_password(password) self.u.save() - token = uuid4() + if predefined_token: + token = predefined_token + else: + token = uuid4() + Token.objects.create(token=token, owner=self.u) print(f"TOKEN: {token}") diff --git a/utils/save_snapshots.py b/utils/save_snapshots.py new file mode 100644 index 0000000..8c02f06 --- /dev/null +++ b/utils/save_snapshots.py @@ -0,0 +1,43 @@ +import os +import json +import shutil + +from datetime import datetime +from django.conf import settings + + +def move_json(path_name, user, place="snapshots"): + if place != "snapshots": + place = "placeholders" + + tmp_snapshots = settings.EVIDENCES_DIR + path_dir = os.path.join(tmp_snapshots, user, place) + + if os.path.isfile(path_name): + shutil.copy(path_name, path_dir) + os.remove(path_name) + + +def save_in_disk(data, user, place="snapshots"): + uuid = data.get('uuid', '') + now = datetime.now() + year = now.year + month = now.month + day = now.day + hour = now.hour + minutes = now.minute + tmp_snapshots = settings.EVIDENCES_DIR + if place != "snapshots": + place = "placeholders" + + name_file = f"{year}-{month}-{day}-{hour}-{minutes}_{uuid}.json" + path_dir = os.path.join(tmp_snapshots, user, place, "errors") + path_name = os.path.join(path_dir, name_file) + + if not os.path.isdir(path_dir): + os.system(f'mkdir -p {path_dir}') + + with open(path_name, 'w') as snapshot_file: + snapshot_file.write(json.dumps(data)) + + return path_name