From 9cdea3c45f9c2cfd295194c06d6019616b0150aa Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Sat, 13 Jul 2024 15:27:26 +0200 Subject: [PATCH 01/26] upload form --- snapshot/views.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/snapshot/views.py b/snapshot/views.py index 8202bc3..8a84d7c 100644 --- a/snapshot/views.py +++ b/snapshot/views.py @@ -1,7 +1,11 @@ from django.utils.translation import gettext_lazy as _ from django.views.generic.base import TemplateView +from django.views.generic.edit import FormView +from django.urls import reverse_lazy + from dashboard.mixins import DashboardView from snapshot.models import Snapshot +from snapshot.forms import UploadForm # from django.shortcuts import render # from rest_framework import viewsets # from snapshot.serializers import SnapshotSerializer @@ -25,3 +29,12 @@ class ListSnapshotsView(DashboardView, TemplateView): 'snapshots': snapshots, }) return context + + +class UploadView(DashboardView, FormView): + template_name = "upload.html" + section = "snapshots" + title = _("Upload Snapshot") + breadcrumb = "Snapshots / Upload" + success_url = reverse_lazy('snashot:list') + form_class = UploadForm -- 2.30.2 From 12baa6f5386c69d1b639dad8cf9dda37d52891e7 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Sat, 13 Jul 2024 15:27:36 +0200 Subject: [PATCH 02/26] upload form --- snapshot/forms.py | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 snapshot/forms.py diff --git a/snapshot/forms.py b/snapshot/forms.py new file mode 100644 index 0000000..063c115 --- /dev/null +++ b/snapshot/forms.py @@ -0,0 +1,8 @@ + + + +class UploadForm(forms.Form): + snapshot_file = forms.FileField(label=_("File")) + + def clean(self): + data = self.cleaned_data -- 2.30.2 From e135fd9d288e1d786d9b6286e67a47e7170f6a35 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 15 Jul 2024 16:23:14 +0200 Subject: [PATCH 03/26] new version with xapian --- dashboard/mixins.py | 4 +- dashboard/templates/unassigned_devices.html | 4 +- dashboard/views.py | 30 +- device/templates/details.html | 21 +- device/urls.py | 6 +- device/views.py | 30 +- dhub/settings.py | 5 +- snapshot/migrations/0004_anotation.py | 41 ++ .../0005_annotation_delete_anotation.py | 44 ++ snapshot/models.py | 10 +- snapshot/parse.py | 677 +----------------- snapshot/views.py | 16 +- snapshot/xapian.py | 22 + utils/constants.py | 1 + 14 files changed, 233 insertions(+), 678 deletions(-) create mode 100644 snapshot/migrations/0004_anotation.py create mode 100644 snapshot/migrations/0005_annotation_delete_anotation.py create mode 100644 snapshot/xapian.py diff --git a/dashboard/mixins.py b/dashboard/mixins.py index a6c372c..df9d6d1 100644 --- a/dashboard/mixins.py +++ b/dashboard/mixins.py @@ -61,7 +61,7 @@ class DetailsMixin(DashboardView, TemplateView): }) return context - + class InventaryMixin(DashboardView, TemplateView): def post(self, request, *args, **kwargs): @@ -76,5 +76,3 @@ class InventaryMixin(DashboardView, TemplateView): except Exception: pass return super().get(request, *args, **kwargs) - - diff --git a/dashboard/templates/unassigned_devices.html b/dashboard/templates/unassigned_devices.html index bc1365f..df71266 100644 --- a/dashboard/templates/unassigned_devices.html +++ b/dashboard/templates/unassigned_devices.html @@ -44,7 +44,9 @@ - {{ dev.type }} {{ dev.manufacturer }} {{ dev.model }} + + {{ dev.type }} {{ dev.manufacturer }} {{ dev.model }} + diff --git a/dashboard/views.py b/dashboard/views.py index 16c34b1..c42d997 100644 --- a/dashboard/views.py +++ b/dashboard/views.py @@ -1,7 +1,11 @@ +import json + from django.utils.translation import gettext_lazy as _ from django.db.models import Count from dashboard.mixins import InventaryMixin, DetailsMixin from device.models import Device +from snapshot.xapian import search +from snapshot.models import Annotation from lot.models import Lot @@ -13,11 +17,29 @@ class UnassignedDevicesView(InventaryMixin): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - devices = Device.objects.filter( - owner=self.request.user - ).annotate(num_lots=Count('lot')).filter(num_lots=0) + annotations = Annotation.objects.filter( + owner=self.request.user).filter( + key="hidalgo1").order_by('created') + # 'created').distinct('value') + # ).annotate(num_lots=Count('lot')).filter(num_lots=0) + + hids = {} + ids = [] + for x in annotations: + if not hids.get(x.key): + hids[x.key] = x.uuid + ids.append(str(x.uuid)) + + devices = [] + for xa in search(ids): + # import pdb; pdb.set_trace() + snap = json.loads(xa.document.get_data()) + dev = snap.get("device", {}) + dev["id"] = snap["uuid"] + devices.append(dev) + context.update({ - 'devices': devices, + 'devices': devices }) return context diff --git a/device/templates/details.html b/device/templates/details.html index f5d484d..28261a8 100644 --- a/device/templates/details.html +++ b/device/templates/details.html @@ -4,7 +4,7 @@ {% block content %}
-

{{ object.pk }}

+

{{ object.uuid }}

