simpler state change and action input
This commit is contained in:
parent
63b8815d1b
commit
070004f9ea
|
@ -2,21 +2,15 @@ from django import forms
|
|||
from .models import State
|
||||
|
||||
|
||||
class AddStateForm(forms.Form):
|
||||
add_note = forms.BooleanField(required=False)
|
||||
class ChangeStateForm(forms.Form):
|
||||
previous_state = forms.CharField(widget=forms.HiddenInput())
|
||||
snapshot_uuid = forms.UUIDField(widget=forms.HiddenInput())
|
||||
new_state = forms.CharField(widget=forms.HiddenInput())
|
||||
|
||||
|
||||
class AddNoteForm(forms.Form):
|
||||
snapshot_uuid = forms.UUIDField(widget=forms.HiddenInput())
|
||||
note = forms.CharField(
|
||||
required=False,
|
||||
required=True,
|
||||
widget=forms.Textarea(attrs={'rows': 4, 'maxlength': 200, 'placeholder': 'Max 200 characters'}),
|
||||
)
|
||||
state_id = forms.IntegerField(required=True, widget=forms.HiddenInput())
|
||||
snapshot_uuid = forms.UUIDField(required=True, widget=forms.HiddenInput())
|
||||
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
add_note = cleaned_data.get('add_note')
|
||||
note = cleaned_data.get('note')
|
||||
|
||||
if add_note == True and not note:
|
||||
self.add_error('note', 'Please enter a note if you checked "Add a note".')
|
||||
return cleaned_data
|
|
@ -58,7 +58,7 @@ class Note(models.Model):
|
|||
institution = models.ForeignKey(Institution, on_delete=models.CASCADE)
|
||||
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
|
||||
date = models.DateTimeField(auto_now_add=True)
|
||||
description = models.TextField(max_lenght=250)
|
||||
description = models.TextField()
|
||||
snapshot_uuid = models.UUIDField()
|
||||
|
||||
class Meta:
|
||||
|
|
|
@ -5,7 +5,8 @@ app_name = 'action'
|
|||
|
||||
urlpatterns = [
|
||||
|
||||
path("new/", views.NewActionView.as_view(), name="new_action"),
|
||||
path('state/<int:pk>/undo/', views.ActionUndoView.as_view(), name='undo_action'),
|
||||
path("new/", views.ChangeStateView.as_view(), name="change_state"),
|
||||
path('state/<int:pk>/undo/', views.UndoStateView.as_view(), name='undo_state'),
|
||||
path('note/add/', views.AddNoteView.as_view(), name='add_note'),
|
||||
|
||||
]
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
from django.views import View
|
||||
from django.shortcuts import redirect, get_object_or_404
|
||||
from django.contrib import messages
|
||||
from action.forms import AddStateForm
|
||||
from django.views.generic.edit import DeleteView
|
||||
from action.forms import ChangeStateForm, AddNoteForm
|
||||
from django.views.generic.edit import DeleteView, CreateView, FormView
|
||||
from django.urls import reverse_lazy
|
||||
from action.models import State, StateDefinition
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from action.models import State, StateDefinition, Note
|
||||
from device.models import Device
|
||||
import logging
|
||||
|
||||
|
@ -12,36 +13,35 @@ import logging
|
|||
device_logger = logging.getLogger('device_log')
|
||||
|
||||
|
||||
class NewActionView(View):
|
||||
class ChangeStateView(View):
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
form = AddStateForm(request.POST)
|
||||
form = ChangeStateForm(request.POST)
|
||||
|
||||
if form.is_valid():
|
||||
state_definition_id = form.cleaned_data['state_id']
|
||||
state_definition = get_object_or_404(StateDefinition, pk=state_definition_id)
|
||||
previous_state = form.cleaned_data['previous_state']
|
||||
new_state = form.cleaned_data['new_state']
|
||||
snapshot_uuid = form.cleaned_data['snapshot_uuid']
|
||||
#TODO: implement notes
|
||||
note = form.cleaned_data.get('note', '')
|
||||
|
||||
state = State.objects.create(
|
||||
State.objects.create(
|
||||
snapshot_uuid=snapshot_uuid,
|
||||
state=state_definition.state,
|
||||
user=request.user,
|
||||
institution=request.user.institution,
|
||||
state=new_state,
|
||||
user=self.request.user,
|
||||
institution=self.request.user.institution,
|
||||
)
|
||||
#TODO: also change logger for full fledged table
|
||||
device_logger.info(f"<Updated> State to '{state_definition.state}', for device '{snapshot_uuid}') by user {self.request.user}.")
|
||||
|
||||
messages.success(request, f"Action to '{state_definition.state}' has been added.")
|
||||
return redirect(request.META.get('HTTP_REFERER'))
|
||||
device_logger.info(f"<Updated> State to '{new_state}', from '{previous_state}' ) by user {self.request.user}.")
|
||||
|
||||
message = _("State changed from '{}' to '{}'.".format(previous_state, new_state) )
|
||||
messages.success(request,message)
|
||||
else:
|
||||
messages.error(request, "There was an error with your submission.")
|
||||
return redirect(request.META.get('HTTP_REFERER'))
|
||||
|
||||
return redirect(request.META.get('HTTP_REFERER') )
|
||||
|
||||
|
||||
class ActionUndoView(DeleteView):
|
||||
model = State
|
||||
class UndoStateView(DeleteView):
|
||||
model = State
|
||||
|
||||
def delete(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
|
@ -52,3 +52,24 @@ class ActionUndoView(DeleteView):
|
|||
messages.info(self.request, f"Action to state: {self.object.state} has been deleted.")
|
||||
device_logger.info(f"<Deleted> State '{self.object.state}', for device '{self.object.snapshot_uuid}') by user {self.request.user}.")
|
||||
return self.request.META.get('HTTP_REFERER', reverse_lazy('device:details', args=[self.object.snapshot_uuid]))
|
||||
|
||||
|
||||
class AddNoteView(View):
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
form = AddNoteForm(request.POST)
|
||||
|
||||
if form.is_valid():
|
||||
note = form.cleaned_data['note']
|
||||
snapshot_uuid = form.cleaned_data['snapshot_uuid']
|
||||
Note.objects.create(
|
||||
snapshot_uuid=snapshot_uuid,
|
||||
description=note,
|
||||
user=self.request.user,
|
||||
institution=self.request.user.institution,
|
||||
)
|
||||
messages.success(request, _("Note has been added"))
|
||||
else:
|
||||
messages.error(request, "There was an error with your submission.")
|
||||
|
||||
return redirect(request.META.get('HTTP_REFERER') )
|
||||
|
|
|
@ -5,36 +5,56 @@
|
|||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>{{ object.shortid }}
|
||||
</h3>
|
||||
<h3>{{ object.shortid }}</h3>
|
||||
</div>
|
||||
<div class="col text-end">
|
||||
{% if state_definitions %}
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-green-admin dropdown-toggle" type="button" id="addStateDropdown" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
{% trans "Action" %}
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="addStateDropdown">
|
||||
{% for state in state_definitions %}
|
||||
<li>
|
||||
<a class="dropdown-item d-flex justify-content-between align-items-center" href="#" data-bs-toggle="modal" data-bs-target="#addStateModal{{ state.id }}">
|
||||
<span class="badge bg-secondary rounded-pill-sm">{{ forloop.counter }}
|
||||
</span>
|
||||
<span>{{ state.state }}
|
||||
</span>
|
||||
<div class="btn-group" role="group" aria-label="Actions">
|
||||
|
||||
<!-- change state button -->
|
||||
{% if state_definitions %}
|
||||
<div class="dropdown ms-2">
|
||||
<a class="btn btn-green-admin dropdown-toggle" id="addStateDropdown" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
{% trans "Change state" %}
|
||||
{% if device_states %}
|
||||
({{ device_states.0.state }})
|
||||
{% endif %}
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="addStateDropdown" style="width: 100%;">
|
||||
{% for state in state_definitions %}
|
||||
<li style="width: 100%;">
|
||||
<form id="changeStateForm{{ state.id }}" method="post" action="{% url 'action:change_state' %}">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="previous_state" value="{{ device_states.0.state }}">
|
||||
<input type="hidden" name="snapshot_uuid" value="{{ object.last_uuid }}">
|
||||
<input type="hidden" name="new_state" value="{{ state.state }}">
|
||||
|
||||
<a class="dropdown-item d-flex justify-content-between align-items-center" href="#" onclick="document.getElementById('changeStateForm{{ state.id }}').submit(); return false;">
|
||||
<span>{{ state.state }}</span>
|
||||
<span class="badge bg-secondary rounded-pill-sm">{{ forloop.counter }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% else %}
|
||||
<button class="btn btn-green-admin" type="button" disabled>
|
||||
{% trans "Action" %}
|
||||
</form>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% else %}
|
||||
<button class="btn btn-green-admin" type="button" disabled>
|
||||
<i class="bi bi-plus"></i> {% trans "Change state" %}
|
||||
{% if device_states %}
|
||||
({{ device_states.0.state }})
|
||||
{% endif %}
|
||||
</button>
|
||||
{% endif %}
|
||||
<!-- Add note button -->
|
||||
<button class="btn btn-warning ms-2" type="button" data-bs-toggle="modal" data-bs-target="#addNoteModal">
|
||||
<i class="bi bi-sticky"></i> {% trans "Add a note" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<ul class="nav nav-tabs nav-tabs-bordered">
|
||||
|
@ -45,7 +65,7 @@
|
|||
<a href="#log" class="nav-link" data-bs-toggle="tab" data-bs-target="#log">{% trans 'Log' %}</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#user_properties" class="nav-link" data-bs-toggle="tab" data-bs-target="#user_properties">{% trans 'User properties' %}</a>
|
||||
<a href="#user_prope rties" class="nav-link" data-bs-toggle="tab" data-bs-target="#user_properties">{% trans 'User properties' %}</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#documents" class="nav-link" data-bs-toggle="tab" data-bs-target="#documents">{% trans 'Documents' %}</a>
|
||||
|
@ -84,75 +104,30 @@
|
|||
|
||||
{% include 'tabs/evidences.html' %}
|
||||
|
||||
|
||||
<!-- add state to device - popup modal-->
|
||||
{% if state_definitions %}
|
||||
{% for state in state_definitions %}
|
||||
<div class="modal fade" id="addStateModal{{ state.id }}" tabindex="-1" aria-labelledby="addStateModalLabel{{ state.id }}" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
|
||||
<form method="post" action="{% url 'action:new_action'%}">
|
||||
{% csrf_token %}
|
||||
<div class="modal fade" id="addNoteModal" tabindex="-1" aria-labelledby="addNoteModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="addStateModalLabel{{ state.id }}">{% trans "Summary of changes" %}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
<h5 class="modal-title" id="addNoteModalLabel">{% trans "Add a Note" %}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% trans 'Close' %}"></button>
|
||||
</div>
|
||||
<div class="modal-body m-1">
|
||||
{% if device_states and device_states.0.state == state.state %}
|
||||
<div class="alert alert-warning d-flex align-items-center">
|
||||
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
||||
<span>{% trans "The device is already in the selected state." %}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-arrow-right-circle text-danger me-2"></i>
|
||||
|
||||
<span class="text-danger fw-bold me-2">{% trans "From:" %}</span>
|
||||
<span class="text-danger fw-italic">
|
||||
{% if device_states %}
|
||||
{{device_states.0.state}}
|
||||
{% else %}
|
||||
{% trans 'None' %}
|
||||
{% endif %}
|
||||
</span>
|
||||
<div class="modal-body">
|
||||
<form method="post" action="{% url 'action:add_note' %}">
|
||||
{% csrf_token %}
|
||||
<div class="mb-3">
|
||||
<input type="hidden" name="snapshot_uuid" value="{{ object.last_uuid }}">
|
||||
<label for="noteDescription" class="form-label">{% trans "Note" %}</label>
|
||||
<textarea class="form-control" id="noteDescription" name="note" placeholder="Max 250 characters" name="note" rows="3" required></textarea>
|
||||
</div>
|
||||
<div class="d-flex align-items-center mt-2">
|
||||
<i class="bi bi-arrow-right-circle text-success me-2"></i>
|
||||
<span class="text-success fw-bold me-2">{% trans "To:" %}</span>
|
||||
<span class="text-success fw-italic">{{ state.state }}</span>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
||||
<button type="submit" class="btn btn-green-admin">{% trans "Save Note" %}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-check form-switch mt-3 d-flex justify-content-end">
|
||||
<label class="form-check-label font-monospace" for="addNoteCheckbox{{ state.id }}">
|
||||
{% trans "Add a note" %}
|
||||
</label>
|
||||
<input class="form-check-input ms-2" type="checkbox" id="addNoteCheckbox{{ state.id }}" data-bs-toggle="collapse" data-bs-target="#collapseInput{{ state.id }}" name="add_note">
|
||||
</div>
|
||||
|
||||
<div class="mb-3 mt-2 collapse" id="collapseInput{{ state.id }}">
|
||||
<textarea type="text" class="form-control" id="stateNote{{ state.id }}" name="note" rows="4" maxlength="200" placeholder="{% trans "Max 200 characters" %}"></textarea>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="state_id" value="{{ state.id }}">
|
||||
<input type="hidden" name="snapshot_uuid" value="{{ object.last_uuid }}">
|
||||
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
||||
<button type="submit" class="btn btn-primary">{% trans "Add State" %}</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -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
|
||||
from evidence.models import SystemProperty, UserProperty
|
||||
from utils.save_snapshots import move_json, save_in_disk
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue