diff --git a/compensation/filters.py b/compensation/filters.py index 75d6085..9d0f3b3 100644 --- a/compensation/filters.py +++ b/compensation/filters.py @@ -31,7 +31,7 @@ class CompensationTableFilter(InterventionTableFilter): """ if not value: return queryset.filter( - intervention__recorded_on=None, + intervention__recorded=None, ) else: return queryset diff --git a/compensation/tables.py b/compensation/tables.py index d187338..0277b52 100644 --- a/compensation/tables.py +++ b/compensation/tables.py @@ -34,13 +34,13 @@ class CompensationTable(BaseTable): verbose_name=_("Checked"), orderable=True, empty_values=[], - accessor="intervention__checked_on", + accessor="intervention__checked", ) r = tables.Column( verbose_name=_("Recorded"), orderable=True, empty_values=[], - accessor="intervention__recorded_on", + accessor="intervention__recorded", ) e = tables.Column( verbose_name=_("Editable"), @@ -90,7 +90,7 @@ class CompensationTable(BaseTable): def render_c(self, value, record: Compensation): """ Renders the checked column for a compensation - checked_on is set by the main object Intervention + checked is set by the main object Intervention Args: value (str): The identifier value @@ -103,9 +103,10 @@ class CompensationTable(BaseTable): checked = value is not None tooltip = _("Not checked yet") if checked: + value = value.timestamp value = localtime(value) checked_on = value.strftime(DEFAULT_DATE_TIME_FORMAT) - tooltip = _("Checked on {} by {}").format(checked_on, record.intervention.checked_by) + tooltip = _("Checked on {} by {}").format(checked_on, record.intervention.checked.user) html += self.render_checked_star( tooltip=tooltip, icn_filled=checked, @@ -126,9 +127,10 @@ class CompensationTable(BaseTable): checked = value is not None tooltip = _("Not registered yet") if checked: + value = value.timestamp value = localtime(value) on = value.strftime(DEFAULT_DATE_TIME_FORMAT) - tooltip = _("Registered on {} by {}").format(on, record.intervention.recorded_by) + tooltip = _("Registered on {} by {}").format(on, record.intervention.recorded.user) html += self.render_bookmark( tooltip=tooltip, icn_filled=checked, diff --git a/intervention/filters.py b/intervention/filters.py index 7eb9553..319a099 100644 --- a/intervention/filters.py +++ b/intervention/filters.py @@ -117,7 +117,7 @@ class InterventionTableFilter(django_filters.FilterSet): """ if not value: return queryset.filter( - recorded_on=None, + recorded=None, ) else: return queryset diff --git a/intervention/models.py b/intervention/models.py index 6d72078..5280c84 100644 --- a/intervention/models.py +++ b/intervention/models.py @@ -15,6 +15,7 @@ from intervention.settings import INTERVENTION_IDENTIFIER_LENGTH, INTERVENTION_I from konova.models import BaseObject, Geometry from konova.utils.generators import generate_random_string from organisation.models import Organisation +from user.models import UserActionLogEntry class Intervention(BaseObject): @@ -32,27 +33,35 @@ class Intervention(BaseObject): geometry = models.ForeignKey(Geometry, null=True, blank=True, on_delete=models.SET_NULL) documents = models.ManyToManyField("konova.Document", blank=True) - # Checks - checked_on = models.DateTimeField(default=None, null=True, blank=True) - checked_by = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, related_name='+') - # Refers to "zugelassen am" registration_date = models.DateField(null=True, blank=True) # Refers to "Bestandskraft am" binding_on = models.DateField(null=True, blank=True) + # Checks - Refers to "Genehmigen" but optional + checked = models.OneToOneField( + UserActionLogEntry, + on_delete=models.SET_NULL, + null=True, + blank=True, + help_text="Holds data on user and timestamp of this action", + related_name="+" + ) + # Refers to "verzeichnen" - recorded_on = models.DateTimeField(default=None, null=True, blank=True) - recorded_by = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, related_name='+') + recorded = models.OneToOneField( + UserActionLogEntry, + on_delete=models.SET_NULL, + null=True, + blank=True, + help_text="Holds data on user and timestamp of this action", + related_name="+" + ) # Holds which intervention is simply a newer version of this dataset next_version = models.ForeignKey("Intervention", null=True, blank=True, on_delete=models.DO_NOTHING) - # Compensation or payments, one-directional - #payments = models.ManyToManyField(Payment, related_name="+", blank=True) - #compensations = models.ManyToManyField(Compensation, related_name="+", blank=True) - # Users having access on this object users = models.ManyToManyField(User) diff --git a/intervention/tables.py b/intervention/tables.py index 69d93b8..570eed4 100644 --- a/intervention/tables.py +++ b/intervention/tables.py @@ -33,13 +33,13 @@ class InterventionTable(BaseTable): verbose_name=_("Checked"), orderable=True, empty_values=[], - accessor="checked_on", + accessor="checked", ) r = tables.Column( verbose_name=_("Recorded"), orderable=True, empty_values=[], - accessor="recorded_on", + accessor="recorded", ) e = tables.Column( verbose_name=_("Editable"), @@ -110,9 +110,10 @@ class InterventionTable(BaseTable): checked = value is not None tooltip = _("Not checked yet") if checked: + value = value.timestamp value = localtime(value) checked_on = value.strftime(DEFAULT_DATE_TIME_FORMAT) - tooltip = _("Checked on {} by {}").format(checked_on, record.checked_by) + tooltip = _("Checked on {} by {}").format(checked_on, record.checked.user) html += self.render_checked_star( tooltip=tooltip, icn_filled=checked, @@ -133,9 +134,10 @@ class InterventionTable(BaseTable): checked = value is not None tooltip = _("Not registered yet") if checked: + value = value.timestamp value = localtime(value) on = value.strftime(DEFAULT_DATE_TIME_FORMAT) - tooltip = _("Registered on {} by {}").format(on, record.recorded_by) + tooltip = _("Registered on {} by {}").format(on, record.recorded.user) html += self.render_bookmark( tooltip=tooltip, icn_filled=checked, diff --git a/intervention/templates/intervention/detail/view.html b/intervention/templates/intervention/detail/view.html index 9cddd4a..e19d3c1 100644 --- a/intervention/templates/intervention/detail/view.html +++ b/intervention/templates/intervention/detail/view.html @@ -93,7 +93,7 @@ {% trans 'Checked' %} - {% if intervention.checked_on is None %} + {% if intervention.checked is None %} {% fa5_icon 'star' 'far' %} @@ -107,7 +107,7 @@ {% trans 'Recorded' %} - {% if intervention.recorded_on is None %} + {% if intervention.recorded is None %} {% fa5_icon 'bookmark' 'far' %} diff --git a/konova/enums.py b/konova/enums.py index cabb978..1f54cf9 100644 --- a/konova/enums.py +++ b/konova/enums.py @@ -47,3 +47,11 @@ class ServerMessageImportance(BaseEnum): DEFAULT = "DEFAULT" INFO = "INFO" WARNING = "WARNING" + + +class UserActionLogEntryEnum(BaseEnum): + """ + Defines different possible user actions for UserActionLogEntry + """ + CHECKED = "Checked" + RECORDED = "Recorded" diff --git a/user/admin.py b/user/admin.py index fb8a5d6..9a633e7 100644 --- a/user/admin.py +++ b/user/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from user.models import UserNotification, KonovaUserExtension +from user.models import UserNotification, KonovaUserExtension, UserActionLogEntry class UserNotificationAdmin(admin.ModelAdmin): @@ -17,5 +17,15 @@ class KonovaUserExtensionAdmin(admin.ModelAdmin): ] +class UserActionLogEntryAdmin(admin.ModelAdmin): + list_display = [ + "id", + "user", + "timestamp", + "action", + ] + + admin.site.register(UserNotification, UserNotificationAdmin) admin.site.register(KonovaUserExtension, KonovaUserExtensionAdmin) +admin.site.register(UserActionLogEntry, UserActionLogEntryAdmin) \ No newline at end of file diff --git a/user/models.py b/user/models.py index 428b4f5..588bf2f 100644 --- a/user/models.py +++ b/user/models.py @@ -1,6 +1,9 @@ +import uuid + from django.contrib.auth.models import User from django.db import models +from konova.enums import UserActionLogEntryEnum from user.enums import UserNotificationEnum @@ -36,3 +39,27 @@ class KonovaUserExtension(models.Model): """ user = models.OneToOneField(User, on_delete=models.CASCADE) notifications = models.ManyToManyField(UserNotification, related_name="+") + + +class UserActionLogEntry(models.Model): + """ Wraps a user action log entry + + Can be used for workflow related attributes like checking or recording. + + """ + id = models.UUIDField( + primary_key=True, + default=uuid.uuid4, + ) + user = models.ForeignKey(User, related_name='+', on_delete=models.CASCADE, help_text="Performing user") + timestamp = models.DateTimeField(auto_now_add=True, help_text="Timestamp of performed action") + action = models.CharField( + max_length=255, + null=True, + blank=True, + help_text="Short name for performed action - optional", + choices=UserActionLogEntryEnum.as_choices(drop_empty_choice=True), + ) + + def __str__(self): + return "{} | {} | {}".format(self.user.username, self.timestamp, self.action) \ No newline at end of file