diff --git a/action/models.py b/action/models.py
index bf49e17..913246a 100644
--- a/action/models.py
+++ b/action/models.py
@@ -14,7 +14,7 @@ class State(models.Model):
def clean(self):
if not StateDefinition.objects.filter(institution=self.institution, state=self.state).exists():
raise ValidationError(f"The state '{self.state}' is not valid for the institution '{self.institution.name}'.")
-
+
def save(self, *args, **kwargs):
self.clean()
super().save(*args, **kwargs)
@@ -22,6 +22,7 @@ class State(models.Model):
def __str__(self):
return f"{self.institution.name} - {self.state} - {self.snapshot_uuid}"
+
class StateDefinition(models.Model):
institution = models.ForeignKey(Institution, on_delete=models.CASCADE)
@@ -41,7 +42,7 @@ class StateDefinition(models.Model):
self.order = (max_order or 0) + 1
super().save(*args, **kwargs)
-
+
def delete(self, *args, **kwargs):
institution = self.institution
order = self.order
diff --git a/device/templates/new_user_property.html b/device/templates/new_user_property.html
index ac16bf8..2ae337e 100644
--- a/device/templates/new_user_property.html
+++ b/device/templates/new_user_property.html
@@ -36,7 +36,7 @@
{% endfor %}
diff --git a/device/views.py b/device/views.py
index 8d79b22..724e13c 100644
--- a/device/views.py
+++ b/device/views.py
@@ -1,7 +1,9 @@
import json
import logging
+
from django.http import JsonResponse
from django.conf import settings
+from django.db import IntegrityError
from django.urls import reverse_lazy
from django.contrib import messages
from django.shortcuts import get_object_or_404, redirect, Http404
@@ -24,6 +26,16 @@ if settings.DPP:
from dpp.api_dlt import PROOF_TYPE
+class DeviceLogMixin(DashboardView):
+
+ def log_registry(self, _uuid, msg):
+ DeviceLog.objects.create(
+ snapshot_uuid=_uuid,
+ event=msg,
+ user=self.request.user,
+ institution=self.request.user.institution
+ )
+
class NewDeviceView(DashboardView, FormView):
template_name = "new_device.html"
title = _("New Device")
@@ -189,7 +201,7 @@ class PublicDeviceWebView(TemplateView):
return JsonResponse(device_data)
-class AddUserPropertyView(DashboardView, CreateView):
+class AddUserPropertyView(DeviceLogMixin, CreateView):
template_name = "new_user_property.html"
title = _("New User Property")
breadcrumb = "Device / New Property"
@@ -202,17 +214,19 @@ class AddUserPropertyView(DashboardView, CreateView):
form.instance.uuid = self.property.uuid
form.instance.type = UserProperty.Type.USER
- message = _(" UserProperty: {}: {}".format(form.instance.key, form.instance.value))
- DeviceLog.objects.create(
- snapshot_uuid=form.instance.uuid,
- event=message,
- user=self.request.user,
- institution=self.request.user.institution
- )
+ try:
+ response = super().form_valid(form)
+ messages.success(self.request, _("Property successfully added."))
+ log_message = _(" UserProperty: {}: {}".format(
+ form.instance.key,
+ form.instance.value
+ ))
- messages.success(self.request, _("User property successfully added."))
- response = super().form_valid(form)
- return response
+ self.log_registry(form.instance.uuid, log_message)
+ return response
+ except IntegrityError:
+ messages.error(self.request, _("Property is already defined."))
+ return self.form_invalid(form)
def get_form_kwargs(self):
pk = self.kwargs.get('pk')
@@ -222,10 +236,15 @@ class AddUserPropertyView(DashboardView, CreateView):
return super().get_form_kwargs()
def get_success_url(self):
- return reverse_lazy('device:details', args=[self.kwargs.get('pk')])
+ pk = self.kwargs.get('pk')
+ return reverse_lazy('device:details', args=[pk]) + "#user_properties"
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context['pk'] = self.kwargs.get('pk')
+ return context
-class UpdateUserPropertyView(DashboardView, UpdateView):
+class UpdateUserPropertyView(DeviceLogMixin, UpdateView):
template_name = "new_user_property.html"
title = _("Update User Property")
breadcrumb = "Device / Update Property"
@@ -250,22 +269,34 @@ class UpdateUserPropertyView(DashboardView, UpdateView):
new_key = form.cleaned_data['key']
new_value = form.cleaned_data['value']
- message = _(" UserProperty: {}: {} to {}: {}".format(old_key, old_value, new_key, new_value))
- DeviceLog.objects.create(
- snapshot_uuid=form.instance.uuid,
- event=message,
- user=self.request.user,
- institution=self.request.user.institution
- )
+ try:
+ super().form_valid(form)
+ messages.success(self.request, _("Property updated successfully."))
+ log_message = _(" UserProperty: {}: {} to {}: {}".format(
+ old_key,
+ old_value,
+ new_key,
+ new_value
+ ))
+ self.log_registry(form.instance.uuid, log_message)
+ # return response
+ return redirect(self.get_success_url()+"#user_properties")
+ except IntegrityError:
+ messages.error(self.request, _("Property is already defined."))
+ return self.form_invalid(form)
- messages.success(self.request, _("User property updated successfully."))
- return super().form_valid(form)
+ def form_invalid(self, form):
+ super().form_invalid(form)
+ return redirect(self.get_success_url()+"#user_properties")
def get_success_url(self):
- return self.request.META.get('HTTP_REFERER', reverse_lazy('device:details', args=[self.object.pk]))
+ return self.request.META.get(
+ 'HTTP_REFERER',
+ reverse_lazy('device:details', args=[self.object.pk])
+ )
-class DeleteUserPropertyView(DashboardView, DeleteView):
+class DeleteUserPropertyView(DeviceLogMixin, DeleteView):
model = UserProperty
def get_queryset(self):
@@ -276,14 +307,11 @@ class DeleteUserPropertyView(DashboardView, DeleteView):
self.object = self.get_object()
self.object.delete()
- message = _(" User Property: {}:{}".format(self.object.key, self.object.value ))
- DeviceLog.objects.create(
- snapshot_uuid=self.object.uuid,
- event=message,
- user=self.request.user,
- institution=self.request.user.institution
- )
-
+ msg = _(" User Property: {}:{}".format(
+ self.object.key,
+ self.object.value
+ ))
+ self.log_registry(self.object.uuid, msg)
messages.info(self.request, _("User property deleted successfully."))
return self.handle_success()
@@ -292,4 +320,6 @@ class DeleteUserPropertyView(DashboardView, DeleteView):
return redirect(self.get_success_url())
def get_success_url(self):
- return self.request.META.get('HTTP_REFERER', reverse_lazy('device:details', args=[self.object.pk]))
+ pk = self.object.pk
+ url = reverse_lazy('device:details', args=[pk])
+ return self.request.META.get('HTTP_REFERER', url) + "#user_properties"
diff --git a/evidence/migrations/0006_userproperty_userproperty_unique_type_key_uuid.py b/evidence/migrations/0006_userproperty_userproperty_unique_type_key_uuid.py
new file mode 100644
index 0000000..66d8868
--- /dev/null
+++ b/evidence/migrations/0006_userproperty_userproperty_unique_type_key_uuid.py
@@ -0,0 +1,20 @@
+# Generated by Django 5.0.6 on 2025-01-30 17:52
+
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('evidence', '0005_alter_userproperty_type'),
+ ('user', '0001_initial'),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.AddConstraint(
+ model_name='userproperty',
+ constraint=models.UniqueConstraint(fields=('key', 'uuid'), name='userproperty_unique_type_key_uuid'),
+ ),
+ ]
diff --git a/evidence/models.py b/evidence/models.py
index 9a57344..98c0256 100644
--- a/evidence/models.py
+++ b/evidence/models.py
@@ -37,14 +37,20 @@ class SystemProperty(Property):
class UserProperty(Property):
- uuid = models.UUIDField()
class Type(models.IntegerChoices):
USER = 1, "User"
ERASE_SERVER = 2, "EraseServer"
+ uuid = models.UUIDField()
type = models.SmallIntegerField(choices=Type, default=Type.USER)
+ class Meta:
+ constraints = [
+ models.UniqueConstraint(
+ fields=["key", "uuid"], name="userproperty_unique_type_key_uuid")
+ ]
+
class Evidence:
def __init__(self, uuid):