Merge branch 'rework/properties' into feature/states

This commit is contained in:
Thomas Nahuel Rusiecki 2024-12-11 15:03:28 -03:00
commit f1f2964785
15 changed files with 250 additions and 81 deletions

View file

@ -4,6 +4,7 @@ DEMO=true
DEBUG=true
ALLOWED_HOSTS=localhost,localhost:8000,127.0.0.1,
DEVICE_LOG_PATH=/tmp
STATIC_ROOT=/tmp/static/
MEDIA_ROOT=/tmp/media/
EMAIL_HOST="mail.example.org"

View file

@ -21,7 +21,7 @@ from django.views.generic.edit import (
from utils.save_snapshots import move_json, save_in_disk
from django.views.generic.edit import View
from dashboard.mixins import DashboardView
from evidence.models import SystemProperty, UserProperty, Property
from evidence.models import SystemProperty, UserProperty
from evidence.parse_details import ParseSnapshot
from evidence.parse import Build
from device.models import Device
@ -113,7 +113,6 @@ class NewSnapshotView(ApiMixing):
property = SystemProperty.objects.filter(
uuid=data['uuid'],
type=Property.Type.SYSTEM,
# TODO this is hardcoded, it should select the user preferred algorithm
key="hidalgo1",
owner=self.tk.owner.institution
@ -281,7 +280,6 @@ class AddPropertyView(ApiMixing):
self.property = SystemProperty.objects.filter(
owner=institution,
value=self.pk,
type=Property.Type.SYSTEM
).first()
if not self.property:

View file

@ -6,7 +6,7 @@ from django.shortcuts import Http404
from django.db.models import Q
from dashboard.mixins import InventaryMixin, DetailsMixin
from evidence.models import Property, SystemProperty
from evidence.models import SystemProperty
from evidence.xapian import search
from device.models import Device
from lot.models import Lot
@ -96,7 +96,6 @@ class SearchView(InventaryMixin):
qry |= Q(value__startswith=i)
chids = SystemProperty.objects.filter(
type=Property.Type.SYSTEM,
owner=self.request.user.institution
).filter(
qry

View file

@ -1,7 +1,7 @@
from django.db import models, connection
from utils.constants import ALGOS
from evidence.models import SystemProperty, UserProperty, Property, Evidence
from evidence.models import SystemProperty, UserProperty, Evidence
from lot.models import DeviceLot
@ -49,7 +49,6 @@ class Device:
return self.properties
self.properties = SystemProperty.objects.filter(
type=Property.Type.SYSTEM,
value=self.id
).order_by("-created")
@ -66,6 +65,7 @@ class Device:
user_properties = UserProperty.objects.filter(
uuid__in=self.uuids,
owner=self.owner,
type=UserProperty.Type.USER,
)
return user_properties
@ -73,10 +73,10 @@ class Device:
if not self.uuids:
self.get_uuids()
properties = SystemProperty.objects.filter(
properties = UserProperty.objects.filter(
uuid__in=self.uuids,
owner=self.owner,
type=Property.Type.DOCUMENT
type=UserProperty.Type.DOCUMENT
)
return properties
@ -91,7 +91,6 @@ class Device:
algos = list(ALGOS.keys())
algos.append('CUSTOM_ID')
self.hids = list(set(properties.filter(
type=Property.Type.SYSTEM,
key__in=algos,
).values_list("value", flat=True)))
@ -115,10 +114,10 @@ class Device:
if not self.uuids:
return False
property = SystemProperty.objects.filter(
property = UserProperty.objects.filter(
uuid__in=self.uuids,
owner=self.owner,
type=Property.Type.ERASE_SERVER
type=UserProperty.Type.ERASE_SERVER
).first()
if property:
@ -154,7 +153,6 @@ class Device:
LEFT JOIN lot_devicelot AS t2 ON t1.value = t2.device_id
WHERE t2.device_id IS NULL
AND t1.owner_id = {institution}
AND t1.type = {type}
)
SELECT DISTINCT
value
@ -164,7 +162,6 @@ class Device:
row_num = 1
""".format(
institution=institution.id,
type=Property.Type.SYSTEM,
)
if limit:
sql += " limit {} offset {}".format(int(limit), int(offset))
@ -202,7 +199,6 @@ class Device:
LEFT JOIN lot_devicelot AS t2 ON t1.value = t2.device_id
WHERE t2.device_id IS NULL
AND t1.owner_id = {institution}
And t1.type = '{type}'
)
SELECT
COUNT(DISTINCT value)
@ -212,7 +208,6 @@ class Device:
row_num = 1
""".format(
institution=institution.id,
type=Property.Type.SYSTEM,
)
with connection.cursor() as cursor:
cursor.execute(sql)
@ -239,7 +234,6 @@ class Device:
LEFT JOIN lot_devicelot AS t2 ON t1.value = t2.device_id
WHERE t2.device_id IS NULL
AND t1.owner_id = {institution}
AND t1.type = '{type}'
AND t1.uuid = '{uuid}'
)
SELECT DISTINCT
@ -251,7 +245,6 @@ class Device:
""".format(
uuid=uuid.replace("-", ""),
institution=institution.id,
type=Property.Type.SYSTEM,
)
properties = []

View file

@ -16,7 +16,7 @@ from django.views.generic.edit import (
from django.views.generic.base import TemplateView
from action.models import StateDefinition, State
from dashboard.mixins import DashboardView, Http403
from evidence.models import UserProperty, SystemProperty, Property
from evidence.models import UserProperty, SystemProperty
from lot.models import LotTag
from device.models import Device
from device.forms import DeviceFormSet
@ -189,9 +189,14 @@ class AddUserPropertyView(DashboardView, CreateView):
form.instance.owner = self.request.user.institution
form.instance.user = self.request.user
form.instance.uuid = self.property.uuid
form.instance.type = Property.Type.USER
form.instance.type = UserProperty.Type.USER
messages.success(self.request, _("User property successfully added."))
device_logger.info(
f"Created user property (key='{form.instance.key}', value='{form.instance.value}') by user {self.request.user}, for evidence uuid: {self.property.uuid}."
)
response = super().form_valid(form)
return response
@ -201,7 +206,6 @@ class AddUserPropertyView(DashboardView, CreateView):
self.property = SystemProperty.objects.filter(
owner=institution,
value=pk,
type=Property.Type.SYSTEM
).first()
if not self.property:
@ -237,7 +241,7 @@ class UpdateUserPropertyView(DashboardView, UpdateView):
form.instance.owner = self.request.user.institution
form.instance.user = self.request.user
form.instance.type = Property.Type.USER
form.instance.type = UserProperty.Type.USER
response = super().form_valid(form)
messages.success(self.request, _("User property updated successfully."))
@ -278,14 +282,14 @@ class AddDocumentView(DashboardView, CreateView):
title = _("New Document")
breadcrumb = "Device / New document"
success_url = reverse_lazy('dashboard:unassigned_devices')
model = SystemProperty
model = UserProperty
fields = ("key", "value")
def form_valid(self, form):
form.instance.owner = self.request.user.institution
form.instance.user = self.request.user
form.instance.uuid = self.property.uuid
form.instance.type = Property.Type.DOCUMENT
form.instance.type = UserProperty.Type.DOCUMENT
response = super().form_valid(form)
return response
@ -295,7 +299,6 @@ class AddDocumentView(DashboardView, CreateView):
self.property = SystemProperty.objects.filter(
owner=institution,
value=pk,
type=Property.Type.SYSTEM
).first()
if not self.property:

View file

@ -65,6 +65,8 @@ ENABLE_EMAIL = config("ENABLE_EMAIL", default=True, cast=bool)
EVIDENCES_DIR = config("EVIDENCES_DIR", default=os.path.join(BASE_DIR, "db"))
DEVICE_LOG_PATH = config("DEVICE_LOG_PATH", default="/tmp")
# Application definition
INSTALLED_APPS = [
@ -224,7 +226,7 @@ LOGGING = {
'device_log_file': {
'level': 'INFO',
'class': 'logging.FileHandler',
'filename': '/var/log/device_changes.log',
'filename': DEVICE_LOG_PATH + "/device_changes.log",
'formatter': 'verbose',
},
},

View file

@ -8,7 +8,7 @@ from utils.device import create_property, create_doc, create_index
from utils.forms import MultipleFileField
from device.models import Device
from evidence.parse import Build
from evidence.models import SystemProperty, Property
from evidence.models import SystemProperty
from utils.save_snapshots import move_json, save_in_disk
@ -70,7 +70,6 @@ class UserTagForm(forms.Form):
self.user = kwargs.pop('user')
instance = SystemProperty.objects.filter(
uuid=self.uuid,
type=Property.Type.SYSTEM,
key='CUSTOM_ID',
owner=self.user.institution
).first()
@ -88,7 +87,6 @@ class UserTagForm(forms.Form):
self.tag = data
self.instance = SystemProperty.objects.filter(
uuid=self.uuid,
type=Property.Type.SYSTEM,
key='CUSTOM_ID',
owner=self.user.institution
).first()
@ -108,7 +106,6 @@ class UserTagForm(forms.Form):
SystemProperty.objects.create(
uuid=self.uuid,
type=Property.Type.SYSTEM,
key='CUSTOM_ID',
value=self.tag,
owner=self.user.institution,
@ -186,9 +183,9 @@ class EraseServerForm(forms.Form):
self.pk = None
self.uuid = kwargs.pop('uuid', None)
self.user = kwargs.pop('user')
instance = SystemProperty.objects.filter(
instance = UserProperty.objects.filter(
uuid=self.uuid,
type=SystemProperty.Type.ERASE_SERVER,
type=UserProperty.Type.ERASE_SERVER,
key='ERASE_SERVER',
owner=self.user.institution
).first()
@ -201,9 +198,9 @@ class EraseServerForm(forms.Form):
def clean(self):
self.erase_server = self.cleaned_data.get('erase_server', False)
self.instance = SystemProperty.objects.filter(
self.instance = UserProperty.objects.filter(
uuid=self.uuid,
type=Property.Type.ERASE_SERVER,
type=UserProperty.Type.ERASE_SERVER,
key='ERASE_SERVER',
owner=self.user.institution
).first()
@ -222,9 +219,9 @@ class EraseServerForm(forms.Form):
if self.instance:
return
SystemProperty.objects.create(
UserProperty.objects.create(
uuid=self.uuid,
type=Property.Type.ERASE_SERVER,
type=UserProperty.Type.ERASE_SERVER,
key='ERASE_SERVER',
value=self.erase_server,
owner=self.user.institution,

View file

@ -0,0 +1,107 @@
# Generated by Django 5.0.6 on 2024-12-10 19:37
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("evidence", "0002_alter_annotation_type"),
("user", "0001_initial"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name="SystemProperty",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("created", models.DateTimeField(auto_now_add=True)),
("key", models.CharField(max_length=256)),
("value", models.CharField(max_length=256)),
("uuid", models.UUIDField()),
(
"owner",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="user.institution",
),
),
(
"user",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to=settings.AUTH_USER_MODEL,
),
),
],
),
migrations.CreateModel(
name="UserProperty",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("created", models.DateTimeField(auto_now_add=True)),
("key", models.CharField(max_length=256)),
("value", models.CharField(max_length=256)),
("uuid", models.UUIDField()),
(
"type",
models.SmallIntegerField(
choices=[(1, "User"), (2, "Document"), (3, "EraseServer")],
default=1,
),
),
(
"owner",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="user.institution",
),
),
(
"user",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to=settings.AUTH_USER_MODEL,
),
),
],
),
migrations.DeleteModel(
name="Annotation",
),
migrations.AddConstraint(
model_name="systemproperty",
constraint=models.UniqueConstraint(
fields=("key", "uuid"), name="system_unique_type_key_uuid"
),
),
migrations.AddConstraint(
model_name="userproperty",
constraint=models.UniqueConstraint(
fields=("key", "uuid", "type"), name="user_unique_type_key_uuid"
),
),
]

View file

@ -10,20 +10,12 @@ from evidence.xapian import search
from evidence.parse_details import ParseSnapshot
from user.models import User, Institution
#TODO: base class is abstract; revise if should be for query efficiency
class Property(models.Model):
class Type(models.IntegerChoices):
SYSTEM = 0, "System"
USER = 1, "User"
DOCUMENT = 2, "Document"
ERASE_SERVER = 3, "EraseServer"
class Property(models.Model):
created = models.DateTimeField(auto_now_add=True)
uuid = models.UUIDField()
owner = models.ForeignKey(Institution, on_delete=models.CASCADE)
user = models.ForeignKey(
User, on_delete=models.SET_NULL, null=True, blank=True)
type = models.SmallIntegerField(choices=Type)
key = models.CharField(max_length=STR_EXTEND_SIZE)
value = models.CharField(max_length=STR_EXTEND_SIZE)
@ -31,40 +23,34 @@ class Property(models.Model):
#Only for shared behaviour, it is not a table
abstract = True
class SystemProperty(Property):
uuid = models.UUIDField()
class Meta:
constraints = [
models.CheckConstraint(
check=~Q(type=1), #Enforce that type is not User
name='property_cannot_be_user'
),
]
#Django orm wont inherit constraints to child
#TODO: check if this is needed
constraints = [
models.UniqueConstraint(
fields=["type", "key", "uuid"], name="system_unique_type_key_uuid")
fields=["key", "uuid"], name="system_unique_type_key_uuid")
]
class UserProperty(Property):
uuid = models.UUIDField()
type = models.SmallIntegerField(default=Property.Type.USER)
class Type(models.IntegerChoices):
USER = 1, "User"
DOCUMENT = 2, "Document"
ERASE_SERVER = 3, "EraseServer"
type = models.SmallIntegerField(choices=Type, default=Type.USER)
class Meta:
constraints = [
models.CheckConstraint(
check=Q(type=1), #Enforce that type is User
name='property_needs_to_be_user'
),
]
constraints = [
models.UniqueConstraint(
fields=["type", "key", "uuid"], name="user_unique_type_key_uuid")
fields=["key", "uuid", "type"], name="user_unique_type_key_uuid")
]
class Evidence:
def __init__(self, uuid):
self.uuid = uuid
@ -166,7 +152,6 @@ class Evidence:
def get_all(cls, user):
return SystemProperty.objects.filter(
owner=user.institution,
type=Property.Type.SYSTEM,
key="hidalgo1",
).order_by("-created").values_list("uuid", "created").distinct()

View file

@ -6,7 +6,7 @@ from dmidecode import DMIParse
from json_repair import repair_json
from evidence.parse_details import get_lshw_child
from evidence.models import SystemProperty, Property
from evidence.models import SystemProperty
from evidence.xapian import index
from utils.constants import CHASSIS_DH
@ -76,7 +76,6 @@ class Build:
property = SystemProperty.objects.filter(
uuid=self.uuid,
owner=self.user.institution,
type=Property.Type.SYSTEM,
)
if property:
@ -89,7 +88,6 @@ class Build:
uuid=self.uuid,
owner=self.user.institution,
user=self.user,
type=Property.Type.SYSTEM,
key=k,
value=v
)

View file

@ -13,7 +13,7 @@ from django.views.generic.edit import (
)
from dashboard.mixins import DashboardView, Http403
from evidence.models import Property, SystemProperty, UserProperty, Evidence
from evidence.models import SystemProperty, UserProperty, Evidence
from evidence.forms import (
UploadForm,
UserTagForm,

View file

@ -0,0 +1,77 @@
# Generated by Django 5.0.6 on 2024-12-10 19:37
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("lot", "0002_alter_lot_closed"),
("user", "0001_initial"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name="LotProperty",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("created", models.DateTimeField(auto_now_add=True)),
("key", models.CharField(max_length=256)),
("value", models.CharField(max_length=256)),
(
"type",
models.SmallIntegerField(
choices=[
(0, "System"),
(1, "User"),
(2, "Document"),
(3, "EraseServer"),
],
default=1,
),
),
(
"lot",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="lot.lot"
),
),
(
"owner",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="user.institution",
),
),
(
"user",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to=settings.AUTH_USER_MODEL,
),
),
],
),
migrations.DeleteModel(
name="LotAnnotation",
),
migrations.AddConstraint(
model_name="lotproperty",
constraint=models.UniqueConstraint(
fields=("key", "lot", "type"), name="lot_unique_type_key_lot"
),
),
]

View file

@ -6,8 +6,8 @@ from utils.constants import (
STR_EXTEND_SIZE,
)
from user.models import User, Institution
from device.models import Property
from user.models import User, Institution
from evidence.models import Property
# from device.models import Device
@ -46,7 +46,19 @@ class Lot(models.Model):
d.delete()
class LotProperty (Property):
#uuid is not needed for id
uuid = None
#lot foreign key is
lot = models.ForeignKey(Lot, on_delete=models.CASCADE)
class Type(models.IntegerChoices):
SYSTEM = 0, "System"
USER = 1, "User"
DOCUMENT = 2, "Document"
ERASE_SERVER = 3, "EraseServer"
type = models.SmallIntegerField(choices=Type.choices, default=Type.USER)
class Meta:
constraints = [
models.UniqueConstraint(
fields=["key", "lot", "type"], name="lot_unique_type_key_lot"
)
]

View file

@ -11,7 +11,6 @@ from django.views.generic.edit import (
from dashboard.mixins import DashboardView
from lot.models import Lot, LotTag, LotProperty
from lot.forms import LotsForm
from device.models import Property
class NewLotView(DashboardView, CreateView):
template_name = "new_lot.html"
@ -154,7 +153,7 @@ class LotAddDocumentView(DashboardView, CreateView):
form.instance.owner = self.request.user.institution
form.instance.user = self.request.user
form.instance.lot = self.lot
form.instance.type = Property.Type.DOCUMENT
form.instance.type = LotProperty.Type.DOCUMENT
response = super().form_valid(form)
return response
@ -178,7 +177,7 @@ class LotDocumentsView(DashboardView, TemplateView):
documents = LotProperty.objects.filter(
lot=lot,
owner=self.request.user.institution,
type=Property.Type.DOCUMENT,
type=LotProperty.Type.DOCUMENT,
)
context.update({
'lot': lot,
@ -201,7 +200,7 @@ class LotPropertiesView(DashboardView, TemplateView):
properties = LotProperty.objects.filter(
lot=lot,
owner=self.request.user.institution,
type=Property.Type.USER,
type=LotProperty.Type.USER,
)
context.update({
'lot': lot,
@ -224,7 +223,7 @@ class LotAddPropertyView(DashboardView, CreateView):
form.instance.owner = self.request.user.institution
form.instance.user = self.request.user
form.instance.lot = self.lot
form.instance.type = Property.Type.USER
form.instance.type = LotProperty.Type.USER
response = super().form_valid(form)
return response

View file

@ -6,7 +6,7 @@ import logging
from django.core.exceptions import ValidationError
from evidence.xapian import index
from evidence.models import SystemProperty, Property
from evidence.models import SystemProperty
from device.models import Device
@ -76,7 +76,6 @@ def create_property(doc, user, commit=False):
'uuid': doc['uuid'],
'owner': user.institution,
'user': user,
'type': Property.Type.SYSTEM,
'key': 'CUSTOMER_ID',
'value': doc['CUSTOMER_ID'],
}
@ -84,7 +83,6 @@ def create_property(doc, user, commit=False):
property = SystemProperty.objects.filter(
uuid=doc["uuid"],
owner=user.institution,
type=Property.Type.SYSTEM,
)
if property: