Compare commits
3 Commits
ac1786c115
...
3a93595396
Author | SHA1 | Date |
---|---|---|
Thomas Nahuel Rusiecki | 3a93595396 | |
Thomas Nahuel Rusiecki | 7b554c1b1f | |
Thomas Nahuel Rusiecki | 25d7a0de63 |
|
@ -0,0 +1,20 @@
|
|||
from django import forms
|
||||
from utils.device import create_annotation, create_doc, create_index
|
||||
from utils.save_snapshots import move_json, save_in_disk
|
||||
|
||||
from django.forms import formset_factory
|
||||
|
||||
class CustomStatusLabelForm(forms.Form):
|
||||
annotation_name = forms.CharField(
|
||||
label="Annotation Name",
|
||||
max_length=50,
|
||||
widget=forms.TextInput(attrs={'class': 'form-control'})
|
||||
)
|
||||
annotation_state = forms.CharField(
|
||||
label="Possible State",
|
||||
max_length=50,
|
||||
widget=forms.TextInput(attrs={'class': 'form-control'})
|
||||
)
|
||||
|
||||
|
||||
CustomStatusLabelFormSet = formset_factory(CustomStatusLabelForm, extra=1)
|
|
@ -10,9 +10,15 @@
|
|||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
|
||||
<a href="{% url 'admin:institution' user.institution.pk %}" class="btn btn-green-admin">
|
||||
{% translate "Institution" %}
|
||||
</a>
|
||||
|
||||
<a href="{% url 'admin:reserved'%}" class="btn btn-green-admin">
|
||||
{% translate "Reserved Annotations" %}
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
{% load django_bootstrap5 %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container mt-5">
|
||||
<div class="row mb-4">
|
||||
<div class="col">
|
||||
<h3 class="text-center">{{ subtitle }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form role="form" method="post" novalidate>
|
||||
{% csrf_token %}
|
||||
<div class="mb-3">
|
||||
{{ form.annotation_name.label_tag }}
|
||||
{{ form.annotation_name }}
|
||||
</div>
|
||||
|
||||
<h5 class="mt-4">{% translate "Possible States" %}</h5>
|
||||
<div id="formset">
|
||||
{{ formset.management_form }}
|
||||
{% for form in formset %}
|
||||
<div class="row mb-3 formset-form">
|
||||
<div class="col-md-10">
|
||||
{% bootstrap_field form.annotation_state show_label=False %}
|
||||
</div>
|
||||
<div class="col-md-2 d-flex align-items-center">
|
||||
{% if forloop.first %}
|
||||
<button type="button" class="btn btn-sm btn-success add-form">
|
||||
+
|
||||
</button>
|
||||
{% endif %}
|
||||
<button type="button" class="btn btn-sm btn-danger remove-form ms-2">
|
||||
−
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="container">
|
||||
<a class="btn btn-grey" href="{% url 'admin:panel' %}">{% translate "Cancel" %}</a>
|
||||
<input class="btn btn-green-admin" type="submit" name="submit" value="{% translate 'Save' %}" />
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
//fix this stub chatgpt code
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var formsetDiv = document.getElementById('formset');
|
||||
var totalForms = document.getElementById('id_form-TOTAL_FORMS');
|
||||
|
||||
function updateElementIndex(el, prefix, index) {
|
||||
var idRegex = new RegExp('(' + prefix + '-\\d+-)');
|
||||
var replacement = prefix + '-' + index + '-';
|
||||
if (el.id) el.id = el.id.replace(idRegex, replacement);
|
||||
if (el.name) el.name = el.name.replace(idRegex, replacement);
|
||||
}
|
||||
|
||||
function addForm(e) {
|
||||
e.preventDefault();
|
||||
var formCount = parseInt(totalForms.value);
|
||||
var newForm = document.querySelector('.formset-form').cloneNode(true);
|
||||
|
||||
newForm.querySelectorAll('input').forEach(function(input) {
|
||||
updateElementIndex(input, 'form', formCount);
|
||||
input.value = '';
|
||||
});
|
||||
|
||||
// Remove any hidden inputs (management form fields)
|
||||
newForm.querySelectorAll('input[type="hidden"]').forEach(function(hiddenInput) {
|
||||
hiddenInput.remove();
|
||||
});
|
||||
|
||||
// Attach event listeners to the new buttons
|
||||
var addButton = newForm.querySelector('.add-form');
|
||||
var removeButton = newForm.querySelector('.remove-form');
|
||||
|
||||
addButton.addEventListener('click', addForm);
|
||||
removeButton.addEventListener('click', removeForm);
|
||||
|
||||
// Ensure only the first form has the add button
|
||||
formsetDiv.querySelectorAll('.add-form').forEach(function(button, index) {
|
||||
if (index > 0) {
|
||||
button.remove();
|
||||
}
|
||||
});
|
||||
|
||||
formsetDiv.appendChild(newForm);
|
||||
totalForms.value = formCount + 1;
|
||||
}
|
||||
|
||||
function removeForm(e) {
|
||||
e.preventDefault();
|
||||
var formToRemove = e.target.closest('.formset-form');
|
||||
formToRemove.remove();
|
||||
|
||||
var forms = formsetDiv.querySelectorAll('.formset-form');
|
||||
totalForms.value = forms.length;
|
||||
|
||||
// Re-index form elements
|
||||
forms.forEach(function(form, index) {
|
||||
form.querySelectorAll('input').forEach(function(input) {
|
||||
updateElementIndex(input, 'form', index);
|
||||
});
|
||||
});
|
||||
|
||||
// Ensure only the first form has the add button
|
||||
formsetDiv.querySelectorAll('.add-form').forEach(function(button, index) {
|
||||
if (index > 0) {
|
||||
button.remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initial event listeners
|
||||
document.querySelectorAll('.add-form').forEach(function(button) {
|
||||
button.addEventListener('click', addForm);
|
||||
});
|
||||
|
||||
document.querySelectorAll('.remove-form').forEach(function(button) {
|
||||
button.addEventListener('click', removeForm);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -10,4 +10,5 @@ urlpatterns = [
|
|||
path("users/edit/<int:pk>", views.EditUserView.as_view(), name="edit_user"),
|
||||
path("users/delete/<int:pk>", views.DeleteUserView.as_view(), name="delete_user"),
|
||||
path("institution/<int:pk>", views.InstitutionView.as_view(), name="institution"),
|
||||
path("reserved", views.AddReservedAnnotationView.as_view(), name="reserved"),
|
||||
]
|
||||
|
|
|
@ -8,9 +8,15 @@ from django.views.generic.edit import (
|
|||
UpdateView,
|
||||
DeleteView,
|
||||
)
|
||||
from django.views.generic import FormView
|
||||
import logging
|
||||
from dashboard.mixins import DashboardView, Http403
|
||||
from user.models import User, Institution
|
||||
from admin.email import NotifyActivateUserByEmail
|
||||
from admin.forms import CustomStatusLabelForm, CustomStatusLabelFormSet
|
||||
from evidence.models import Annotation
|
||||
|
||||
logger = logging.getLogger('dhub')
|
||||
|
||||
|
||||
class AdminView(DashboardView):
|
||||
|
@ -124,3 +130,46 @@ class InstitutionView(AdminView, UpdateView):
|
|||
self.object = self.request.user.institution
|
||||
kwargs = super().get_form_kwargs()
|
||||
return kwargs
|
||||
|
||||
|
||||
|
||||
class AddReservedAnnotationView(AdminView, FormView):
|
||||
template_name = "reserved.html"
|
||||
title = _("New Custom State Labels")
|
||||
breadcrumb = "Admin / Custom State Labels (new name?)"
|
||||
success_url = reverse_lazy('admin:panel')
|
||||
model = Annotation
|
||||
|
||||
form_class = CustomStatusLabelForm
|
||||
formset_class = CustomStatusLabelFormSet
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
if self.request.POST:
|
||||
context['formset'] = self.formset_class(self.request.POST)
|
||||
else:
|
||||
context['formset'] = self.formset_class()
|
||||
context['subtitle'] = _("Add Custom Status Label")
|
||||
return context
|
||||
|
||||
def form_valid(self, form):
|
||||
context = self.get_context_data()
|
||||
formset = context['formset']
|
||||
if formset.is_valid():
|
||||
annotation_name = form.cleaned_data['annotation_name']
|
||||
|
||||
logger.info("Saving to db: " + annotation_name)
|
||||
annotation = Annotation.objects.create(name=annotation_name)
|
||||
for form in formset:
|
||||
state = form.cleaned_data.get('annotation_state')
|
||||
if state:
|
||||
PossibleValue.objects.create(annotation=annotation, value=state)
|
||||
|
||||
logger.info("Saved to db: " + annotation_name)
|
||||
self.success_message = _("Custom status label has been added.")
|
||||
self.success_url = reverse_lazy('admin:panel')
|
||||
return super().form_valid(form)
|
||||
else:
|
||||
logger.error("Formset is not valid")
|
||||
logger.error(formset.errors)
|
||||
return self.form_invalid(form)
|
|
@ -15,6 +15,7 @@ class Annotation(models.Model):
|
|||
USER = 1, "User"
|
||||
DOCUMENT = 2, "Document"
|
||||
ERASE_SERVER = 3, "EraseServer"
|
||||
ADMIN = 4, "Admin"
|
||||
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
uuid = models.UUIDField()
|
||||
|
@ -28,7 +29,32 @@ class Annotation(models.Model):
|
|||
constraints = [
|
||||
models.UniqueConstraint(fields=["type", "key", "uuid"], name="unique_type_key_uuid")
|
||||
]
|
||||
#TODO: check if this works properly
|
||||
def clean(self):
|
||||
super().clean()
|
||||
if self.type == self.Type.ADMIN:
|
||||
if Annotation.objects.filter(type=self.Type.ADMIN, key=self.key).exists():
|
||||
raise ValidationError(f"The key '{self.key}' is already reserved by admin.")
|
||||
else:
|
||||
if Annotation.objects.filter(type=self.Type.ADMIN, key=self.key).exists():
|
||||
raise ValidationError(f"The key '{self.key}' is reserved by admin and cannot be used.")
|
||||
|
||||
class AllowedValue(models.Model):
|
||||
annotation = models.ForeignKey(Annotation, on_delete=models.CASCADE, limit_choices_to={'type': Annotation.Type.ADMIN})
|
||||
value = models.CharField(max_length=50)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return self.value
|
||||
|
||||
#This represents a change on a System-type Annotation
|
||||
class Action(models.Model):
|
||||
|
||||
annotation = models.ForeignKey(Annotation, on_delete=models.CASCADE, limit_choices_to={'type': Annotation.Type.ADMIN})
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
owner = models.ForeignKey(Institution, on_delete=models.CASCADE)
|
||||
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
|
||||
comment = models.CharField(max_length=250)
|
||||
|
||||
class Evidence:
|
||||
def __init__(self, uuid):
|
||||
|
|
Loading…
Reference in New Issue