@@ -45,16 +45,16 @@
Details
- {%if object.hid %}Snapshot{% else %}Placeholder{% endif %} + {% if object.hid %}Snapshot{% else %}Placeholder{% endif %}
Phid
-
{{ object.id }}
+
{{ object.uuid }}
@@ -69,22 +69,17 @@
Manufacturer
-
{{ object.manufacturer|default:"" }}
+
{{ object.device.manufacturer|default:"" }}
Model
-
{{ object.model|default:"" }}
-
- -
-
Part Number
-
{{ object.part_number|default:"" }}
+
{{ object.device.model|default:"" }}
Serial Number
-
{{ object.serial_number|default:"" }}
+
{{ object.device.serialNumber|default:"" }}
@@ -92,7 +87,7 @@
Physical Properties
diff --git a/device/urls.py b/device/urls.py index 8445449..33260e9 100644 --- a/device/urls.py +++ b/device/urls.py @@ -5,7 +5,7 @@ app_name = 'device' urlpatterns = [ path("add/", views.NewDeviceView.as_view(), name="add"), - path("edit//", views.EditDeviceView.as_view(), name="edit"), - path("/", views.DetailsView.as_view(), name="details"), - path("physical//", views.PhysicalView.as_view(), name="physical_edit"), + path("edit//", views.EditDeviceView.as_view(), name="edit"), + path("/", views.DetailsView.as_view(), name="details"), + path("physical//", views.PhysicalView.as_view(), name="physical_edit"), ] diff --git a/device/views.py b/device/views.py index 249ee1e..0285529 100644 --- a/device/views.py +++ b/device/views.py @@ -1,3 +1,5 @@ +import json + from django.urls import reverse_lazy from django.shortcuts import get_object_or_404 from django.utils.translation import gettext_lazy as _ @@ -5,7 +7,10 @@ from django.views.generic.edit import ( CreateView, UpdateView, ) +from django.views.generic.base import TemplateView from dashboard.mixins import DashboardView, DetailsMixin +from snapshot.models import Annotation +from snapshot.xapian import search from device.models import Device, PhysicalProperties @@ -64,12 +69,35 @@ class EditDeviceView(DashboardView, UpdateView): return kwargs -class DetailsView(DetailsMixin): +class DetailsView2(DetailsMixin): template_name = "details.html" title = _("Device") breadcrumb = "Device / Details" model = Device +class DetailsView(DashboardView, TemplateView): + template_name = "details.html" + title = _("Device") + breadcrumb = "Device / Details" + + def get(self, request, *args, **kwargs): + # import pdb; pdb.set_trace() + self.pk = kwargs['pk'] + annotation = get_object_or_404(Annotation, owner=self.request.user, uuid=self.pk) + for xa in search([str(self.pk)]): + self.object = json.loads(xa.document.get_data()) + return super().get(request, *args, **kwargs) + + return super().get(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context.update({ + 'object': self.object, + }) + return context + + class PhysicalView(DashboardView, UpdateView): template_name = "physical_properties.html" diff --git a/dhub/settings.py b/dhub/settings.py index 0dc2788..6444f43 100644 --- a/dhub/settings.py +++ b/dhub/settings.py @@ -10,6 +10,8 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/5.0/ref/settings/ """ +import xapian + from pathlib import Path from django.contrib.messages import constants as messages from decouple import config, Csv @@ -92,11 +94,10 @@ WSGI_APPLICATION = "dhub.wsgi.application" DATABASES = { "default": { "ENGINE": "django.db.backends.sqlite3", - "NAME": BASE_DIR / "db.sqlite3", + "NAME": BASE_DIR / "db/db.sqlite3", } } - # Password validation # https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators diff --git a/snapshot/migrations/0004_anotation.py b/snapshot/migrations/0004_anotation.py new file mode 100644 index 0000000..f2e6887 --- /dev/null +++ b/snapshot/migrations/0004_anotation.py @@ -0,0 +1,41 @@ +# Generated by Django 5.0.6 on 2024-07-15 09:20 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("snapshot", "0003_remove_snapshot_start_time"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="anotation", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("created", models.DateTimeField(auto_now_add=True)), + ("uuid", models.UUIDField(unique=True)), + ("key", models.CharField(max_length=256)), + ("value", models.CharField(max_length=256)), + ( + "owner", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + ), + ] diff --git a/snapshot/migrations/0005_annotation_delete_anotation.py b/snapshot/migrations/0005_annotation_delete_anotation.py new file mode 100644 index 0000000..10c2ded --- /dev/null +++ b/snapshot/migrations/0005_annotation_delete_anotation.py @@ -0,0 +1,44 @@ +# Generated by Django 5.0.6 on 2024-07-15 09:21 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("snapshot", "0004_anotation"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="Annotation", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("created", models.DateTimeField(auto_now_add=True)), + ("uuid", models.UUIDField(unique=True)), + ("key", models.CharField(max_length=256)), + ("value", models.CharField(max_length=256)), + ( + "owner", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + ), + migrations.DeleteModel( + name="anotation", + ), + ] diff --git a/snapshot/models.py b/snapshot/models.py index 72919ee..868b25a 100644 --- a/snapshot/models.py +++ b/snapshot/models.py @@ -1,5 +1,5 @@ from django.db import models -from utils.constants import STR_SM_SIZE +from utils.constants import STR_SM_SIZE, STR_EXTEND_SIZE from user.models import User from device.models import Computer, Component @@ -29,3 +29,11 @@ class Snapshot(models.Model): computer = models.ForeignKey(Computer, on_delete=models.CASCADE) components = models.ManyToManyField(Component) + +class Annotation(models.Model): + created = models.DateTimeField(auto_now_add=True) + uuid = models.UUIDField(unique=True) + owner = models.ForeignKey(User, on_delete=models.CASCADE) + key = models.CharField(max_length=STR_EXTEND_SIZE) + value = models.CharField(max_length=STR_EXTEND_SIZE) + diff --git a/snapshot/parse.py b/snapshot/parse.py index b09c5fa..f6ce559 100644 --- a/snapshot/parse.py +++ b/snapshot/parse.py @@ -1,15 +1,15 @@ import os import json import shutil +import xapian import hashlib from datetime import datetime -from django.conf import settings -from device.models import Device, Computer -from snapshot.models import Snapshot +from snapshot.models import Snapshot, Annotation +from snapshot.xapian import search, indexer, database -HID = [ +HID_ALGO1 = [ "manufacturer", "model", "chassis", @@ -23,651 +23,44 @@ class Build: self.json = snapshot_json self.user = user self.hid = None - self.result = False - self.save_disk() - self.json_device = self.json["device"] - self.json_components = self.json["components"] - self.uuid = self.json["uuid"] - self.get_hid() - self.gen_computer() - self.gen_components() - self.gen_actions() - self.gen_snapshot() + self.index() + self.create_annotation() - self.result = True - self.move_json() - - def save_disk(self): - snapshot_path = settings.SNAPSHOT_PATH - user = self.user.email - uuid = self.json.get("uuid", "") - now = datetime.now().strftime("%Y-%m-%d-%H-%M") - filename = f"{now}_{user}_{uuid}.json" - path_dir_base = os.path.join(snapshot_path, user) - path_upload = os.path.join(path_dir_base, 'upload') - path_name = os.path.join(path_upload, filename) - self.filename = path_name - self.path_dir_base = path_dir_base - - if not os.path.isdir(path_dir_base): - os.system(f'mkdir -p {path_upload}') - - with open(path_name, 'w') as file: - file.write(json.dumps(self.json)) - - def move_json(self): - if not self.result: + def index(self): + matches = search(self.json['uuid'], limit=1) + if matches.size() > 0: return - shutil.copy(self.filename, self.path_dir_base) - os.remove(self.filename) + snap = json.dumps(self.json) + doc = xapian.Document() + doc.set_data(snap) - def get_hid(self): - hid = "" - for f in HID: - hid += "-" + self.json_device[f] - self.hid = hid + indexer.set_document(doc) + indexer.index_text(snap) - def gen_computer(self): - self.device = Device.objects.filter( - hid=self.hid, - active=True, - reliable=True, - owner=self.user - ).first() + # Add the document to the database. + database.add_document(doc) - if self.device: - return + def get_hid_14(self): + device = self.json['device'] + manufacturer = device.get("manufacturer", '') + model = device.get("model", '') + chassis = device.get("chassis", '') + serial_number = device.get("serialNumber", '') + sku = device.get("sku", '') + hid = f"{manufacturer}{model}{chassis}{serial_number}{sku}" + return hashlib.sha3_256(hid.encode()).hexdigest() - chid = hashlib.sha3_256(self.hid.encode()).hexdigest() - self.device = Device.objects.create( - serial_number=self.json_device["serialNumber"], - manufacturer=self.json_device["manufacturer"], - version=self.json_device["version"], - model=self.json_device["model"], - type=self.json_device["type"], - hid=self.hid, - chid=chid, - owner=self.user + def create_annotation(self): + uuid = self.json['uuid'] + owner = self.user + key = 'hidalgo1' + value = self.get_hid_14() + Annotation.objects.create( + uuid=uuid, + owner=owner, + key=key, + value=value ) - Computer.objects.create( - device=self.device, - sku=self.json_device["sku"], - chassis=self.json_device["chassis"] - ) - - def gen_snapshot(self): - self.snapshot = Snapshot.objects.create( - uuid = self.uuid, - version = self.json["version"], - computer = self.device.computer, - sid = self.json.get("sid", ""), - settings_version = self.json.get("settings_version", ""), - end_time = self.json.get("endTime"), - owner=self.user - ) - - def gen_components(self): - pass - - def gen_actions(self): - pass - - -# class ParseSnapshot: -# def __init__(self, snapshot, default="n/a"): -# self.default = default -# self.dmidecode_raw = snapshot["hwmd"]["dmidecode"] -# self.smart_raw = snapshot["hwmd"]["smart"] -# self.hwinfo_raw = snapshot["hwmd"]["hwinfo"] -# self.lshw_raw = snapshot["hwmd"]["lshw"] -# self.lscpi_raw = snapshot["hwmd"]["lspci"] -# self.sanitize_raw = snapshot.get("sanitize", []) -# self.device = {"actions": []} -# self.components = [] -# self.monitors = [] - -# self.dmi = DMIParse(self.dmidecode_raw) -# self.smart = self.loads(self.smart_raw) -# self.lshw = self.loads(self.lshw_raw) -# self.hwinfo = self.parse_hwinfo() - -# self.set_computer() -# self.get_hwinfo_monitors() -# self.set_components() -# self.snapshot_json = { -# "type": "Snapshot", -# "device": self.device, -# "software": "Workbench", -# # "software": snapshot["software"], -# "components": self.components, -# "uuid": snapshot['uuid'], -# "version": "15.0.0", -# # "version": snapshot['version'], -# "settings_version": snapshot['settings_version'], -# "endTime": snapshot["timestamp"], -# "elapsed": 1, -# "sid": snapshot["sid"], -# } - -# def get_snapshot(self): -# return Snapshot().load(self.snapshot_json) - -# def set_computer(self): -# self.device['manufacturer'] = self.dmi.manufacturer().strip() -# self.device['model'] = self.dmi.model().strip() -# self.device['serialNumber'] = self.dmi.serial_number() -# self.device['type'] = self.get_type() -# self.device['sku'] = self.get_sku() -# self.device['version'] = self.get_version() -# self.device['system_uuid'] = self.get_uuid() -# self.device['family'] = self.get_family() -# self.device['chassis'] = self.get_chassis_dh() - -# def set_components(self): -# self.get_cpu() -# self.get_ram() -# self.get_mother_board() -# self.get_graphic() -# self.get_data_storage() -# self.get_display() -# self.get_sound_card() -# self.get_networks() - -# def get_cpu(self): -# for cpu in self.dmi.get('Processor'): -# serial = cpu.get('Serial Number') -# if serial == 'Not Specified' or not serial: -# serial = cpu.get('ID').replace(' ', '') -# self.components.append( -# { -# "actions": [], -# "type": "Processor", -# "speed": self.get_cpu_speed(cpu), -# "cores": int(cpu.get('Core Count', 1)), -# "model": cpu.get('Version'), -# "threads": int(cpu.get('Thread Count', 1)), -# "manufacturer": cpu.get('Manufacturer'), -# "serialNumber": serial, -# "generation": None, -# "brand": cpu.get('Family'), -# "address": self.get_cpu_address(cpu), -# } -# ) - -# def get_ram(self): -# for ram in self.dmi.get("Memory Device"): -# if ram.get('size') == 'No Module Installed': -# continue -# if not ram.get("Speed"): -# continue - -# self.components.append( -# { -# "actions": [], -# "type": "RamModule", -# "size": self.get_ram_size(ram), -# "speed": self.get_ram_speed(ram), -# "manufacturer": ram.get("Manufacturer", self.default), -# "serialNumber": ram.get("Serial Number", self.default), -# "interface": ram.get("Type", "DDR"), -# "format": ram.get("Form Factor", "DIMM"), -# "model": ram.get("Part Number", self.default), -# } -# ) - -# def get_mother_board(self): -# for moder_board in self.dmi.get("Baseboard"): -# self.components.append( -# { -# "actions": [], -# "type": "Motherboard", -# "version": moder_board.get("Version"), -# "serialNumber": moder_board.get("Serial Number", "").strip(), -# "manufacturer": moder_board.get("Manufacturer", "").strip(), -# "biosDate": self.get_bios_date(), -# "ramMaxSize": self.get_max_ram_size(), -# "ramSlots": len(self.dmi.get("Memory Device")), -# "slots": self.get_ram_slots(), -# "model": moder_board.get("Product Name", "").strip(), -# "firewire": self.get_firmware_num(), -# "pcmcia": self.get_pcmcia_num(), -# "serial": self.get_serial_num(), -# "usb": self.get_usb_num(), -# } -# ) - -# def get_graphic(self): -# nodes = get_nested_dicts_with_key_value(self.lshw, 'class', 'display') -# for c in nodes: -# if not c['configuration'].get('driver', None): -# continue - -# self.components.append( -# { -# "actions": [], -# "type": "GraphicCard", -# "memory": self.get_memory_video(c), -# "manufacturer": c.get("vendor", self.default), -# "model": c.get("product", self.default), -# "serialNumber": c.get("serial", self.default), -# } -# ) - -# def get_memory_video(self, c): -# # get info of lspci -# # pci_id = c['businfo'].split('@')[1] -# # lspci.get(pci_id) | grep size -# # lspci -v -s 00:02.0 -# return None - -# def get_data_storage(self): -# for sm in self.smart: -# if sm.get('smartctl', {}).get('exit_status') == 1: -# continue -# model = sm.get('model_name') -# manufacturer = None -# if model and len(model.split(" ")) > 1: -# mm = model.split(" ") -# model = mm[-1] -# manufacturer = " ".join(mm[:-1]) - -# self.components.append( -# { -# "actions": self.sanitize(sm), -# "type": self.get_data_storage_type(sm), -# "model": model, -# "manufacturer": manufacturer, -# "serialNumber": sm.get('serial_number'), -# "size": self.get_data_storage_size(sm), -# "variant": sm.get("firmware_version"), -# "interface": self.get_data_storage_interface(sm), -# } -# ) - -# def sanitize(self, disk): -# disk_sanitize = None -# for d in self.sanitize_raw: -# s = d.get('device_info', {}).get('export_data', {}) -# s = s.get('block', {}).get('serial') -# if s == disk.get('serial_number'): -# disk_sanitize = d -# break -# if not disk_sanitize: -# return [] - -# steps = [] -# step_type = 'EraseBasic' -# if d.get("method", {}).get('name') == 'Baseline Cryptographic': -# step_type = 'EraseCrypto' - -# if disk.get('type') == 'EraseCrypto': -# step_type = 'EraseCrypto' - -# erase = { -# 'type': step_type, -# 'severity': "Info", -# 'steps': steps, -# 'startTime': None, -# 'endTime': None, -# } -# severities = [] - -# for step in disk_sanitize.get('steps', []): -# severity = "Info" -# if not step['success']: -# severity = "Error" - -# steps.append( -# { -# 'severity': severity, -# 'startTime': unix_isoformat(step['start_time']), -# 'endTime': unix_isoformat(step['end_time']), -# 'type': 'StepRandom', -# } -# ) -# severities.append(severity) - -# erase['endTime'] = unix_isoformat(step['end_time']) -# if not erase['startTime']: -# erase['startTime'] = unix_isoformat(step['start_time']) - -# if "Error" in severities: -# erase['severity'] = "Error" - -# return [erase] - -# def get_networks(self): -# nodes = get_nested_dicts_with_key_value(self.lshw, 'class', 'network') -# for c in nodes: -# capacity = c.get('capacity') -# units = c.get('units') -# speed = None -# if capacity and units: -# speed = unit.Quantity(capacity, units).to('Mbit/s').m -# wireless = bool(c.get('configuration', {}).get('wireless', False)) -# self.components.append( -# { -# "actions": [], -# "type": "NetworkAdapter", -# "model": c.get('product'), -# "manufacturer": c.get('vendor'), -# "serialNumber": c.get('serial'), -# "speed": speed, -# "variant": c.get('version', 1), -# "wireless": wireless, -# } -# ) - -# def get_sound_card(self): -# nodes = get_nested_dicts_with_key_value(self.lshw, 'class', 'multimedia') -# for c in nodes: -# self.components.append( -# { -# "actions": [], -# "type": "SoundCard", -# "model": c.get('product'), -# "manufacturer": c.get('vendor'), -# "serialNumber": c.get('serial'), -# } -# ) - -# def get_display(self): # noqa: C901 -# TECHS = 'CRT', 'TFT', 'LED', 'PDP', 'LCD', 'OLED', 'AMOLED' - -# for c in self.monitors: -# resolution_width, resolution_height = (None,) * 2 -# refresh, serial, model, manufacturer, size = (None,) * 5 -# year, week, production_date = (None,) * 3 - -# for x in c: -# if "Vendor: " in x: -# manufacturer = x.split('Vendor: ')[-1].strip() -# if "Model: " in x: -# model = x.split('Model: ')[-1].strip() -# if "Serial ID: " in x: -# serial = x.split('Serial ID: ')[-1].strip() -# if " Resolution: " in x: -# rs = x.split(' Resolution: ')[-1].strip() -# if 'x' in rs: -# resolution_width, resolution_height = [ -# int(r) for r in rs.split('x') -# ] -# if "Frequencies: " in x: -# try: -# refresh = int(float(x.split(',')[-1].strip()[:-3])) -# except Exception: -# pass -# if 'Year of Manufacture' in x: -# year = x.split(': ')[1] - -# if 'Week of Manufacture' in x: -# week = x.split(': ')[1] - -# if "Size: " in x: -# size = self.get_size_monitor(x) -# technology = next((t for t in TECHS if t in c[0]), None) - -# if year and week: -# d = '{} {} 0'.format(year, week) -# production_date = datetime.strptime(d, '%Y %W %w').isoformat() - -# self.components.append( -# { -# "actions": [], -# "type": "Display", -# "model": model, -# "manufacturer": manufacturer, -# "serialNumber": serial, -# 'size': size, -# 'resolutionWidth': resolution_width, -# 'resolutionHeight': resolution_height, -# "productionDate": production_date, -# 'technology': technology, -# 'refreshRate': refresh, -# } -# ) - -# def get_hwinfo_monitors(self): -# for c in self.hwinfo: -# monitor = None -# external = None -# for x in c: -# if 'Hardware Class: monitor' in x: -# monitor = c -# if 'Driver Info' in x: -# external = c - -# if monitor and not external: -# self.monitors.append(c) - -# def get_size_monitor(self, x): -# i = 1 / 25.4 -# t = x.split('Size: ')[-1].strip() -# tt = t.split('mm') -# if not tt: -# return 0 -# sizes = tt[0].strip() -# if 'x' not in sizes: -# return 0 -# w, h = [int(x) for x in sizes.split('x')] -# return numpy.sqrt(w**2 + h**2) * i - -# def get_cpu_address(self, cpu): -# default = 64 -# for ch in self.lshw.get('children', []): -# for c in ch.get('children', []): -# if c['class'] == 'processor': -# return c.get('width', default) -# return default - -# def get_usb_num(self): -# return len( -# [ -# u -# for u in self.dmi.get("Port Connector") -# if "USB" in u.get("Port Type", "").upper() -# ] -# ) - -# def get_serial_num(self): -# return len( -# [ -# u -# for u in self.dmi.get("Port Connector") -# if "SERIAL" in u.get("Port Type", "").upper() -# ] -# ) - -# def get_firmware_num(self): -# return len( -# [ -# u -# for u in self.dmi.get("Port Connector") -# if "FIRMWARE" in u.get("Port Type", "").upper() -# ] -# ) - -# def get_pcmcia_num(self): -# return len( -# [ -# u -# for u in self.dmi.get("Port Connector") -# if "PCMCIA" in u.get("Port Type", "").upper() -# ] -# ) - -# def get_bios_date(self): -# return self.dmi.get("BIOS")[0].get("Release Date", self.default) - -# def get_firmware(self): -# return self.dmi.get("BIOS")[0].get("Firmware Revision", '1') - -# def get_max_ram_size(self): -# size = 0 -# for slot in self.dmi.get("Physical Memory Array"): -# capacity = slot.get("Maximum Capacity", '0').split(" ")[0] -# size += int(capacity) - -# return size - -# def get_ram_slots(self): -# slots = 0 -# for x in self.dmi.get("Physical Memory Array"): -# slots += int(x.get("Number Of Devices", 0)) -# return slots - -# def get_ram_size(self, ram): -# try: -# memory = ram.get("Size", "0") -# memory = memory.split(' ') -# if len(memory) > 1: -# size = int(memory[0]) -# units = memory[1] -# return base2.Quantity(size, units).to('MiB').m -# return int(size.split(" ")[0]) -# except Exception as err: -# logger.error("get_ram_size error: {}".format(err)) -# return 0 - -# def get_ram_speed(self, ram): -# size = ram.get("Speed", "0") -# return int(size.split(" ")[0]) - -# def get_cpu_speed(self, cpu): -# speed = cpu.get('Max Speed', "0") -# return float(speed.split(" ")[0]) / 1024 - -# def get_sku(self): -# return self.dmi.get("System")[0].get("SKU Number", self.default).strip() - -# def get_version(self): -# return self.dmi.get("System")[0].get("Version", self.default).strip() - -# def get_uuid(self): -# return self.dmi.get("System")[0].get("UUID", '').strip() - -# def get_family(self): -# return self.dmi.get("System")[0].get("Family", '') - -# def get_chassis(self): -# return self.dmi.get("Chassis")[0].get("Type", '_virtual') - -# def get_type(self): -# chassis_type = self.get_chassis() -# return self.translation_to_devicehub(chassis_type) - -# def translation_to_devicehub(self, original_type): -# lower_type = original_type.lower() -# CHASSIS_TYPE = { -# 'Desktop': [ -# 'desktop', -# 'low-profile', -# 'tower', -# 'docking', -# 'all-in-one', -# 'pizzabox', -# 'mini-tower', -# 'space-saving', -# 'lunchbox', -# 'mini', -# 'stick', -# ], -# 'Laptop': [ -# 'portable', -# 'laptop', -# 'convertible', -# 'tablet', -# 'detachable', -# 'notebook', -# 'handheld', -# 'sub-notebook', -# ], -# 'Server': ['server'], -# 'Computer': ['_virtual'], -# } -# for k, v in CHASSIS_TYPE.items(): -# if lower_type in v: -# return k -# return self.default - -# def get_chassis_dh(self): -# CHASSIS_DH = { -# 'Tower': {'desktop', 'low-profile', 'tower', 'server'}, -# 'Docking': {'docking'}, -# 'AllInOne': {'all-in-one'}, -# 'Microtower': {'mini-tower', 'space-saving', 'mini'}, -# 'PizzaBox': {'pizzabox'}, -# 'Lunchbox': {'lunchbox'}, -# 'Stick': {'stick'}, -# 'Netbook': {'notebook', 'sub-notebook'}, -# 'Handheld': {'handheld'}, -# 'Laptop': {'portable', 'laptop'}, -# 'Convertible': {'convertible'}, -# 'Detachable': {'detachable'}, -# 'Tablet': {'tablet'}, -# 'Virtual': {'_virtual'}, -# } - -# chassis = self.get_chassis() -# lower_type = chassis.lower() -# for k, v in CHASSIS_DH.items(): -# if lower_type in v: -# return k -# return self.default - -# def get_data_storage_type(self, x): -# # TODO @cayop add more SSDS types -# SSDS = ["nvme"] -# SSD = 'SolidStateDrive' -# HDD = 'HardDrive' -# type_dev = x.get('device', {}).get('type') -# trim = x.get('trim', {}).get("supported") in [True, "true"] -# return SSD if type_dev in SSDS or trim else HDD - -# def get_data_storage_interface(self, x): -# interface = x.get('device', {}).get('protocol', 'ATA') -# try: -# DataStorageInterface(interface.upper()) -# except ValueError as err: -# txt = "Sid: {}, interface {} is not in DataStorageInterface Enum".format( -# self.sid, interface -# ) -# self.errors("{}".format(err)) -# self.errors(txt, severity=Severity.Warning) -# return "ATA" - -# def get_data_storage_size(self, x): -# total_capacity = x.get('user_capacity', {}).get('bytes') -# if not total_capacity: -# return 1 -# # convert bytes to Mb -# return total_capacity / 1024**2 - -# def parse_hwinfo(self): -# hw_blocks = self.hwinfo_raw.split("\n\n") -# return [x.split("\n") for x in hw_blocks] - -# def loads(self, x): -# if isinstance(x, str): -# return json.loads(x) -# return x - -# def errors(self, txt=None, severity=Severity.Error): -# if not txt: -# return self._errors - -# logger.error(txt) -# self._errors.append(txt) -# error = SnapshotsLog( -# description=txt, -# snapshot_uuid=self.uuid, -# severity=severity, -# sid=self.sid, -# version=self.version, -# ) -# error.save() - - diff --git a/snapshot/views.py b/snapshot/views.py index 8a84d7c..0b143a9 100644 --- a/snapshot/views.py +++ b/snapshot/views.py @@ -5,7 +5,7 @@ from django.urls import reverse_lazy from dashboard.mixins import DashboardView from snapshot.models import Snapshot -from snapshot.forms import UploadForm +# from snapshot.forms import UploadForm # from django.shortcuts import render # from rest_framework import viewsets # from snapshot.serializers import SnapshotSerializer @@ -31,10 +31,10 @@ class ListSnapshotsView(DashboardView, TemplateView): return context -class UploadView(DashboardView, FormView): - template_name = "upload.html" - section = "snapshots" - title = _("Upload Snapshot") - breadcrumb = "Snapshots / Upload" - success_url = reverse_lazy('snashot:list') - form_class = UploadForm +# class UploadView(DashboardView, FormView): +# template_name = "upload.html" +# section = "snapshots" +# title = _("Upload Snapshot") +# breadcrumb = "Snapshots / Upload" +# success_url = reverse_lazy('snashot:list') +# form_class = UploadForm diff --git a/snapshot/xapian.py b/snapshot/xapian.py new file mode 100644 index 0000000..8ed6261 --- /dev/null +++ b/snapshot/xapian.py @@ -0,0 +1,22 @@ +import xapian + +database = xapian.WritableDatabase("db", xapian.DB_CREATE_OR_OPEN) + +indexer = xapian.TermGenerator() +stemmer = xapian.Stem("english") +indexer.set_stemmer(stemmer) + + +def search(qs, offset=0, limit=10): + query_string = str.join(' ', qs) + + qp = xapian.QueryParser() + qp.set_stemmer(stemmer) + qp.set_database(database) + qp.set_stemming_strategy(xapian.QueryParser.STEM_SOME) + query = qp.parse_query(query_string) + enquire = xapian.Enquire(database) + enquire.set_query(query) + matches = enquire.get_mset(offset, limit) + return matches + diff --git a/utils/constants.py b/utils/constants.py index d51519d..210b1c2 100644 --- a/utils/constants.py +++ b/utils/constants.py @@ -5,3 +5,4 @@ STR_XSM_SIZE = 16 STR_SM_SIZE = 32 STR_SIZE = 64 STR_BIG_SIZE = 128 +STR_EXTEND_SIZE = 256 -- 2.30.2 From b1440fddfa97bba7fda60ede3f3322e00ba744a0 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 18 Jul 2024 17:21:22 +0200 Subject: [PATCH 04/26] new structure --- dashboard/mixins.py | 2 + dashboard/templates/base.html | 16 +- dashboard/views.py | 28 +- device/migrations/0001_initial.py | 369 +----------------- ...rand_alter_device_devicehub_id_and_more.py | 33 -- device/migrations/0002_device_model.py | 18 + device/migrations/0003_device_manufacturer.py | 18 + ...nent_type_remove_computer_type_and_more.py | 73 ---- ..._dhid_bk_remove_device_phid_bk_and_more.py | 46 --- device/models.py | 192 +++------ device/templates/details.html | 198 ++++------ device/urls.py | 6 +- device/views.py | 108 ++--- example/snapshot1.json | 1 + lot/migrations/0001_initial.py | 44 ++- lot/models.py | 40 +- lot/templates/list_lots.html | 35 +- lot/urls.py | 4 +- lot/views.py | 38 +- reset.sh | 4 + snapshot/migrations/0001_initial.py | 44 +-- .../migrations/0002_alter_snapshot_uuid.py | 18 - .../0003_remove_snapshot_start_time.py | 17 - snapshot/migrations/0004_anotation.py | 41 -- .../0005_annotation_delete_anotation.py | 44 --- snapshot/models.py | 85 ++-- snapshot/parse.py | 71 ++-- snapshot/views.py | 9 +- snapshot/xapian.py | 43 +- user/management/commands/add_user.py | 20 +- user/migrations/0001_initial.py | 2 +- utils/constants.py | 14 + 32 files changed, 471 insertions(+), 1210 deletions(-) delete mode 100644 device/migrations/0002_alter_device_brand_alter_device_devicehub_id_and_more.py create mode 100644 device/migrations/0002_device_model.py create mode 100644 device/migrations/0003_device_manufacturer.py delete mode 100644 device/migrations/0003_remove_component_type_remove_computer_type_and_more.py delete mode 100644 device/migrations/0004_remove_device_dhid_bk_remove_device_phid_bk_and_more.py create mode 100644 example/snapshot1.json create mode 100644 reset.sh delete mode 100644 snapshot/migrations/0002_alter_snapshot_uuid.py delete mode 100644 snapshot/migrations/0003_remove_snapshot_start_time.py delete mode 100644 snapshot/migrations/0004_anotation.py delete mode 100644 snapshot/migrations/0005_annotation_delete_anotation.py diff --git a/dashboard/mixins.py b/dashboard/mixins.py index df9d6d1..bd93513 100644 --- a/dashboard/mixins.py +++ b/dashboard/mixins.py @@ -5,6 +5,7 @@ from django.core.exceptions import PermissionDenied from django.contrib.auth.mixins import LoginRequiredMixin from django.views.generic.base import TemplateView from device.models import Device +from lot.models import LotTag class Http403(PermissionDenied): @@ -37,6 +38,7 @@ class DashboardView(LoginRequiredMixin): 'section': self.section, 'path': resolve(self.request.path).url_name, 'user': self.request.user, + 'lot_tags': LotTag.objects.filter(owner=self.request.user) }) return context diff --git a/dashboard/templates/base.html b/dashboard/templates/base.html index 8134c90..296dd35 100644 --- a/dashboard/templates/base.html +++ b/dashboard/templates/base.html @@ -103,21 +103,13 @@ {% trans 'Lots' %} - - @@ -47,7 +44,6 @@ (Edit Device)
- {% if object.hid %}Snapshot{% else %}Placeholder{% endif %}
@@ -56,29 +52,24 @@
{{ object.id }}
-
-
Id device internal
-
-
-
Type
-
{{ snapshot.doc.device.type }}
+
{{ object.type }}
Manufacturer
-
{{ snapshot.doc.device.manufacturer|default:"" }}
+
{{ object.manufacturer|default:"" }}
Model
-
{{ snapshot.doc.device.model|default:"" }}
+
{{ object.model|default:"" }}
Serial Number
-
{{ snapshot.doc.device.serialNumber|default:"" }}
+
{{ object.last_snapshot.doc.device.serialNumber|default:"" }}
Identifiers
@@ -132,7 +123,7 @@ {% for tag in lot_tags %}
{{ tag }}
- {% for lot in object.lot_set.filter %} + {% for lot in tag.lot_set.filter %} {% if lot.type == tag %}
@@ -171,32 +162,10 @@
-
-
Traceability log Details
-
- -
- Snapshot ✓ - 14:07 23-06-2024 -
- -
- EraseCrypto ✓ - 14:07 23-06-2024 -
- -
- EraseCrypto ✓ - 14:07 23-06-2024 -
- -
-
-
Components last snapshot
- {% for c in snapshot.components %} + {% for c in object.last_snapshot.doc.components %}
{{ c.type }}
diff --git a/device/templates/new_device.html b/device/templates/new_device.html index 8f2df37..8907ef0 100644 --- a/device/templates/new_device.html +++ b/device/templates/new_device.html @@ -22,11 +22,34 @@
{% endif %} -{% bootstrap_form form %} +{# bootstrap_form form #} + + + +
+ {% csrf_token %} +
+ {% for f in form %} +
+ {{ f.as_p }} +
+ {% endfor %} +
+ +
{% endblock %} diff --git a/device/urls.py b/device/urls.py index 7fc0e96..3d0b368 100644 --- a/device/urls.py +++ b/device/urls.py @@ -5,7 +5,7 @@ app_name = 'device' urlpatterns = [ path("add/", views.NewDeviceView.as_view(), name="add"), - path("edit//", views.EditDeviceView.as_view(), name="edit"), - path("/", views.DetailsView.as_view(), name="details"), - path("/annotation/add", views.AddAnnotationView.as_view(), name="add_annotation"), + path("edit//", views.EditDeviceView.as_view(), name="edit"), + path("/", views.DetailsView.as_view(), name="details"), + path("/annotation/add", views.AddAnnotationView.as_view(), name="add_annotation"), ] diff --git a/device/views.py b/device/views.py index 00255dd..012c878 100644 --- a/device/views.py +++ b/device/views.py @@ -6,21 +6,23 @@ from django.utils.translation import gettext_lazy as _ from django.views.generic.edit import ( CreateView, UpdateView, + FormView, ) from django.views.generic.base import TemplateView -from dashboard.mixins import DashboardView, DetailsMixin +from dashboard.mixins import DashboardView from snapshot.models import Annotation from snapshot.xapian import search from lot.models import LotTag from device.models import Device +from device.forms import DeviceFormSet -class NewDeviceView(DashboardView, CreateView): +class NewDeviceView(DashboardView, FormView): template_name = "new_device.html" title = _("New Device") breadcrumb = "Device / New Device" success_url = reverse_lazy('dashboard:unassigned_devices') - model = Device + form_class = DeviceFormSet def form_valid(self, form): form.instance.owner = self.request.user @@ -28,12 +30,41 @@ class NewDeviceView(DashboardView, CreateView): return response +# class AddToLotView(DashboardView, FormView): +# template_name = "list_lots.html" +# title = _("Add to lots") +# breadcrumb = "lot / add to lots" +# success_url = reverse_lazy('dashboard:unassigned_devices') +# form_class = LotsForm + +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# lots = Lot.objects.filter(owner=self.request.user) +# lot_tags = LotTag.objects.filter(owner=self.request.user) +# context.update({ +# 'lots': lots, +# 'lot_tags':lot_tags, +# }) +# return context + +# def get_form(self): +# form = super().get_form() +# form.fields["lots"].queryset = Lot.objects.filter(owner=self.request.user) +# return form + +# def form_valid(self, form): +# form.devices = self.get_session_devices() +# form.save() +# response = super().form_valid(form) +# return response + + class EditDeviceView(DashboardView, UpdateView): template_name = "new_device.html" title = _("Update Device") breadcrumb = "Device / Update Device" success_url = reverse_lazy('dashboard:unassigned_devices') - model = Device + model = Annotation def get_form_kwargs(self): pk = self.kwargs.get('pk') @@ -43,17 +74,23 @@ class EditDeviceView(DashboardView, UpdateView): return kwargs -class DetailsView(DetailsMixin): +class DetailsView(DashboardView, TemplateView): template_name = "details.html" title = _("Device") breadcrumb = "Device / Details" - model = Device + model = Annotation + + def get(self, request, *args, **kwargs): + self.pk = kwargs['pk'] + self.object = Device(id=self.pk) + return super().get(request, *args, **kwargs) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) self.object.initial() lot_tags = LotTag.objects.filter(owner=self.request.user) context.update({ + 'object': self.object, 'snapshot': self.object.get_last_snapshot(), 'lot_tags': lot_tags, }) diff --git a/lot/forms.py b/lot/forms.py index 0065960..7b809fd 100644 --- a/lot/forms.py +++ b/lot/forms.py @@ -15,13 +15,14 @@ class LotsForm(forms.Form): def save(self, commit=True): if not commit: return + for dev in self.devices: for lot in self._lots: - lot.devices.add(dev.id) + lot.add(dev.id) return def remove(self): for dev in self.devices: for lot in self._lots: - lot.devices.remove(dev.id) + lot.remove(dev.id) return diff --git a/lot/migrations/0002_remove_lot_devices_devicelot.py b/lot/migrations/0002_remove_lot_devices_devicelot.py new file mode 100644 index 0000000..8496dea --- /dev/null +++ b/lot/migrations/0002_remove_lot_devices_devicelot.py @@ -0,0 +1,39 @@ +# Generated by Django 5.0.6 on 2024-07-18 17:30 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("lot", "0001_initial"), + ] + + operations = [ + migrations.RemoveField( + model_name="lot", + name="devices", + ), + migrations.CreateModel( + name="DeviceLot", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("device_id", models.CharField(max_length=256)), + ( + "lot", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="lot.lot" + ), + ), + ], + ), + ] diff --git a/lot/models.py b/lot/models.py index fb34778..9237a27 100644 --- a/lot/models.py +++ b/lot/models.py @@ -7,7 +7,7 @@ from utils.constants import ( ) from user.models import User -from device.models import Device +# from device.models import Device from snapshot.models import Annotation @@ -19,6 +19,11 @@ class LotTag(models.Model): return self.name +class DeviceLot(models.Model): + lot = models.ForeignKey("Lot", on_delete=models.CASCADE) + device_id = models.CharField(max_length=STR_EXTEND_SIZE, blank=False, null=False) + + class Lot(models.Model): created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) @@ -28,4 +33,13 @@ class Lot(models.Model): closed = models.BooleanField(default=True) owner = models.ForeignKey(User, on_delete=models.CASCADE) type = models.ForeignKey(LotTag, on_delete=models.CASCADE) - devices = models.ManyToManyField(Device) + + def add(self, v): + if DeviceLot.objects.filter(lot=self, device_id=v).exists(): + return + DeviceLot.objects.create(lot=self, device_id=v) + + def remove(self, v): + for d in DeviceLot.objects.filter(lot=self, device_id=v): + d.delete() + diff --git a/lot/views.py b/lot/views.py index 44d7266..9549076 100644 --- a/lot/views.py +++ b/lot/views.py @@ -6,7 +6,7 @@ from django.views.generic.edit import ( CreateView, DeleteView, UpdateView, - FormView + FormView, ) from dashboard.mixins import DashboardView from lot.models import Lot, LotTag diff --git a/snapshot/migrations/0002_remove_annotation_device.py b/snapshot/migrations/0002_remove_annotation_device.py new file mode 100644 index 0000000..326eca2 --- /dev/null +++ b/snapshot/migrations/0002_remove_annotation_device.py @@ -0,0 +1,17 @@ +# Generated by Django 5.0.6 on 2024-07-18 17:30 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("snapshot", "0001_initial"), + ] + + operations = [ + migrations.RemoveField( + model_name="annotation", + name="device", + ), + ] diff --git a/snapshot/models.py b/snapshot/models.py index bb6e40e..7c1a942 100644 --- a/snapshot/models.py +++ b/snapshot/models.py @@ -63,7 +63,6 @@ class Annotation(models.Model): type = models.SmallIntegerField(choices=Type) key = models.CharField(max_length=STR_EXTEND_SIZE) value = models.CharField(max_length=STR_EXTEND_SIZE) - device = models.ForeignKey('device.Device', on_delete=models.CASCADE) class Meta: constraints = [ diff --git a/snapshot/parse.py b/snapshot/parse.py index ea7e0a5..8137a86 100644 --- a/snapshot/parse.py +++ b/snapshot/parse.py @@ -7,7 +7,6 @@ import hashlib from datetime import datetime from snapshot.xapian import search, index from snapshot.models import Snapshot, Annotation -from device.models import Device from utils.constants import ALGOS @@ -47,21 +46,10 @@ class Build: value = algorithms['hidalgo1'] ).first() - if annotation: - device = annotation.device - else: - device = Device.objects.create( - type=self.json["device"]["type"], - manufacturer=self.json["device"]["manufacturer"], - model=self.json["device"]["model"], - owner=self.user - ) - for k, v in algorithms.items(): Annotation.objects.create( uuid=self.uuid, owner=self.user, - device=device, type=Annotation.Type.SYSTEM, key=k, value=v diff --git a/snapshot/views.py b/snapshot/views.py index b49615c..6a7f98b 100644 --- a/snapshot/views.py +++ b/snapshot/views.py @@ -1,10 +1,10 @@ from django.utils.translation import gettext_lazy as _ from django.views.generic.base import TemplateView -from django.views.generic.edit import FormView from django.urls import reverse_lazy from django.views.generic.edit import ( CreateView, UpdateView, + FormView, ) from dashboard.mixins import DashboardView -- 2.30.2 From 45ebb6f169c75b213c75b59d6afe0e5732dc3fef Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 22 Jul 2024 13:48:10 +0200 Subject: [PATCH 06/26] managment formset for new device --- device/templates/new_device.html | 76 ++++++++++++++++++-------------- device/views.py | 11 ++++- 2 files changed, 52 insertions(+), 35 deletions(-) diff --git a/device/templates/new_device.html b/device/templates/new_device.html index 8907ef0..870bf79 100644 --- a/device/templates/new_device.html +++ b/device/templates/new_device.html @@ -8,48 +8,58 @@
-{% load django_bootstrap5 %} -
-{% csrf_token %} -{% if form.errors %} - -{% endif %} -{# bootstrap_form form #} - - -
-
- {% csrf_token %} -
- {% for f in form %} -
- {{ f.as_p }} -
- {% endfor %} +{% load django_bootstrap5 %} + + {% csrf_token %} + {% if form.errors %} + + {% endif %} + {{ form.management_form }} +
+ + {% for f in form %} +
+
+ {% bootstrap_field f.name %} +
+
+ {% bootstrap_field f.value %} +
+
+ {% endfor %} +
+ + + {% endblock %} diff --git a/device/views.py b/device/views.py index 012c878..1a1f4a8 100644 --- a/device/views.py +++ b/device/views.py @@ -21,14 +21,21 @@ class NewDeviceView(DashboardView, FormView): template_name = "new_device.html" title = _("New Device") breadcrumb = "Device / New Device" - success_url = reverse_lazy('dashboard:unassigned_devices') + success_url = reverse_lazy('device:add') + # success_url = reverse_lazy('dashboard:unassigned_devices') form_class = DeviceFormSet def form_valid(self, form): - form.instance.owner = self.request.user + # import pdb; pdb.set_trace() + # form.instance.owner = self.request.user response = super().form_valid(form) return response + def form_invalid(self, form): + import pdb; pdb.set_trace() + response = super().form_invalid(form) + return response + # class AddToLotView(DashboardView, FormView): # template_name = "list_lots.html" -- 2.30.2 From 70ded1085220c24818f35b785363e5385ef4eb95 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 23 Jul 2024 15:37:40 +0200 Subject: [PATCH 07/26] save the device from web to index --- device/forms.py | 97 +++++++++++++++++++++++++++++--- device/templates/new_device.html | 24 +++++++- device/views.py | 5 +- snapshot/parse.py | 5 +- 4 files changed, 116 insertions(+), 15 deletions(-) diff --git a/device/forms.py b/device/forms.py index b74d29b..cf42dbc 100644 --- a/device/forms.py +++ b/device/forms.py @@ -1,17 +1,98 @@ +import json +import uuid +import hashlib +import datetime + from django import forms from snapshot.models import Annotation +from snapshot.xapian import search, index - -class DeviceForm2(forms.ModelForm): - class Meta: - model = Annotation - fields = ['key', 'value'] +DEVICE_TYPES = [ + ("Desktop", "Desktop"), + ("Laptop", "Laptop"), + ("Server", "Server"), + ("GraphicCard", "GraphicCard"), + ("HardDrive", "HardDrive"), + ("SolidStateDrive", "SolidStateDrive"), + ("Motherboard", "Motherboard"), + ("NetworkAdapter", "NetworkAdapter"), + ("Processor", "Processor"), + ("RamModule", "RamModule"), + ("SoundCard", "SoundCard"), + ("Display", "Display"), + ("Battery", "Battery"), + ("Camera", "Camera"), +] class DeviceForm(forms.Form): - name = forms.CharField() - value = forms.CharField() + type = forms.ChoiceField(choices = DEVICE_TYPES, required=False) + amount = forms.IntegerField(required=True, initial=1) + tag = forms.CharField(required=False) + name = forms.CharField(required=False) + value = forms.CharField(required=False) -DeviceFormSet = forms.formset_factory(form=DeviceForm, extra=1) +class BaseDeviceFormSet(forms.BaseFormSet): + def save(self, user, commit=True): + self.user = user + doc = {} + device = {} + kv = {} + self.uuid = str(uuid.uuid4()) + tag = hashlib.sha3_256(self.uuid.encode()).hexdigest() + for f in self.forms: + d = f.cleaned_data + if not d: + continue + if d.get("type"): + device["type"] = d["type"] + if d.get("amount"): + device["amount"] = d["amount"] + if d.get("name"): + kv[d["name"]] = d.get("value", '') + if d.get("tag"): + tag = d["tag"] + + if not device: + return + device["manufacturer"] = "" + device["model"] = tag + + doc["device"] = device + + if kv: + doc["kv"] = kv + + date = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S") + if doc: + doc["uuid"] = self.uuid + doc["endTime"] = date + doc["software"] = "DeviceHub" + doc["type"] = "WebSnapshot" + + + if not commit: + return doc + + self.index(doc) + self.create_annotations(tag) + return doc + + def index(self, doc): + snap = json.dumps(doc) + index(self.uuid, snap) + + def create_annotations(self, tag): + Annotation.objects.create( + uuid=self.uuid, + owner=self.user, + type=Annotation.Type.SYSTEM, + key='Web', + value=tag + ) + + + +DeviceFormSet = forms.formset_factory(form=DeviceForm, formset=BaseDeviceFormSet, extra=1) diff --git a/device/templates/new_device.html b/device/templates/new_device.html index 870bf79..0d6cf7c 100644 --- a/device/templates/new_device.html +++ b/device/templates/new_device.html @@ -12,8 +12,13 @@ function addForm(button) { var formCount = parseInt(document.getElementById('id_form-TOTAL_FORMS').value); var formCopy = $(document.querySelector('#id_form-0-name')).parent().parent().parent()[0].cloneNode(true); - // formCopy.style.display = 'block'; - formCopy.innerHTML = formCopy.innerHTML.replace(/__prefix__/g, formCount); + formCopy.querySelectorAll('input').forEach(function(input) { + var name = input.name.replace(/form-\d+/g, 'form-' + formCount); + var id = 'id_' + name; + input.name = name; + input.id = id; + input.value = ''; + }); document.getElementById('formset-container').appendChild(formCopy); document.getElementById('id_form-TOTAL_FORMS').value = formCount + 1; } @@ -44,6 +49,21 @@
+
+
+ {% bootstrap_field form.0.type %} +
+
+
+
+ {% bootstrap_field form.0.amount %} +
+
+
+
+ {% bootstrap_field form.0.tag %} +
+
{% for f in form %}
diff --git a/device/views.py b/device/views.py index 1a1f4a8..68344b0 100644 --- a/device/views.py +++ b/device/views.py @@ -22,17 +22,14 @@ class NewDeviceView(DashboardView, FormView): title = _("New Device") breadcrumb = "Device / New Device" success_url = reverse_lazy('device:add') - # success_url = reverse_lazy('dashboard:unassigned_devices') form_class = DeviceFormSet def form_valid(self, form): - # import pdb; pdb.set_trace() - # form.instance.owner = self.request.user + form.save(self.request.user) response = super().form_valid(form) return response def form_invalid(self, form): - import pdb; pdb.set_trace() response = super().form_invalid(form) return response diff --git a/snapshot/parse.py b/snapshot/parse.py index 8137a86..ee0e8cc 100644 --- a/snapshot/parse.py +++ b/snapshot/parse.py @@ -1,7 +1,6 @@ import os import json import shutil -import xapian import hashlib from datetime import datetime @@ -39,6 +38,7 @@ class Build: 'hidalgo1': self.get_hid_14(), } + # TODO is neccesary? annotation = Annotation.objects.filter( owner=self.user, type=Annotation.Type.SYSTEM, @@ -47,6 +47,9 @@ class Build: ).first() for k, v in algorithms.items(): + if annotation and k == annotation.key: + continue + Annotation.objects.create( uuid=self.uuid, owner=self.user, -- 2.30.2 From 91780be94bdef1ca5fd63f8a8578593f2604f76c Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 26 Jul 2024 17:59:34 +0200 Subject: [PATCH 08/26] change snapshots for evidences --- dashboard/mixins.py | 2 +- dashboard/templates/base.html | 10 ++--- dashboard/templates/base_site.html | 6 +-- dashboard/views.py | 4 +- device/models.py | 42 +++++++++---------- device/templates/details.html | 16 +++---- dhub/settings.py | 2 +- {snapshot => evidence}/__init__.py | 0 {snapshot => evidence}/admin.py | 0 {snapshot => evidence}/apps.py | 2 +- {snapshot => evidence}/forms.py | 2 +- {snapshot => evidence}/management/__init__.py | 0 .../management/commands/__init__.py | 0 .../management/commands/up_snapshots.py | 0 .../migrations/0001_initial.py | 0 .../0002_remove_annotation_device.py | 0 {snapshot => evidence}/migrations/__init__.py | 0 {snapshot => evidence}/models.py | 4 +- {snapshot => evidence}/parse.py | 8 ++-- {snapshot => evidence}/serializers.py | 8 ++-- .../templates/evidences.html | 6 +-- {snapshot => evidence}/tests.py | 0 {snapshot => evidence}/urls.py | 6 +-- {snapshot => evidence}/views.py | 18 ++++---- {snapshot => evidence}/xapian.py | 0 lot/models.py | 2 +- 26 files changed, 69 insertions(+), 69 deletions(-) rename {snapshot => evidence}/__init__.py (100%) rename {snapshot => evidence}/admin.py (100%) rename {snapshot => evidence}/apps.py (84%) rename {snapshot => evidence}/forms.py (62%) rename {snapshot => evidence}/management/__init__.py (100%) rename {snapshot => evidence}/management/commands/__init__.py (100%) rename {snapshot => evidence}/management/commands/up_snapshots.py (100%) rename {snapshot => evidence}/migrations/0001_initial.py (100%) rename {snapshot => evidence}/migrations/0002_remove_annotation_device.py (100%) rename {snapshot => evidence}/migrations/__init__.py (100%) rename {snapshot => evidence}/models.py (97%) rename {snapshot => evidence}/parse.py (89%) rename {snapshot => evidence}/serializers.py (88%) rename snapshot/templates/snapshots.html => evidence/templates/evidences.html (83%) rename {snapshot => evidence}/tests.py (100%) rename {snapshot => evidence}/urls.py (74%) rename {snapshot => evidence}/views.py (74%) rename {snapshot => evidence}/xapian.py (100%) diff --git a/dashboard/mixins.py b/dashboard/mixins.py index 470bf0d..c28dcf8 100644 --- a/dashboard/mixins.py +++ b/dashboard/mixins.py @@ -5,7 +5,7 @@ from django.core.exceptions import PermissionDenied from django.contrib.auth.mixins import LoginRequiredMixin from django.views.generic.base import TemplateView from device.models import Device -from snapshot.models import Annotation +from evidence.models import Annotation from lot.models import LotTag diff --git a/dashboard/templates/base.html b/dashboard/templates/base.html index be20573..c73e203 100644 --- a/dashboard/templates/base.html +++ b/dashboard/templates/base.html @@ -108,19 +108,19 @@
+
+ {% load django_bootstrap5 %} +
+
+ {% csrf_token %} + {% if form.errors %} + + {% endif %} + {% bootstrap_form form %} + +
+
+
{% endblock %} diff --git a/evidence/views.py b/evidence/views.py index 58a0d56..a9459e1 100644 --- a/evidence/views.py +++ b/evidence/views.py @@ -7,7 +7,7 @@ from django.views.generic.edit import ( from dashboard.mixins import DashboardView, Http403 from evidence.models import Evidence -from evidence.forms import UploadForm +from evidence.forms import UploadForm, UserTagForm # from django.shortcuts import render # from rest_framework import viewsets # from snapshot.serializers import SnapshotSerializer @@ -51,12 +51,14 @@ class UploadView(DashboardView, FormView): response = super().form_invalid(form) return response - -class EvidenceView(DashboardView, TemplateView): + +class EvidenceView(DashboardView, FormView): template_name = "ev_details.html" section = "evidences" title = _("Evidences") breadcrumb = "Evidences / Details" + success_url = reverse_lazy('evidence:list') + form_class = UserTagForm def get(self, request, *args, **kwargs): self.pk = kwargs['pk'] @@ -73,3 +75,22 @@ class EvidenceView(DashboardView, TemplateView): 'object': self.object, }) return context + + def get_form_kwargs(self): + self.pk = self.kwargs.get('pk') + kwargs = super().get_form_kwargs() + kwargs['uuid'] = self.pk + return kwargs + + def form_valid(self, form): + form.save(self.request.user) + response = super().form_valid(form) + return response + + def form_invalid(self, form): + response = super().form_invalid(form) + return response + + def get_success_url(self): + success_url = reverse_lazy('evidence:details', args=[self.pk]) + return success_url diff --git a/lot/views.py b/lot/views.py index 0045d16..280450e 100644 --- a/lot/views.py +++ b/lot/views.py @@ -162,7 +162,7 @@ class LotDocumentsView(DashboardView, TemplateView): template_name = "documents.html" title = _("New Document") breadcrumb = "Device / New document" - + def get_context_data(self, **kwargs): self.pk = kwargs.get('pk') context = super().get_context_data(**kwargs) @@ -185,7 +185,7 @@ class LotAnnotationsView(DashboardView, TemplateView): template_name = "annotations.html" title = _("New Annotation") breadcrumb = "Device / New annotation" - + def get_context_data(self, **kwargs): self.pk = kwargs.get('pk') context = super().get_context_data(**kwargs) @@ -203,7 +203,7 @@ class LotAnnotationsView(DashboardView, TemplateView): }) return context - + class LotAddAnnotationView(DashboardView, CreateView): template_name = "new_annotation.html" title = _("New Annotation") -- 2.30.2 From 435e18c8b6b4c62f29ac1255b56956266e8d3192 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 1 Aug 2024 17:33:23 +0200 Subject: [PATCH 19/26] Download evidence from evidence details --- evidence/templates/ev_details.html | 3 +++ evidence/urls.py | 1 + evidence/views.py | 18 ++++++++++++++++++ 3 files changed, 22 insertions(+) diff --git a/evidence/templates/ev_details.html b/evidence/templates/ev_details.html index e589d2f..4c3fdbf 100644 --- a/evidence/templates/ev_details.html +++ b/evidence/templates/ev_details.html @@ -16,6 +16,9 @@ diff --git a/evidence/urls.py b/evidence/urls.py index 060ce52..872073a 100644 --- a/evidence/urls.py +++ b/evidence/urls.py @@ -17,4 +17,5 @@ urlpatterns = [ path("", views.ListEvidencesView.as_view(), name="list"), path("upload", views.UploadView.as_view(), name="upload"), path("", views.EvidenceView.as_view(), name="details"), + path("/download", views.DownloadEvidenceView.as_view(), name="download"), ] diff --git a/evidence/views.py b/evidence/views.py index a9459e1..d5ff542 100644 --- a/evidence/views.py +++ b/evidence/views.py @@ -1,3 +1,6 @@ +import json + +from django.http import HttpResponse from django.utils.translation import gettext_lazy as _ from django.views.generic.base import TemplateView from django.urls import reverse_lazy @@ -94,3 +97,18 @@ class EvidenceView(DashboardView, FormView): def get_success_url(self): success_url = reverse_lazy('evidence:details', args=[self.pk]) return success_url + + +class DownloadEvidenceView(DashboardView, TemplateView): + + def get(self, request, *args, **kwargs): + pk = kwargs['pk'] + evidence = Evidence(pk) + if evidence.owner != self.request.user: + raise Http403() + + evidence.get_doc() + data = json.dumps(evidence.doc) + response = HttpResponse(data, content_type="application/json") + response['Content-Disposition'] = 'attachment; filename={}'.format("credential.json") + return response -- 2.30.2 From 260b7db7656e310865e57eada12b106bd6e28624 Mon Sep 17 00:00:00 2001 From: pedro Date: Fri, 2 Aug 2024 13:05:02 +0200 Subject: [PATCH 20/26] add minimal docker support for debugging --- db/.gitignore | 6 +++ docker-compose.yml | 12 ++++++ docker/devicehub-django.Dockerfile | 35 +++++++++++++++++ docker/devicehub-django.entrypoint.sh | 56 +++++++++++++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 db/.gitignore create mode 100644 docker-compose.yml create mode 100644 docker/devicehub-django.Dockerfile create mode 100644 docker/devicehub-django.entrypoint.sh diff --git a/db/.gitignore b/db/.gitignore new file mode 100644 index 0000000..2171e8d --- /dev/null +++ b/db/.gitignore @@ -0,0 +1,6 @@ +# src https://stackoverflow.com/questions/115983/how-do-i-add-an-empty-directory-to-a-git-repository + +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..b6e2d01 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,12 @@ +services: + devicehub-django: + init: true + build: + dockerfile: docker/devicehub-django.Dockerfile + environment: + DEBUG: true + volumes: + - .:/opt/devicehub-django + ports: + - 8000:8000 + diff --git a/docker/devicehub-django.Dockerfile b/docker/devicehub-django.Dockerfile new file mode 100644 index 0000000..2f734b4 --- /dev/null +++ b/docker/devicehub-django.Dockerfile @@ -0,0 +1,35 @@ +FROM python:3.11.7-slim-bookworm + +# last line is dependencies for weasyprint (for generating pdfs in lafede pilot) https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#debian-11 +RUN apt update && \ + apt-get install -y \ + python3-xapian \ + git \ + sqlite3 \ + jq \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /opt/devicehub-django + +# reduce size (python specifics) -> src https://stackoverflow.com/questions/74616667/removing-pip-cache-after-installing-dependencies-in-docker-image +ENV PYTHONDONTWRITEBYTECODE=1 +# here document in dockerfile src https://stackoverflow.com/questions/40359282/launch-a-cat-command-unix-into-dockerfile +RUN cat > /etc/pip.conf < Date: Mon, 5 Aug 2024 13:32:52 +0200 Subject: [PATCH 21/26] Import device from a file --- dashboard/templates/base.html | 2 +- device/forms.py | 6 +- device/templates/details.html | 8 -- evidence/forms.py | 125 +++++++++++++++++++++++++ evidence/urls.py | 1 + evidence/views.py | 25 ++++- example/placeholders1.ods | Bin 0 -> 13284 bytes example/{ => snapshots}/snapshot1.json | 0 requirements.txt | 6 +- reset.sh | 2 +- 10 files changed, 160 insertions(+), 15 deletions(-) create mode 100644 example/placeholders1.ods rename example/{ => snapshots}/snapshot1.json (100%) diff --git a/dashboard/templates/base.html b/dashboard/templates/base.html index bcf569f..67c7573 100644 --- a/dashboard/templates/base.html +++ b/dashboard/templates/base.html @@ -132,7 +132,7 @@
    diff --git a/device/forms.py b/device/forms.py index 1c1c5e7..e83aed2 100644 --- a/device/forms.py +++ b/device/forms.py @@ -5,7 +5,7 @@ import datetime from django import forms from evidence.models import Annotation -from evidence.xapian import search, index +from evidence.xapian import index DEVICE_TYPES = [ ("Desktop", "Desktop"), @@ -62,8 +62,6 @@ class BaseDeviceFormSet(forms.BaseFormSet): if not device: return - device["manufacturer"] = "" - device["model"] = tag doc["device"] = device @@ -71,10 +69,12 @@ class BaseDeviceFormSet(forms.BaseFormSet): doc["kv"] = kv date = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S") + if doc: doc["uuid"] = self.uuid doc["endTime"] = date doc["software"] = "DeviceHub" + doc["CUSTOMER_ID"] = tag doc["type"] = "WebSnapshot" diff --git a/device/templates/details.html b/device/templates/details.html index 30e7cfb..577e823 100644 --- a/device/templates/details.html +++ b/device/templates/details.html @@ -40,14 +40,6 @@
    Details
    -
    - (Edit Device) -
    -
    -
    -
    - -
    Phid
    {{ object.id }}
    diff --git a/evidence/forms.py b/evidence/forms.py index 7eaf0ca..6e6ad8a 100644 --- a/evidence/forms.py +++ b/evidence/forms.py @@ -1,10 +1,16 @@ import json +import uuid +import hashlib +import datetime +import pandas as pd from django import forms from django.core.exceptions import ValidationError from django.utils.translation import gettext_lazy as _ from utils.forms import MultipleFileField +from device.models import Device from evidence.parse import Build +from evidence.xapian import index from evidence.models import Annotation @@ -73,3 +79,122 @@ class UserTagForm(forms.Form): key='CUSTOM_ID', value=self.tag ) + + +class ImportForm(forms.Form): + file_import = forms.FileField(label=_("File to import")) + + def __init__(self, *args, **kwargs): + + self.rows = [] + self.properties = {} + self.user = kwargs.pop('user') + super().__init__(*args, **kwargs) + + def clean_file_import(self): + data = self.cleaned_data["file_import"] + + self.file_name = data.name + df = pd.read_excel(data) + df.fillna('', inplace=True) + + data_pd = df.to_dict(orient='index') + + if not data_pd or df.last_valid_index() is None: + self.exception(_("The file you try to import is empty!")) + + for n in data_pd.keys(): + # import pdb; pdb.set_trace() + if 'type' not in [x.lower() for x in data_pd[n]]: + raise ValidationError("You need a column with name 'type'") + + + for k, v in data_pd[n].items(): + if k.lower() == "type": + if v not in Device.Types.values: + raise ValidationError("{} is not a valid device".format(v)) + + self.rows.append(data_pd[n]) + + return data + + def save(self, commit=True): + table = [] + for row in self.rows: + table.append(self.create_annotation(row)) + + if commit: + for doc, cred in table: + cred.save() + self.index(doc) + return table + + return + + def create_annotation(self, row): + doc = self.create_doc(row) + if not doc: + return [] + + data = { + 'uuid': doc['uuid'], + 'owner': self.user, + 'type': Annotation.Type.SYSTEM, + 'key': 'CUSTOM_ID', + 'value': doc['CUSTOMER_ID'], + } + + return [doc, Annotation(**data)] + + def index(self, doc): + _uuid = doc['uuid'] + ev = json.dumps(doc) + index(_uuid, ev) + + def create_doc(self, row): + doc = {} + device = {"manufacturer": "", "model": ""} + kv = {} + _uuid = str(uuid.uuid4()) + tag = hashlib.sha3_256(_uuid.encode()).hexdigest() + + + for k, v in row.items(): + if k.upper() == "CUSTOM_ID": + tag = v + + if not v: + continue + + if k.lower() == "type": + device["type"] = v + elif k.lower() == "amount": + try: + device["amount"] = int(v) + except Exception: + device["amount"] = 1 + + else: + kv[k] = v + + if 'amount' not in row.keys(): + device["amount"] = 1 + + if not device: + return + + doc["device"] = device + + if kv: + doc["kv"] = kv + + date = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S") + + if doc: + doc["uuid"] = _uuid + doc["endTime"] = date + doc["software"] = "DeviceHub" + doc["CUSTOMER_ID"] = tag + doc["type"] = "WebSnapshot" + + return doc diff --git a/evidence/urls.py b/evidence/urls.py index 872073a..d4dff01 100644 --- a/evidence/urls.py +++ b/evidence/urls.py @@ -16,6 +16,7 @@ app_name = 'evidence' urlpatterns = [ path("", views.ListEvidencesView.as_view(), name="list"), path("upload", views.UploadView.as_view(), name="upload"), + path("import", views.ImportView.as_view(), name="import"), path("", views.EvidenceView.as_view(), name="details"), path("/download", views.DownloadEvidenceView.as_view(), name="download"), ] diff --git a/evidence/views.py b/evidence/views.py index d5ff542..1e02c7e 100644 --- a/evidence/views.py +++ b/evidence/views.py @@ -10,7 +10,7 @@ from django.views.generic.edit import ( from dashboard.mixins import DashboardView, Http403 from evidence.models import Evidence -from evidence.forms import UploadForm, UserTagForm +from evidence.forms import UploadForm, UserTagForm, ImportForm # from django.shortcuts import render # from rest_framework import viewsets # from snapshot.serializers import SnapshotSerializer @@ -55,6 +55,29 @@ class UploadView(DashboardView, FormView): return response +class ImportView(DashboardView, FormView): + template_name = "upload.html" + section = "evidences" + title = _("Import Evidence") + breadcrumb = "Evidences / Import" + success_url = reverse_lazy('evidence:list') + form_class = ImportForm + + def get_form_kwargs(self): + kwargs = super().get_form_kwargs() + kwargs['user'] = self.request.user + return kwargs + + def form_valid(self, form): + form.save() + response = super().form_valid(form) + return response + + def form_invalid(self, form): + response = super().form_invalid(form) + return response + + class EvidenceView(DashboardView, FormView): template_name = "ev_details.html" section = "evidences" diff --git a/example/placeholders1.ods b/example/placeholders1.ods new file mode 100644 index 0000000000000000000000000000000000000000..414816577dd4550760d8ce4fdf4564963d739da8 GIT binary patch literal 13284 zcmbt*1yo!~w>9n(T!IA+?ry<7H16)!ST_U@PH-o<1c%0g1czV&0t9yt?gZCIzW2|U znRzqw-uvI_b=RtU*WJ6S&Z(-duCp7U01Jl;1%(6!)vE`u6Ku~P&H@Dm_49gq1m$4k zU;*-QvM_OSvbQla0ogbLS>1rDX41rWsI>f~Z!V(w~fVF3dC zf%A#x-$wjYl5hlC+E{^I{>A3X!3uJ8w0ANATG+GxJ&yb@a5fGmRu-{LctcpGp|_T;ay%1G}>l&aEEBav!145FSSJ{XsYCw?q*M{S4eX% zN7tqwn2>yls44DL=Q5+G8IZNE+hG)FW@#*#7nqx=XCzM}J+Tce$YyAA2Qu&*B?mL} zqS=pp%zODJ?T3(Z3uWgdpR+7lZ*4RZGFgb}tLdM68(IYcUVQ7UL zhAXXAhx&ob-bvP;hi0DO@t%`qszl=qjzi_$Wpv-nvE796P7m)_EBnsz`u&l+=Bcc=$U8L*StrrUAkSScNUgO3A8+7>@qJBzy6S9y}c_opoErb3g9UgZzGpIe&QyS*Q(j**fE z-9pPP*l9QM8Kyb!e7yi6)R8{%*VGHaK|MtC`C{TfUM@;fGautgz2Iw31iEpVVwof& z*oey#7J8_z1oJco#8$MwF{*Xj*LaxeF)}-ivJ|yS@gqzTe+Xr?mX{YDweqH%&dJq! zt|u}O7<^>*W`Pc6?d_6?{9@MSh)#{N=@G1nU(F_gQz(v$*Rnj#UC;N{Q8zJ_YtbTPbFq=UMBe79qp8=P3^}@HG|FVi7spCJmvq&@Ki2abH8Q z;p1!e{g!iI_Sa6kOmKlQ52R4z95;oB(PY*QS{Ju$YhcX^ShC`07r9bjb=Jj7T_k$n z9iw_Av>5m`jM*^oGX-yIU<6a?6JR{P{?=4AIQF)OcaxYdi9R_^$0h}Su#<(F=V3vB&BD!?gTtgw9zYRVzP`^sLE z0PtJZ*>7NJw`TY9_Rb#yV%E8IoJab4diahs#Bx%i?rC?fTGO=IPX?+vxCp+@9e;JR54%kC>-FWY8}Oii!^o6eCdc!NWhSBo7~2-k+bky;+=dN-cMUDycxhIs}H1?<=s4 zIkHc_XI2*KcK&#nBfZrG-8XeuycN-V7^zdVu7Gy1DNNTjVN_WyGxv54Eqdcr+rFV1 zV1jSjaxLCnUkK6yi2z^=cv#vtZj(z9jRs1l+IpDr#3n!8=CDwK=;{>$u&Jo zX{$!)?8LBZ)Ykh6%Js=N~(KChHU|cJ>cn%CnC@r^El+QOCa&ImLvf{1Y71@h(d5oak zg_$^mzUh~Cshz?y*4>|=5#T5Ezq5;>Bf@>dwhyjPp30(--{JGka{Kyab9k(s+Tnt^ zjg)Zv5ZVsJA*nCT}JR<6c#Tjd7zIuYY z&W@l(m`~>nfZN$T)uCW2{0ysobyA;*kH;kQ@2^T0fjw}AZ~)_(Jn zR6K|a3qw9`Mj@qLt-39U1#nX%q89pa6EdO>-%TnnscXeH+@Jq^pJhLns$H$Z)sjzd z^uj@EIT2ee$Y}6g$8E>~HgMoTs}g(c8x~qVYjWn5OBspPo;5J;Jk-kYH>Uj?OMDCmwFy&Y${doUSLm zj#q99+sd`B6;18j?oXU*&3p`fb5Hkk)lxoxIQ4;pf-=Sbr|%+^r&Y@pfn5k3)*j4;cDY51B@Ii)_6@)i zGMRRw9ahki=1{;iEmpOBv~|0Yal&+UN)O;NS`#GVJB*}5K3F#lTIKi>04Mi-8N0=A zo%*nz<0vVNg@px130#gmh*%g6vvPdG%=C&6h~=s}P%_B7Fce%AxusTs=cvXb<04p9 zsBsJ(c9V_S&gY9WR5EA3|NMr~EJ=XIm@mV980JT-;jFrnd%z9-53}TySiny|Arm`^{bz;C+c(c#?xsXV|rT?wPdfd_zm zf`8I4Hu@D3#?YsPLBG2_TrH^<{M6Uv8l3p~JY}CiRO)ne@KgLH5f%xY?WpY|n*%iL*^$jp%;7RF?ww>WzPMRy5Wrf2p z5MJ|(htPJ?&#BC7G^RqT zn_%t<)dXDkY1Uq@7cbnGQG}o%Bmv zB2f*6(WJKt{W+nORJ{Zdnn@R~#0v!sp2sVXsm!U+HAyMQhlxmee={yyv{4(E+Dbi{ zY6jBPBXUeUMzn$}Ae*4TF5`tEEW>UxNU2!%@vfLNhptv_4FapM#xQf?#b_G)P29!p z!+tK>%F)p2{sF&0x`(YRtYThmUW=Z7zH{mN$IudQ%`~1?Gkz^piLKu4N@(WDx)F?w@(v4ywC4&(W@dLO2#}Nc3ig(O+TX4_koZ#b#@3u4!VeEG1 z&&$~54@&eQ(wg_U=f@J~)Vpvb!vuKNb=&NkO6iPC#5D7?wN9MD$|SnspXo){0Xce# zH4sq$!V6u_a{S_OY?@uUa7?7!@`yxm)T$kAf#(+|*<8LPpY;Xnh9Cq1i6tB{&>SYT zr&d1v_UL#m(#Uf5g&S27*K>z6{-KqkuKXnnMMr~joum#b-38D1P7Mu`u07iZ6>b-u zZjLP;FYg~-$8;Is_d>VKbipD478EJ5k+RSNwEo+S#%J%xOtRh!?qKE8*7V72!P{NgL>4 zZ)uBtKE^z$G@FyILn`sOpuvLv)o?U)t5Ul*BoHKoZQXn{)0z?%pXb%yvnoYL6R41% zq7*{wUC~755TMFhU9qoWWTEV|VY-kM;W&{L!LD_IJ#VmTuH_3YXh?pc__4LJI>Wr# z@JywvQpFn1?eco~|@qbc=l zsa*VgYgD^+B73Le{vErHP^DM4g|f@x?!KrbrEWG425*9xr-nwdnSkVCAb8Vsd;T)l~y|!2Raqs>jOW1dh`Byn+$6f@&NS6P5|GOm483W74I14Y1Slq zrD?9H%kb6Uv=5lW3!g6khI5tA{k!DFC)i2%YERtDn~OlP%lpGNVty~;5S*AS9_*rg z+w~WpT?==Sqlx)+bY(K#s=R|f5N94Rx=y%Es0^mKsppB(3EIx>ikh%LbRTJ$#uU0K z3y#dJP4mX8k=@&nqmzG$7G4}*Tl_KCg;ndkYR1B+I1z0`S@&`I*bDgrt;lK_sKOfS zJ2F8UPT(2wO)tb!s4>ka%sBEUj(CCPbLEh`Xsz=(Bl*BNe?0XC>FTz`anCo2W4JzQ znOJY!9&P<0s9EBezP=Jn-!~O3eLlz7^Zm&lwe3_cJ_n zd|{nIGt3V$rqkZ|1VbZxGR{$&J%+gqscgFZxmnUe>V6DcTzomj9Nw|Ch^RjI9%llJ zV4*LrO3B zdK=DAs(LY+6ofeJ5fouo-W!#a+x~DV`pozH?2&C8!gt=dj}`20##QMMygXzCyoj8U}&2s)Mbty5#a__A4tl*-LJ5wCbr~1H z5LJ021lk$K;jvCUscU`1*7nHP%Wf9-tpkbG=RX)nGg54y^V=sIH5*o1oV$j@o#D)8 zl&9mE^3wFXfc=fnDC<m*6t@FnHBp%>T2;Z!L^&CU)IG42tD-2m;9aspF-ry4Fe=R>zv3APU>b*}w;uUk7R3fayv`7vIC;col$B#1nd z1yQP2Il`-9wJX|1o0|Zlil1|7U%ZIjHO%g$c6s@#6NiJxoNFVSeEEU;3R4{yelhPW zCi{wT$7Uln2Cg!D2)~#EKvAbqUXx{nF)1R`Y|dT12&%I(*btG4lhTNM(g%XJ(u*ek zB1#*&-2K|@CHAdDcbfz|uW`jRUy!V4nt&<~UtA1Vi&Ff|cOR18k#{tQBl!X=W1@Jk zjNzH4YvsF9KIBNec7C7kCd=4bM6(z&GAxV{#4Fw>f!gglD~f%^j#I>9)M=;C9i@#B z9*KRHQCUE)vi&H8VxXl|gXr|qjWq&7ERGNld(C*xj;=7dGpMb(pi%@KhUyHxOAN=C ztTzDkhl1}24d8)tE5O8Sya4%K^`fz@$aC8OM2%zVEZ4WOz~k;YMb2&Fybml zbSfsS@=XNUxeL>ER`9hKijYAT4+FXkbVgAdaSh^iyjr}i1Pqaj@)Q*&j{RH7Fw(X&4ZEl*+b82ljOdRhtM%+|*+~|s`?V>YmBQ){?LCVF$7P(hJ#O%! z%2fA`j(0hH$iooq#bw*OL!EVD=BrKhWYp;tj-%~bM>o9wk&ol`3>Pm|E&R+I4jP5) z1B(U#2k31vm)>_nJW0j=d$6taHiJHaq^;LnQ&u$&mRd|Wk+64sjtu?rb(<2)wY%W5 z0v_hFrE$n?H%Y0Ik5j=8DPugBXgU=bn0_`^KJx(4BuCr28nxB!)ov_K?=mrxXO+EMSbjbDDSFCtd%G*5^BE>k1p6i?=z;qaH2$}Y;5G>;1`1~R706_3n9Nv5B0;X; z<3TB~bK{V*tSQ(JIqV&j0u}g1Aj7(z6(tJ0-BCQ1k>P-0W8^zea2`-V~(r z)dG!Zw-txC^#}b?Rb^!3WacU6bk2YWLAUMW(^)Sf(xda9^&E~U^US_XPLYQ~o|jEszw%mOc& zxtQ2_xR_}Iy14YDzL{DoO?bDP0vgO-)S+O?xR_XE_6qy1u!Rsh6Iqt(K*`wWgGXftHJ| zl!=kCjj6t;sRGDU&BapB)z-+z65wT{?qzRiYG!F>=W6BRXY1r<XYwGK2&Ckqgt=P=db!1USw;uAMFx7M2ivEHfj>loi{rgMzV{A)7akCq z6cC*n7N3z26_%J7lNlG9kr|7@sG{jWu23?9bcP14>t6S*7VKP^)EDk z8E^W!)b?$$acHGwbgi>I>C4BA?%MpWPZfjpxkF6_{mqastsh6*O8Pq+X1XBr1N94| zt!txgU0((}2PZ!d&wUx2n;hz%8||B!o$a67?p-*ZSXdukIUHI$n_J(T-a21Ce%PGu z+gKbwS?W7l9r?bxw7W8~v%c_S_3O#{*y-ln`Oe(k&cx0B;^WEU`uEMX&E4-i`#axP z_V+gS_V&K-|M>pne*ffb@9b{x=JCh=_mjijtHag%i=7{5XJ;4JXLk=*=VuRhXAch# zPZQzs@v&1S^l2VFJC>6aQ-3peuz(Cuza&LGZeZ$;4yYlVf|av&kC&AyLqfn?%cG45 zK(rmxt$QaIB~!X4W=o7!^-^WeU%;m2xdChWi8y1bXD=)u!oKAhS01*Ek`Q0b;QGDg z&0~8*^9pyuhH$3b>HYA_!E?V`k=tc=@5^eK7jrUD(CWE2pS)e?!F$bmBi?bMdXp6& z3>pmgZod*-2Q7f^YBlVNZ>{66m=V!qHF~TXzR+!??JSK0ggHExB03utBm!K+M9|sm zMhX~@hV5!%R0DMVD8`Zu3v)1qjIM72D>zdP=cGYwU$_`;xis1>P>59|gm2;#u}@w0 zbz%?<9$X@3K^8Mod5JV&!E`6s>O?rM!SqN$c+xEmpnPe-9Q^dGBKN>g5Kq zLTS_ofIoK;)jdPRlk_S$a2=j-P;vzI9-a=18dtKrVLJ!b`6 zm1^$T5>m4p(uW_y#sB?j&`<#$awRtF*Mmod8p{o_>+ zlpE-s7DqIbc4>I?=3YzDXCik~HEc+$Mr?&J13%?qj5F==JfOz%-_W3H?ErOm{Gkba(=k>h+dw|b*+NB}5l<{6_Zdu*D6fe=oa&%Ty1Q=AAxa75gV+?%r`ztW^Xf zPaX%#I4X4ta62sDv<+LHdG(lMw*krq$mH7P1@@&%3>)2Fqi$91j#PQIzdumh4jFl$ z&b^A3Q=BEjde z`W9;L#w%%M%tTP>njdD0KKGP0x$d{s6m_M|!tc*oIxclI&MAHm^zEMh7V8r!>T@m^ z?~AH3E4MouO1VrYu-ZD()ks{m&fv#D6dy+QrBuxz&}GsLWI3hCXW_ahaTVOl*X-L zCx^`@E7tyU$BJ}{=8B2isenVjB77uBNm9f_=Dm+H^2)=z=+~# zmsr22e>j3}J*lYF^I5ajxDy8k5V~guX`jk@_2`&p;E{5yj!ViI!uoxV1m zOw)JEO7ThLq6Iy^C0{-0ogVam*vCBrM*1&DVT*^qCfg@aIBI1NG$wU7$mEl-E9AMj zQ3{AUI!VU!s&Wq-WOez-Zydj2-4-(QJewvt9~oa*t^ijkEV|q2lkcLd;BVArK5DK| zx(FSsy)R>+%xq)ytL4uc)0fIY(I}=Y)u=>cobp`&-(S6UpGCS@E(+vgVoT{|6ijZs zXW$|}IVn5(RHDkAoh>KacH;16zvYo0tEPmh>0PB;jBcZfc84ek^=!=cThpZbgdoQ} zd718ci_4}dPwHmE+0ujZ_K7;G#bj%ddV)b zg?4jw`+Ar!D$%`rid66D@*PThj18T8j$LavsB*zJ2F22?3HvU2>~3?XHodGxJ_&W! zJJZcoBTL<_i?5G()eglvSq&dcW;B-{cYL*wIS-QtMaMnlMw81PwWImjjl`$@_cwaB zBH7#VfDAHuT;Ty7Hm}pSlYq#a36*Psq0L>beUHkP$l`+1mYZn7yF@TFcXmg*T^jyt zt?TuMsfepVn2oH&J#Z<8Jb_|ieN@+uNBye2gVprWirK-HreE*jM=j6c@qknZfG&J= z9Iwh8G$6)}M~~PmmV{VD{Z!wgITq|72*$zhm(p%?I{LsifD^uv-eOpL%VgVupHrAT zmTp)z3yg?Y(M&qiv(N~aUm_nsFeu0UD(d^3f+%6Yqf$r0BdS)lb#0u3`U^Gn$MIVs zr7c?rW>TCQpa#3DR9$?@=8t54Wvx`gEt5t=KSyxn@<`rC+%F*(BVG>~BjW}+sjHRM zdM=$z87IaoFHG#m8N4>_>YHCX^pa~V1*o-IHoqcL_TUa7|45j)>8UHz)JfN)C@O!p zHUHU%tP~%qoip7iQ+%{@?@1moh^bjB3b`1rMW~@s=iZt_^yu902V-ULTwzHl5<+%x zY2KTm)@l0*`kh2?*HrC6dDWy1-EyfUX|*5R37Jf_i1|BDKFwU-o5(`-%HTDS=$?xY z2hA=mFdFU08DWm?H64*Fts{k(^wCu&wR@-3^DvBlVYX3PL%bg-^B)2{CV>xrlNnDN z#IJZnL;}K^CHn82pXEAX2_6T?mKbc{eC0HA@JnU>`pI(f>0n~Y*qF2 zyt{L6DP@dJ#dD{Fc)(FhUUEvyIsOWho79#Sx?Ge#Ng1<0xk!3G;!*L<1m97ytm?{I zlPgn+H03qJa~W6-EGzq%7Gn*!vQAe#F&rd~C@S%D0wJwzc{>OX;yUAunB(4*@O9%A zBV=w%p#9Jml5&wyb}WHExkWJ2REJM4BJ1ha2sE|=g|?=6kh^#xlcIR0JL+b8= zMeCo{+fL{RI~{B9*+T5p%S7gM`|wkKOwEZnkr%udYG%^4F!e;h`w@Y>Q~GeXeC^>E zh7h0q-xyYs%X>5F3uJOzD<5?A1+S`B>|Ye?FSE z5n|O5aRk^wXl+&t6o)>&m83V``^NWR1$U|e#CC*So?69yG_2*FdNnz#8{=M%bus!w z$#sBIKn>)C(G#@D#CSgwe7NO62cC)<7J6cKEqox&8ODeCm(qpIuaz4ZejA^`>Ueq<3uBvOxT|R+a5;Z@x zUu@M}e`wq$Dv@T+i>K|m+f|KInvwL?VAlfIPbp3r1ka=EO_JF)8rFN&)=f3)*{KXp zrIo1WkLg-@EiCW|l?7idS>~#lm~%|dpf?wSElb&vBgYnX1v5%1mtkagw@SOjWP-}m zMfvphgbM057v$}fbe~*P|05_0|)fUaj}uqoYG$8%hEjOpd6Q#+Sf)jGLhbZ)ft z22D=o0Ae5jxSzUVtNc8)CI7WG=pu8fOfSCX=3LLNtgH^0Utc$@o#*g0f;2Si$C-)j zH&bM_eC)Hnr007=&VP>bgosKj^YZrzab+%Yr@NI!8kX*M!V&tAI*aF{Z`-UP8k=!b zy5H|@CA{AD)lOk%YRiuJ;`I=3h{&4WKV&Q`gt~-MyS*ywBZv5TY6_eFKk@kyGpms++WZYE3 zts2vAUWTTGWN}i5^uQFw#lY?W2$2XevNyJa=y$fHte#%N5h+wQE<1D;7P{Z8TyPkE zaZ@rRDxB0G+R~ySv#*WWmK~h;pPx-&ax#i>p8KlNY;xzrtY^1@vMDl9Mp)!Ju-7^t z5`Mt&$ao*-oH!M&+EtrYMi+!H#tc`VT8{{fgK3MsJ+nS9J=OQox4SP0pPB>1f7Dl+ zt|@3)@oYfHV}g@6qRGPZI!r)4P(y+tD3Q6{e-+$L$?8 zC_uZDoRSR&OU-Z$j%y!0n{VDv%~3Q=4n^*eD72Wu5hw%3#i8 zzk%+kB}Ba}dE|z=%TupnoBAOx%6B_)SB%^NB30^%IIU|(;80oT7ELdJipIA>kcfnsZs+jV>_1s^<{uqbZ@(&8dook9GaPkpzES+MH-x`O-&lBi5ua$=5D$M#5 zwO?92OJ6K;pTsh)A$xu?FkKE~-&#Mzz3=s?;a9cjR=0zv3;XVSZSjEL`-=IHjj*vY z^90FBiTDY5a;Q2-S4`Pc$5s-h=|!dv!RDOI(DCl5%#2sPRukd!=TdM*P@@9|-l)bku3!Mj`u(T$Js!Aknv)=mZ)|u09}fs+NmPC~BX}TkIAqXpJUSx>*h{fuSFWR+M>;~wj8ni z0Q2*B_e$^W3-%`wDASXq3ZMWDgA4WdQv09r`DMQe@BfVY^#&BwPj&h)Q-3P{leGSi zwg19FLH!ih|FX!Z;-7i`i`4$_$$kpNe_8)i@y}#`l-~b6(;vGB`{c&|!t^^S{@?Tb zJU#zqf`7sDOPc@pEPrf`^Ix$1UaJ51Jb!FW$zSmNlJ5UcS(g8T<(HKI?^*sBD?FJ0 z>ft|1`~Q>aH+A~&b?ZM9*S}2piRs^K$CK3mw?X_H^7q>4pSt#67X6g9c>2f5zf|sj zM*Uu!_)|Ci%gmoLC}zJ@)PDy4KKK4JPx8xtrcHhc8UKv?eRAfH9dyO{W1jvu53J7@lzRT`iGkMQ#~tf!B~)1qU;`t$BT0OU}D0ssI2 literal 0 HcmV?d00001 diff --git a/example/snapshot1.json b/example/snapshots/snapshot1.json similarity index 100% rename from example/snapshot1.json rename to example/snapshots/snapshot1.json diff --git a/requirements.txt b/requirements.txt index 2357fe8..9d4492f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,5 +3,9 @@ Django==5.0.6 django-bootstrap5==24.2 django-extensions==3.2.3 djangorestframework==3.15.1 -py-dmidecode==0.1.3 python-decouple==3.3 +py-dmidecode==0.1.3 +pandas==2.2.2 +xlrd==2.0.1 +odfpy==1.4.1 + diff --git a/reset.sh b/reset.sh index a3bd06b..3b634ae 100644 --- a/reset.sh +++ b/reset.sh @@ -1,4 +1,4 @@ rm db/* ./manage.py migrate ./manage.py add_user user@example.org 1234 -./manage.py up_snapshots example/ user@example.org +./manage.py up_snapshots example/snapshots/ user@example.org -- 2.30.2 From 468abb2c2f9f4ac3796603256f08d62a7531d345 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 5 Aug 2024 15:06:34 +0200 Subject: [PATCH 22/26] add evidences in details of device --- device/models.py | 20 ++++++++++++++++---- device/templates/details.html | 9 +++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/device/models.py b/device/models.py index ce874fd..f1b1ee7 100644 --- a/device/models.py +++ b/device/models.py @@ -43,11 +43,11 @@ class Device: self.get_hids() self.get_evidences() self.get_lots() - + def get_annotations(self): if self.annotations: return self.annotations - + self.annotations = Annotation.objects.filter( type=Annotation.Type.SYSTEM, value=self.id @@ -69,7 +69,7 @@ class Device: type=Annotation.Type.USER ) return annotations - + def get_user_documents(self): if not self.uuids: self.get_uuids() @@ -80,7 +80,7 @@ class Device: type=Annotation.Type.DOCUMENT ) return annotations - + def get_uuids(self): for a in self.get_annotations(): if a.uuid not in self.uuids: @@ -125,6 +125,18 @@ class Device: # owner=user # ).annotate(num_lots=models.Count('lot')).filter(num_lots=0) + @property + def is_websnapshot(self): + if not self.last_evidence: + self.get_last_evidence() + return self.last_evidence.doc['type'] == "WebSnapshot" + + @property + def last_user_evidence(self): + if not self.last_evidence: + self.get_last_evidence() + return self.last_evidence.doc['kv'].items() + @property def manufacturer(self): if not self.last_evidence: diff --git a/device/templates/details.html b/device/templates/details.html index 577e823..3881c1a 100644 --- a/device/templates/details.html +++ b/device/templates/details.html @@ -49,6 +49,14 @@
    {{ object.type }}
    + {% if object.is_websnapshot %} + {% for k, v in object.last_user_evidence %} +
    +
    {{ k }}
    +
    {{ v|default:"" }}
    +
    + {% endfor %} + {% else %}
    Manufacturer
    {{ object.manufacturer|default:"" }}
    @@ -63,6 +71,7 @@
    Serial Number
    {{ object.last_evidence.doc.device.serialNumber|default:"" }}
    + {% endif %}
    Identifiers
    -- 2.30.2 From 247ba5bd15fbbb3d0e8c737c306afad616d60e2e Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 5 Aug 2024 15:07:29 +0200 Subject: [PATCH 23/26] refactor of create a new placeholder from excel or form --- device/forms.py | 65 +++++------------------ device/templates/new_device.html | 2 +- evidence/forms.py | 82 +++-------------------------- utils/device.py | 89 ++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 129 deletions(-) create mode 100644 utils/device.py diff --git a/device/forms.py b/device/forms.py index e83aed2..b6c1d21 100644 --- a/device/forms.py +++ b/device/forms.py @@ -1,11 +1,6 @@ -import json -import uuid -import hashlib -import datetime - from django import forms -from evidence.models import Annotation -from evidence.xapian import index +from utils.device import create_annotation, create_doc, create_index + DEVICE_TYPES = [ ("Desktop", "Desktop"), @@ -28,7 +23,7 @@ DEVICE_TYPES = [ class DeviceForm(forms.Form): type = forms.ChoiceField(choices = DEVICE_TYPES, required=False) amount = forms.IntegerField(required=False, initial=1) - tag = forms.CharField(required=False) + customer_id = forms.CharField(required=False) name = forms.CharField(required=False) value = forms.CharField(required=False) @@ -42,63 +37,29 @@ class BaseDeviceFormSet(forms.BaseFormSet): def save(self, user, commit=True): self.user = user - doc = {} - device = {} - kv = {} - self.uuid = str(uuid.uuid4()) - tag = hashlib.sha3_256(self.uuid.encode()).hexdigest() + row = {} for f in self.forms: d = f.cleaned_data if not d: continue + if d.get("type"): - device["type"] = d["type"] + row["type"] = d["type"] if d.get("amount"): - device["amount"] = d["amount"] + row["amount"] = d["amount"] if d.get("name"): - kv[d["name"]] = d.get("value", '') - if d.get("tag"): - tag = d["tag"] - - if not device: - return - - doc["device"] = device - - if kv: - doc["kv"] = kv - - date = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S") - - if doc: - doc["uuid"] = self.uuid - doc["endTime"] = date - doc["software"] = "DeviceHub" - doc["CUSTOMER_ID"] = tag - doc["type"] = "WebSnapshot" - + row[d["name"]] = d.get("value", '') + if d.get("customer_id"): + row['CUSTOMER_ID']= d["customer_id"] + doc = create_doc(row) if not commit: return doc - self.index(doc) - self.create_annotations(tag) + create_index(doc) + create_annotation(doc, user, commit=commit) return doc - def index(self, doc): - snap = json.dumps(doc) - index(self.uuid, snap) - - def create_annotations(self, tag): - Annotation.objects.create( - uuid=self.uuid, - owner=self.user, - type=Annotation.Type.SYSTEM, - key='CUSTOM_ID', - value=tag - ) - - DeviceFormSet = forms.formset_factory(form=DeviceForm, formset=BaseDeviceFormSet, extra=1) diff --git a/device/templates/new_device.html b/device/templates/new_device.html index 0d6cf7c..bdb2911 100644 --- a/device/templates/new_device.html +++ b/device/templates/new_device.html @@ -61,7 +61,7 @@
    - {% bootstrap_field form.0.tag %} + {% bootstrap_field form.0.customer_id %}
    {% for f in form %} diff --git a/evidence/forms.py b/evidence/forms.py index 6e6ad8a..ae2630d 100644 --- a/evidence/forms.py +++ b/evidence/forms.py @@ -1,16 +1,13 @@ import json -import uuid -import hashlib -import datetime import pandas as pd from django import forms from django.core.exceptions import ValidationError from django.utils.translation import gettext_lazy as _ +from utils.device import create_annotation, create_doc, create_index from utils.forms import MultipleFileField from device.models import Device from evidence.parse import Build -from evidence.xapian import index from evidence.models import Annotation @@ -104,10 +101,8 @@ class ImportForm(forms.Form): self.exception(_("The file you try to import is empty!")) for n in data_pd.keys(): - # import pdb; pdb.set_trace() if 'type' not in [x.lower() for x in data_pd[n]]: raise ValidationError("You need a column with name 'type'") - for k, v in data_pd[n].items(): if k.lower() == "type": @@ -118,83 +113,18 @@ class ImportForm(forms.Form): return data + def save(self, commit=True): table = [] for row in self.rows: - table.append(self.create_annotation(row)) + doc = create_doc(row) + annotation = create_annotation(doc, self.user) + table.append((doc, annotation)) if commit: for doc, cred in table: cred.save() - self.index(doc) + create_index(doc) return table return - - def create_annotation(self, row): - doc = self.create_doc(row) - if not doc: - return [] - - data = { - 'uuid': doc['uuid'], - 'owner': self.user, - 'type': Annotation.Type.SYSTEM, - 'key': 'CUSTOM_ID', - 'value': doc['CUSTOMER_ID'], - } - - return [doc, Annotation(**data)] - - def index(self, doc): - _uuid = doc['uuid'] - ev = json.dumps(doc) - index(_uuid, ev) - - def create_doc(self, row): - doc = {} - device = {"manufacturer": "", "model": ""} - kv = {} - _uuid = str(uuid.uuid4()) - tag = hashlib.sha3_256(_uuid.encode()).hexdigest() - - - for k, v in row.items(): - if k.upper() == "CUSTOM_ID": - tag = v - - if not v: - continue - - if k.lower() == "type": - device["type"] = v - elif k.lower() == "amount": - try: - device["amount"] = int(v) - except Exception: - device["amount"] = 1 - - else: - kv[k] = v - - if 'amount' not in row.keys(): - device["amount"] = 1 - - if not device: - return - - doc["device"] = device - - if kv: - doc["kv"] = kv - - date = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S") - - if doc: - doc["uuid"] = _uuid - doc["endTime"] = date - doc["software"] = "DeviceHub" - doc["CUSTOMER_ID"] = tag - doc["type"] = "WebSnapshot" - - return doc diff --git a/utils/device.py b/utils/device.py new file mode 100644 index 0000000..2e41597 --- /dev/null +++ b/utils/device.py @@ -0,0 +1,89 @@ +import json +import uuid +import hashlib +import datetime + +from django.core.exceptions import ValidationError +from evidence.xapian import index +from evidence.models import Annotation +from device.models import Device + +def create_doc(data): + if not data: + return + + doc = {} + device = {"manufacturer": "", "model": "", "amount": 1} + kv = {} + _uuid = str(uuid.uuid4()) + customer_id = hashlib.sha3_256(_uuid.encode()).hexdigest() + + + for k, v in data.items(): + if not v: + continue + + if k.upper() == "CUSTOMER_ID": + customer_id = v + continue + + if k.lower() == "type": + if v not in Device.Types.values: + raise ValidationError("{} is not a valid device".format(v)) + + device["type"] = v + + elif k.lower() == "amount": + try: + amount = int(v) + device["amount"] = amount + except Exception: + pass + + else: + kv[k] = v + + if not device: + return + + doc["device"] = device + + if kv: + doc["kv"] = kv + + date = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S") + + if doc: + doc["uuid"] = _uuid + doc["endTime"] = date + doc["software"] = "DeviceHub" + doc["CUSTOMER_ID"] = customer_id + doc["type"] = "WebSnapshot" + + return doc + + +def create_annotation(doc, user, commit=False): + if not doc or not doc.get('uuid') or not doc.get("CUSTOMER_ID"): + return [] + + data = { + 'uuid': doc['uuid'], + 'owner': user, + 'type': Annotation.Type.SYSTEM, + 'key': 'CUSTOMER_ID', + 'value': doc['CUSTOMER_ID'], + } + if commit: + return Annotation.objects.create(**data) + + return Annotation(**data) + + +def create_index(doc): + if not doc or not doc.get('uuid'): + return [] + + _uuid = doc['uuid'] + ev = json.dumps(doc) + index(_uuid, ev) -- 2.30.2 From 71d9e5481c691f2adf687bbfbe2a3bfdbb9ab62a Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 3 Sep 2024 16:41:27 +0200 Subject: [PATCH 24/26] fix --- evidence/xapian.py | 2 +- reset.sh | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/evidence/xapian.py b/evidence/xapian.py index 222afe3..e38a8ab 100644 --- a/evidence/xapian.py +++ b/evidence/xapian.py @@ -32,7 +32,7 @@ def index(uuid, snap): matches = search(uuid, limit=1) if matches.size() > 0: return - except xapian.DatabaseNotFoundError: + except (xapian.DatabaseNotFoundError, xapian.DatabaseOpeningError): pass database = xapian.WritableDatabase("db", xapian.DB_CREATE_OR_OPEN) diff --git a/reset.sh b/reset.sh index 3b634ae..e9c2543 100644 --- a/reset.sh +++ b/reset.sh @@ -1,4 +1,4 @@ rm db/* -./manage.py migrate -./manage.py add_user user@example.org 1234 -./manage.py up_snapshots example/snapshots/ user@example.org +python3 manage.py migrate +python3 manage.py add_user user@example.org 1234 +python3 manage.py up_snapshots example/snapshots/ user@example.org -- 2.30.2 From 343600a5403010770d8e0931a8ebf35511ff6361 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 3 Sep 2024 18:41:53 +0200 Subject: [PATCH 25/26] migrations --- device/migrations/0001_initial.py | 404 ++++++++++++++++++ ...rand_alter_device_devicehub_id_and_more.py | 33 ++ ...nent_type_remove_computer_type_and_more.py | 73 ++++ 3 files changed, 510 insertions(+) create mode 100644 device/migrations/0001_initial.py create mode 100644 device/migrations/0002_alter_device_brand_alter_device_devicehub_id_and_more.py create mode 100644 device/migrations/0003_remove_component_type_remove_computer_type_and_more.py diff --git a/device/migrations/0001_initial.py b/device/migrations/0001_initial.py new file mode 100644 index 0000000..22d9017 --- /dev/null +++ b/device/migrations/0001_initial.py @@ -0,0 +1,404 @@ +# Generated by Django 5.0.6 on 2024-06-11 09:20 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="Device", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("created", models.DateTimeField(auto_now_add=True)), + ("updated", models.DateTimeField(auto_now=True)), + ("type", models.CharField(max_length=32)), + ("model", models.CharField(blank=True, max_length=64, null=True)), + ( + "manufacturer", + models.CharField(blank=True, max_length=64, null=True), + ), + ( + "serial_number", + models.CharField(blank=True, max_length=64, null=True), + ), + ("part_number", models.CharField(blank=True, max_length=64, null=True)), + ("brand", models.TextField(blank=True, null=True)), + ("generation", models.SmallIntegerField(blank=True, null=True)), + ("version", models.TextField(blank=True, null=True)), + ("production_date", models.DateTimeField(blank=True, null=True)), + ("variant", models.TextField(blank=True, null=True)), + ("devicehub_id", models.TextField(blank=True, null=True, unique=True)), + ("dhid_bk", models.CharField(blank=True, max_length=64, null=True)), + ("phid_bk", models.CharField(blank=True, max_length=64, null=True)), + ("family", models.CharField(blank=True, max_length=64, null=True)), + ("hid", models.CharField(blank=True, max_length=64, null=True)), + ("chid", models.CharField(blank=True, max_length=64, null=True)), + ("active", models.BooleanField(default=True)), + ( + "owner", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + ), + migrations.CreateModel( + name="Component", + fields=[ + ( + "device", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + primary_key=True, + serialize=False, + to="device.device", + ), + ), + ( + "type", + models.CharField( + choices=[ + ("GraphicCard", "Graphiccard"), + ("DataStorage", "Datastorage"), + ("Motherboard", "Motherboard"), + ("NetworkAdapter", "Networkadapter"), + ("Processor", "Processor"), + ("RamModule", "Rammodule"), + ("SoundCard", "Soundcard"), + ("Display", "Display"), + ("Battery", "Battery"), + ("Camera", "Camera"), + ], + max_length=32, + ), + ), + ], + ), + migrations.CreateModel( + name="Computer", + fields=[ + ( + "device", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + primary_key=True, + serialize=False, + to="device.device", + ), + ), + ("chassis", models.TextField(blank=True, null=True)), + ("system_uuid", models.UUIDField()), + ("sku", models.TextField(blank=True, null=True)), + ( + "type", + models.CharField( + choices=[ + ("Desktop", "Desktop"), + ("Laptop", "Laptop"), + ("Server", "Server"), + ], + default="Laptop", + max_length=32, + ), + ), + ], + ), + migrations.CreateModel( + name="PhysicalProperties", + fields=[ + ( + "device", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + primary_key=True, + serialize=False, + to="device.device", + ), + ), + ("weight", models.FloatField(blank=True, null=True)), + ("width", models.FloatField(blank=True, null=True)), + ("height", models.FloatField(blank=True, null=True)), + ("depth", models.FloatField(blank=True, null=True)), + ("color", models.CharField(blank=True, max_length=20, null=True)), + ("image", models.CharField(blank=True, max_length=64, null=True)), + ], + ), + migrations.CreateModel( + name="SoundCard", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "component", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + to="device.component", + ), + ), + ], + ), + migrations.CreateModel( + name="RamModule", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("size", models.IntegerField(blank=True, null=True)), + ("speed", models.SmallIntegerField(blank=True, null=True)), + ( + "interface", + models.CharField( + choices=[ + ("SDRAM", "Sdram"), + ("DDR SDRAM", "Ddr"), + ("DDR2 SDRAM", "Ddr2"), + ("DDR3 SDRAM", "Ddr3"), + ("DDR4 SDRAM", "Ddr4"), + ("DDR5 SDRAM", "Ddr5"), + ("DDR6 SDRAM", "Ddr6"), + ("LPDDR3", "Lpddr3"), + ], + max_length=32, + ), + ), + ( + "format", + models.CharField( + choices=[("DIMM", "Dimm"), ("SODIMM", "Sodimm")], max_length=32 + ), + ), + ( + "component", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + to="device.component", + ), + ), + ], + ), + migrations.CreateModel( + name="Processor", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("speed", models.FloatField(blank=True, null=True)), + ("cores", models.SmallIntegerField(blank=True, null=True)), + ("threads", models.SmallIntegerField(blank=True, null=True)), + ("address", models.SmallIntegerField(blank=True, null=True)), + ( + "component", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + to="device.component", + ), + ), + ], + ), + migrations.CreateModel( + name="NetworkAdapter", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("speed", models.IntegerField(blank=True, null=True)), + ("wireless", models.BooleanField(default=False)), + ( + "component", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + to="device.component", + ), + ), + ], + ), + migrations.CreateModel( + name="Motherboard", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("slots", models.SmallIntegerField(blank=True, null=True)), + ("usb", models.SmallIntegerField(blank=True, null=True)), + ("firewire", models.SmallIntegerField(blank=True, null=True)), + ("serial", models.SmallIntegerField(blank=True, null=True)), + ("pcmcia", models.SmallIntegerField(blank=True, null=True)), + ("bios_date", models.DateTimeField()), + ("ram_slots", models.SmallIntegerField(blank=True, null=True)), + ("ram_max_size", models.IntegerField(blank=True, null=True)), + ( + "component", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + to="device.component", + ), + ), + ], + ), + migrations.CreateModel( + name="GraphicCard", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("memory", models.IntegerField(blank=True, null=True)), + ( + "component", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + to="device.component", + ), + ), + ], + ), + migrations.CreateModel( + name="Display", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "component", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + to="device.component", + ), + ), + ], + ), + migrations.CreateModel( + name="DataStorage", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("size", models.IntegerField(blank=True, null=True)), + ( + "interface", + models.CharField( + choices=[ + ("ATA", "Ata"), + ("USB", "Usb"), + ("PCI", "Pci"), + ("NVME", "Nvme"), + ], + max_length=32, + ), + ), + ( + "type", + models.CharField( + choices=[ + ("HardDrive", "Harddrive"), + ("SolidStateDrive", "Solidstatedrive"), + ], + max_length=32, + ), + ), + ( + "component", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + to="device.component", + ), + ), + ], + ), + migrations.CreateModel( + name="Battery", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "component", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + to="device.component", + ), + ), + ], + ), + migrations.AddField( + model_name="component", + name="computer", + field=models.OneToOneField( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="device.computer", + ), + ), + ] diff --git a/device/migrations/0002_alter_device_brand_alter_device_devicehub_id_and_more.py b/device/migrations/0002_alter_device_brand_alter_device_devicehub_id_and_more.py new file mode 100644 index 0000000..1d02fb7 --- /dev/null +++ b/device/migrations/0002_alter_device_brand_alter_device_devicehub_id_and_more.py @@ -0,0 +1,33 @@ +# Generated by Django 5.0.6 on 2024-07-03 11:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("device", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="device", + name="brand", + field=models.CharField(blank=True, max_length=64, null=True), + ), + migrations.AlterField( + model_name="device", + name="devicehub_id", + field=models.CharField(blank=True, max_length=64, null=True, unique=True), + ), + migrations.AlterField( + model_name="device", + name="variant", + field=models.CharField(blank=True, max_length=64, null=True), + ), + migrations.AlterField( + model_name="device", + name="version", + field=models.CharField(blank=True, max_length=64, null=True), + ), + ] diff --git a/device/migrations/0003_remove_component_type_remove_computer_type_and_more.py b/device/migrations/0003_remove_component_type_remove_computer_type_and_more.py new file mode 100644 index 0000000..d57d6bc --- /dev/null +++ b/device/migrations/0003_remove_component_type_remove_computer_type_and_more.py @@ -0,0 +1,73 @@ +# Generated by Django 5.0.6 on 2024-07-03 12:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("device", "0002_alter_device_brand_alter_device_devicehub_id_and_more"), + ] + + operations = [ + migrations.RemoveField( + model_name="component", + name="type", + ), + migrations.RemoveField( + model_name="computer", + name="type", + ), + migrations.RemoveField( + model_name="datastorage", + name="type", + ), + migrations.AlterField( + model_name="computer", + name="chassis", + field=models.CharField( + blank=True, + choices=[ + ("Tower", "Tower"), + ("All in one", "Allinone"), + ("Microtower", "Microtower"), + ("Netbook", "Netbook"), + ("Laptop", "Laptop"), + ("Tablet", "Tabler"), + ("Server", "Server"), + ("Non-physical device", "Virtual"), + ], + max_length=32, + null=True, + ), + ), + migrations.AlterField( + model_name="computer", + name="sku", + field=models.CharField(blank=True, max_length=32, null=True), + ), + migrations.AlterField( + model_name="device", + name="type", + field=models.CharField( + choices=[ + ("Desktop", "Desktop"), + ("Laptop", "Laptop"), + ("Server", "Server"), + ("GraphicCard", "Graphiccard"), + ("HardDrive", "Harddrive"), + ("SolidStateDrive", "Solidstatedrive"), + ("Motherboard", "Motherboard"), + ("NetworkAdapter", "Networkadapter"), + ("Processor", "Processor"), + ("RamModule", "Rammodule"), + ("SoundCard", "Soundcard"), + ("Display", "Display"), + ("Battery", "Battery"), + ("Camera", "Camera"), + ], + default="Laptop", + max_length=32, + ), + ), + ] -- 2.30.2 From 21feaea3de42171d92c19a52983800dc82e57958 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 3 Sep 2024 18:45:51 +0200 Subject: [PATCH 26/26] revert migrations --- device/migrations/0001_initial.py | 404 ------------------ ...rand_alter_device_devicehub_id_and_more.py | 33 -- ...nent_type_remove_computer_type_and_more.py | 73 ---- 3 files changed, 510 deletions(-) delete mode 100644 device/migrations/0001_initial.py delete mode 100644 device/migrations/0002_alter_device_brand_alter_device_devicehub_id_and_more.py delete mode 100644 device/migrations/0003_remove_component_type_remove_computer_type_and_more.py diff --git a/device/migrations/0001_initial.py b/device/migrations/0001_initial.py deleted file mode 100644 index 22d9017..0000000 --- a/device/migrations/0001_initial.py +++ /dev/null @@ -1,404 +0,0 @@ -# Generated by Django 5.0.6 on 2024-06-11 09:20 - -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name="Device", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("created", models.DateTimeField(auto_now_add=True)), - ("updated", models.DateTimeField(auto_now=True)), - ("type", models.CharField(max_length=32)), - ("model", models.CharField(blank=True, max_length=64, null=True)), - ( - "manufacturer", - models.CharField(blank=True, max_length=64, null=True), - ), - ( - "serial_number", - models.CharField(blank=True, max_length=64, null=True), - ), - ("part_number", models.CharField(blank=True, max_length=64, null=True)), - ("brand", models.TextField(blank=True, null=True)), - ("generation", models.SmallIntegerField(blank=True, null=True)), - ("version", models.TextField(blank=True, null=True)), - ("production_date", models.DateTimeField(blank=True, null=True)), - ("variant", models.TextField(blank=True, null=True)), - ("devicehub_id", models.TextField(blank=True, null=True, unique=True)), - ("dhid_bk", models.CharField(blank=True, max_length=64, null=True)), - ("phid_bk", models.CharField(blank=True, max_length=64, null=True)), - ("family", models.CharField(blank=True, max_length=64, null=True)), - ("hid", models.CharField(blank=True, max_length=64, null=True)), - ("chid", models.CharField(blank=True, max_length=64, null=True)), - ("active", models.BooleanField(default=True)), - ( - "owner", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to=settings.AUTH_USER_MODEL, - ), - ), - ], - ), - migrations.CreateModel( - name="Component", - fields=[ - ( - "device", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - primary_key=True, - serialize=False, - to="device.device", - ), - ), - ( - "type", - models.CharField( - choices=[ - ("GraphicCard", "Graphiccard"), - ("DataStorage", "Datastorage"), - ("Motherboard", "Motherboard"), - ("NetworkAdapter", "Networkadapter"), - ("Processor", "Processor"), - ("RamModule", "Rammodule"), - ("SoundCard", "Soundcard"), - ("Display", "Display"), - ("Battery", "Battery"), - ("Camera", "Camera"), - ], - max_length=32, - ), - ), - ], - ), - migrations.CreateModel( - name="Computer", - fields=[ - ( - "device", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - primary_key=True, - serialize=False, - to="device.device", - ), - ), - ("chassis", models.TextField(blank=True, null=True)), - ("system_uuid", models.UUIDField()), - ("sku", models.TextField(blank=True, null=True)), - ( - "type", - models.CharField( - choices=[ - ("Desktop", "Desktop"), - ("Laptop", "Laptop"), - ("Server", "Server"), - ], - default="Laptop", - max_length=32, - ), - ), - ], - ), - migrations.CreateModel( - name="PhysicalProperties", - fields=[ - ( - "device", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - primary_key=True, - serialize=False, - to="device.device", - ), - ), - ("weight", models.FloatField(blank=True, null=True)), - ("width", models.FloatField(blank=True, null=True)), - ("height", models.FloatField(blank=True, null=True)), - ("depth", models.FloatField(blank=True, null=True)), - ("color", models.CharField(blank=True, max_length=20, null=True)), - ("image", models.CharField(blank=True, max_length=64, null=True)), - ], - ), - migrations.CreateModel( - name="SoundCard", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "component", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - to="device.component", - ), - ), - ], - ), - migrations.CreateModel( - name="RamModule", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("size", models.IntegerField(blank=True, null=True)), - ("speed", models.SmallIntegerField(blank=True, null=True)), - ( - "interface", - models.CharField( - choices=[ - ("SDRAM", "Sdram"), - ("DDR SDRAM", "Ddr"), - ("DDR2 SDRAM", "Ddr2"), - ("DDR3 SDRAM", "Ddr3"), - ("DDR4 SDRAM", "Ddr4"), - ("DDR5 SDRAM", "Ddr5"), - ("DDR6 SDRAM", "Ddr6"), - ("LPDDR3", "Lpddr3"), - ], - max_length=32, - ), - ), - ( - "format", - models.CharField( - choices=[("DIMM", "Dimm"), ("SODIMM", "Sodimm")], max_length=32 - ), - ), - ( - "component", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - to="device.component", - ), - ), - ], - ), - migrations.CreateModel( - name="Processor", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("speed", models.FloatField(blank=True, null=True)), - ("cores", models.SmallIntegerField(blank=True, null=True)), - ("threads", models.SmallIntegerField(blank=True, null=True)), - ("address", models.SmallIntegerField(blank=True, null=True)), - ( - "component", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - to="device.component", - ), - ), - ], - ), - migrations.CreateModel( - name="NetworkAdapter", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("speed", models.IntegerField(blank=True, null=True)), - ("wireless", models.BooleanField(default=False)), - ( - "component", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - to="device.component", - ), - ), - ], - ), - migrations.CreateModel( - name="Motherboard", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("slots", models.SmallIntegerField(blank=True, null=True)), - ("usb", models.SmallIntegerField(blank=True, null=True)), - ("firewire", models.SmallIntegerField(blank=True, null=True)), - ("serial", models.SmallIntegerField(blank=True, null=True)), - ("pcmcia", models.SmallIntegerField(blank=True, null=True)), - ("bios_date", models.DateTimeField()), - ("ram_slots", models.SmallIntegerField(blank=True, null=True)), - ("ram_max_size", models.IntegerField(blank=True, null=True)), - ( - "component", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - to="device.component", - ), - ), - ], - ), - migrations.CreateModel( - name="GraphicCard", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("memory", models.IntegerField(blank=True, null=True)), - ( - "component", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - to="device.component", - ), - ), - ], - ), - migrations.CreateModel( - name="Display", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "component", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - to="device.component", - ), - ), - ], - ), - migrations.CreateModel( - name="DataStorage", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("size", models.IntegerField(blank=True, null=True)), - ( - "interface", - models.CharField( - choices=[ - ("ATA", "Ata"), - ("USB", "Usb"), - ("PCI", "Pci"), - ("NVME", "Nvme"), - ], - max_length=32, - ), - ), - ( - "type", - models.CharField( - choices=[ - ("HardDrive", "Harddrive"), - ("SolidStateDrive", "Solidstatedrive"), - ], - max_length=32, - ), - ), - ( - "component", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - to="device.component", - ), - ), - ], - ), - migrations.CreateModel( - name="Battery", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "component", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - to="device.component", - ), - ), - ], - ), - migrations.AddField( - model_name="component", - name="computer", - field=models.OneToOneField( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="device.computer", - ), - ), - ] diff --git a/device/migrations/0002_alter_device_brand_alter_device_devicehub_id_and_more.py b/device/migrations/0002_alter_device_brand_alter_device_devicehub_id_and_more.py deleted file mode 100644 index 1d02fb7..0000000 --- a/device/migrations/0002_alter_device_brand_alter_device_devicehub_id_and_more.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.0.6 on 2024-07-03 11:07 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("device", "0001_initial"), - ] - - operations = [ - migrations.AlterField( - model_name="device", - name="brand", - field=models.CharField(blank=True, max_length=64, null=True), - ), - migrations.AlterField( - model_name="device", - name="devicehub_id", - field=models.CharField(blank=True, max_length=64, null=True, unique=True), - ), - migrations.AlterField( - model_name="device", - name="variant", - field=models.CharField(blank=True, max_length=64, null=True), - ), - migrations.AlterField( - model_name="device", - name="version", - field=models.CharField(blank=True, max_length=64, null=True), - ), - ] diff --git a/device/migrations/0003_remove_component_type_remove_computer_type_and_more.py b/device/migrations/0003_remove_component_type_remove_computer_type_and_more.py deleted file mode 100644 index d57d6bc..0000000 --- a/device/migrations/0003_remove_component_type_remove_computer_type_and_more.py +++ /dev/null @@ -1,73 +0,0 @@ -# Generated by Django 5.0.6 on 2024-07-03 12:33 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("device", "0002_alter_device_brand_alter_device_devicehub_id_and_more"), - ] - - operations = [ - migrations.RemoveField( - model_name="component", - name="type", - ), - migrations.RemoveField( - model_name="computer", - name="type", - ), - migrations.RemoveField( - model_name="datastorage", - name="type", - ), - migrations.AlterField( - model_name="computer", - name="chassis", - field=models.CharField( - blank=True, - choices=[ - ("Tower", "Tower"), - ("All in one", "Allinone"), - ("Microtower", "Microtower"), - ("Netbook", "Netbook"), - ("Laptop", "Laptop"), - ("Tablet", "Tabler"), - ("Server", "Server"), - ("Non-physical device", "Virtual"), - ], - max_length=32, - null=True, - ), - ), - migrations.AlterField( - model_name="computer", - name="sku", - field=models.CharField(blank=True, max_length=32, null=True), - ), - migrations.AlterField( - model_name="device", - name="type", - field=models.CharField( - choices=[ - ("Desktop", "Desktop"), - ("Laptop", "Laptop"), - ("Server", "Server"), - ("GraphicCard", "Graphiccard"), - ("HardDrive", "Harddrive"), - ("SolidStateDrive", "Solidstatedrive"), - ("Motherboard", "Motherboard"), - ("NetworkAdapter", "Networkadapter"), - ("Processor", "Processor"), - ("RamModule", "Rammodule"), - ("SoundCard", "Soundcard"), - ("Display", "Display"), - ("Battery", "Battery"), - ("Camera", "Camera"), - ], - default="Laptop", - max_length=32, - ), - ), - ] -- 2.30.2