From f113bad7333a5c56a84bfad1069b8452868f9228 Mon Sep 17 00:00:00 2001 From: mipel Date: Mon, 2 Aug 2021 11:52:20 +0200 Subject: [PATCH] Created|Deleted refactoring * refactors base attributes created and deleted into UserActionLogEntry foreign keys * refactors all related queries and process logic * fixes binding_on into binding_date in intervention/detail/view.html * adds basic __str__ for some models * --- compensation/admin.py | 9 +--- compensation/forms.py | 8 +++- compensation/models.py | 42 ++++++++++++++---- compensation/tables.py | 4 +- compensation/views.py | 4 +- intervention/admin.py | 4 +- intervention/forms.py | 8 +++- intervention/models.py | 30 +++++++++++-- intervention/tables.py | 2 +- .../templates/intervention/detail/view.html | 6 +-- intervention/views.py | 7 ++- konova/admin.py | 6 +-- konova/enums.py | 2 + konova/forms.py | 43 +++++++++++++++---- konova/models.py | 11 +++-- konova/views.py | 9 ++-- organisation/admin.py | 3 +- 17 files changed, 138 insertions(+), 60 deletions(-) diff --git a/compensation/admin.py b/compensation/admin.py index a902e1bc..43fef018 100644 --- a/compensation/admin.py +++ b/compensation/admin.py @@ -37,8 +37,7 @@ class CompensationAdmin(admin.ModelAdmin): "id", "identifier", "title", - "created_on", - "created_by", + "created", ] @@ -47,8 +46,6 @@ class EcoAccountAdmin(admin.ModelAdmin): "id", "identifier", "title", - "created_on", - "created_by", ] @@ -57,8 +54,6 @@ class PaymentAdmin(admin.ModelAdmin): "id", "amount", "due_on", - "created_by", - "created_on", ] @@ -68,8 +63,6 @@ class EcoAccountWithdrawAdmin(admin.ModelAdmin): "account", "intervention", "amount", - "created_by", - "created_on", ] diff --git a/compensation/forms.py b/compensation/forms.py index 0741478a..05154673 100644 --- a/compensation/forms.py +++ b/compensation/forms.py @@ -10,7 +10,9 @@ from django.db import transaction from django.utils.translation import gettext_lazy as _ from compensation.models import Payment +from konova.enums import UserActionLogEntryEnum from konova.forms import BaseForm, BaseModalForm +from user.models import UserActionLogEntry class NewCompensationForm(BaseForm): @@ -56,8 +58,12 @@ class NewPaymentForm(BaseModalForm): def save(self): with transaction.atomic(): + action = UserActionLogEntry.objects.create( + user=self.user, + action=UserActionLogEntryEnum.CREATED.value, + ) pay = Payment.objects.create( - created_by=self.user, + created=action, amount=self.cleaned_data.get("amount", -1), due_on=self.cleaned_data.get("due", None), comment=self.cleaned_data.get("transfer_note", None), diff --git a/compensation/models.py b/compensation/models.py index 0221a7b6..dd5488de 100644 --- a/compensation/models.py +++ b/compensation/models.py @@ -8,14 +8,17 @@ Created on: 17.11.20 from django.contrib.auth.models import User from django.contrib.gis.db import models from django.core.validators import MinValueValidator, MaxValueValidator +from django.db import transaction from django.utils import timezone from django.utils.timezone import now from compensation.settings import COMPENSATION_IDENTIFIER_LENGTH, COMPENSATION_IDENTIFIER_TEMPLATE from intervention.models import Intervention, ResponsibilityData +from konova.enums import UserActionLogEntryEnum from konova.models import BaseObject, BaseResource, Geometry, UuidModel from konova.utils.generators import generate_random_string from organisation.models import Organisation +from user.models import UserActionLogEntry class Payment(BaseResource): @@ -68,10 +71,11 @@ class CompensationAction(BaseResource): control = models.ForeignKey(CompensationControl, on_delete=models.SET_NULL, null=True, blank=True) -class Compensation(BaseObject): +class AbstractCompensation(BaseObject): """ - The compensation holds information about which actions have to be performed until which date, who is in charge - of this, which legal authority is the point of contact, and so on. + Abstract compensation model which holds basic attributes, shared by subclasses like the regular Compensation + or EcoAccount. + """ responsible = models.OneToOneField( ResponsibilityData, @@ -93,6 +97,14 @@ class Compensation(BaseObject): # Holds which intervention is simply a newer version of this dataset next_version = models.ForeignKey("Compensation", null=True, blank=True, on_delete=models.DO_NOTHING) + class Meta: + abstract = True + + +class Compensation(AbstractCompensation): + """ + Regular compensation, linked to an intervention + """ intervention = models.ForeignKey( Intervention, on_delete=models.CASCADE, @@ -101,6 +113,9 @@ class Compensation(BaseObject): related_name='compensations' ) + def __str__(self): + return "{}".format(self.identifier) + @staticmethod def _generate_new_identifier() -> str: """ Generates a new identifier for the intervention object @@ -131,9 +146,16 @@ class Compensation(BaseObject): """ _now = timezone.now() _user = kwargs.get("user", None) - self.deleted_on = _now - self.deleted_by = _user - self.save() + with transaction.atomic(): + action = UserActionLogEntry.objects.create( + user=_user, + timestamp=_now, + action=UserActionLogEntryEnum.DELETED.value + ) + self.deleted = action + #self.deleted_on = _now + #self.deleted_by = _user + self.save() def save(self, *args, **kwargs): if self.identifier is None or len(self.identifier) == 0: @@ -145,13 +167,17 @@ class Compensation(BaseObject): super().save(*args, **kwargs) -class EcoAccount(Compensation): +class EcoAccount(AbstractCompensation): """ An eco account is a kind of 'prepaid' compensation. It can be compared to an account that already has been filled with some kind of currency. From this account one is able to 'withdraw' currency for current projects. """ # Users having access on this object - users = models.ManyToManyField(User) + # Not needed in regular Compensation since their access is defined by the linked intervention's access + users = models.ManyToManyField( + User, + help_text="Users having access" + ) def __str__(self): return "{}".format(self.identifier) diff --git a/compensation/tables.py b/compensation/tables.py index 0277b52b..5fd65b3e 100644 --- a/compensation/tables.py +++ b/compensation/tables.py @@ -51,7 +51,7 @@ class CompensationTable(BaseTable): lm = tables.Column( verbose_name=_("Last edit"), orderable=True, - accessor="created_on", + accessor="created__timestamp", ) class Meta(BaseTable.Meta): @@ -173,7 +173,7 @@ class EcoAccountTable(BaseTable): d = tables.Column( verbose_name=_("Created on"), orderable=True, - accessor="created_on", + accessor="created__timestamp", ) ac = tables.Column( verbose_name=_("Actions"), diff --git a/compensation/views.py b/compensation/views.py index c0b55a34..55e585ad 100644 --- a/compensation/views.py +++ b/compensation/views.py @@ -28,7 +28,7 @@ def index_view(request: HttpRequest): template = "generic_index.html" user = request.user compensations = Compensation.objects.filter( - deleted_on=None, + deleted=None, ) table = CompensationTable( request=request, @@ -92,7 +92,7 @@ def account_index_view(request: HttpRequest): template = "generic_index.html" user = request.user eco_accounts = EcoAccount.objects.filter( - deleted_on=None, + deleted=None, ) table = EcoAccountTable( request=request, diff --git a/intervention/admin.py b/intervention/admin.py index 4adf095e..591a9a6e 100644 --- a/intervention/admin.py +++ b/intervention/admin.py @@ -7,8 +7,8 @@ class InterventionAdmin(admin.ModelAdmin): list_display = [ "id", "title", - "created_on", - "deleted_on", + "created", + "deleted", ] diff --git a/intervention/forms.py b/intervention/forms.py index 3eb2a885..147c06be 100644 --- a/intervention/forms.py +++ b/intervention/forms.py @@ -15,10 +15,12 @@ from django.urls import reverse from django.utils.translation import gettext_lazy as _ from intervention.models import Intervention +from konova.enums import UserActionLogEntryEnum from konova.forms import BaseForm, BaseModalForm from konova.models import Document from konova.settings import DEFAULT_LAT, DEFAULT_LON, DEFAULT_ZOOM from organisation.models import Organisation +from user.models import UserActionLogEntry class NewInterventionForm(BaseForm): @@ -115,6 +117,10 @@ class NewInterventionForm(BaseForm): geometry = self.cleaned_data.get("geometry", Polygon()) documents = self.cleaned_data.get("documents", []) or [] + action = UserActionLogEntry.objects.create( + user=user, + action=UserActionLogEntryEnum.CREATED.value, + ) intervention = Intervention( identifier=identifier, title=title, @@ -124,7 +130,7 @@ class NewInterventionForm(BaseForm): data_provider=data_provider, data_provider_detail=data_provider_detail, geometry=geometry, - created_by=user, + created=action, ) intervention.save() for doc in documents: diff --git a/intervention/models.py b/intervention/models.py index 81981bba..22f68f8c 100644 --- a/intervention/models.py +++ b/intervention/models.py @@ -12,6 +12,7 @@ from django.utils import timezone from django.utils.timezone import now from intervention.settings import INTERVENTION_IDENTIFIER_LENGTH, INTERVENTION_IDENTIFIER_TEMPLATE +from konova.enums import UserActionLogEntryEnum from konova.models import BaseObject, Geometry, UuidModel from konova.utils import generators from konova.utils.generators import generate_random_string @@ -30,6 +31,13 @@ class ResponsibilityData(UuidModel): conservation_file_number = models.CharField(max_length=1000, blank=True, null=True) handler = models.CharField(max_length=500, null=True, blank=True, help_text="Refers to 'Eingriffsverursacher'") + def __str__(self): + return "ZB: {} | ETS: {} | Handler: {}".format( + self.registration_office, + self.conservation_office, + self.handler + ) + class LegalData(UuidModel): """ @@ -44,6 +52,13 @@ class LegalData(UuidModel): process_type = models.CharField(max_length=500, null=True, blank=True) law = models.CharField(max_length=500, null=True, blank=True) + def __str__(self): + return "{} | {} | {}".format( + self.process_type, + self.law, + self.id + ) + class Intervention(BaseObject): """ @@ -121,13 +136,20 @@ class Intervention(BaseObject): with transaction.atomic(): # "Delete" related compensations as well coms = self.compensations.all() + action = UserActionLogEntry.objects.create( + user=_user, + timestamp=_now, + action=UserActionLogEntryEnum.DELETED.value + ) for com in coms: - com.deleted_on = _now - com.deleted_by = _user + com.deleted = action + #com.deleted_on = _now + #com.deleted_by = _user com.save() - self.deleted_on = _now - self.deleted_by = _user + self.deleted = action + #self.deleted_on = _now + #self.deleted_by = _user self.save() @staticmethod diff --git a/intervention/tables.py b/intervention/tables.py index 570eed41..be459377 100644 --- a/intervention/tables.py +++ b/intervention/tables.py @@ -50,7 +50,7 @@ class InterventionTable(BaseTable): lm = tables.Column( verbose_name=_("Last edit"), orderable=True, - accessor="created_on", + accessor="created__timestamp", ) """ # ToDo: Decide to keep actions column or to dismiss them diff --git a/intervention/templates/intervention/detail/view.html b/intervention/templates/intervention/detail/view.html index f7540b0e..2ade6d7a 100644 --- a/intervention/templates/intervention/detail/view.html +++ b/intervention/templates/intervention/detail/view.html @@ -122,15 +122,15 @@ {% trans 'Binding on' %} - {{intervention.legal.binding_on|default_if_none:""}} + {{intervention.legal.binding_date|default_if_none:""}} {% trans 'Last modified' %} - {{intervention.created_on|default_if_none:""|naturalday}} + {{intervention.created.timestamp|default_if_none:""|naturalday}}
{% trans 'by' %} - {{intervention.created_by|default_if_none:""}} + {{intervention.created.user|default_if_none:""}} diff --git a/intervention/views.py b/intervention/views.py index e982b8be..40fbd6a2 100644 --- a/intervention/views.py +++ b/intervention/views.py @@ -28,10 +28,10 @@ def index_view(request: HttpRequest): # Filtering by user access is performed in table filter inside of InterventionTableFilter class interventions = Intervention.objects.filter( - deleted_on=None, # not deleted + deleted=None, # not deleted next_version=None, # only newest versions ).order_by( - "-created_on" + "-created__timestamp" ) table = InterventionTable( request=request, @@ -128,8 +128,7 @@ def open_view(request: HttpRequest, id: str): # Fetch data, filter out deleted related data intervention = get_object_or_404(Intervention, id=id) compensations = intervention.compensations.filter( - deleted_on=None, - deleted_by=None, + deleted=None, ) has_access = intervention.has_access(user=request.user) diff --git a/konova/admin.py b/konova/admin.py index e53a7fa3..dc2c0583 100644 --- a/konova/admin.py +++ b/konova/admin.py @@ -13,8 +13,7 @@ from konova.models import Geometry, Document, Deadline class GeometryAdmin(admin.ModelAdmin): list_display = [ "id", - "created_on", - "created_by", + "created", ] @@ -23,8 +22,7 @@ class DocumentAdmin(admin.ModelAdmin): "id", "title", "comment", - "created_on", - "created_by", + "created", ] diff --git a/konova/enums.py b/konova/enums.py index f2209350..529c42dd 100644 --- a/konova/enums.py +++ b/konova/enums.py @@ -55,6 +55,8 @@ class UserActionLogEntryEnum(BaseEnum): """ CHECKED = "Checked" RECORDED = "Recorded" + CREATED = "Created" + DELETED = "Deleted" class DeadlineTypeEnum(BaseEnum): diff --git a/konova/forms.py b/konova/forms.py index 16bc8d47..73dfd391 100644 --- a/konova/forms.py +++ b/konova/forms.py @@ -21,8 +21,10 @@ from django.utils import timezone from django.utils.translation import gettext_lazy as _ from konova.contexts import BaseContext +from konova.enums import UserActionLogEntryEnum from konova.models import Document from konova.utils.message_templates import FORM_INVALID +from user.models import UserActionLogEntry class BaseForm(forms.Form): @@ -101,11 +103,26 @@ class RemoveForm(BaseForm): return self.cleaned_data.get("check", False) def save(self, user: User): + """ Perform generic removing by running the form typical 'save()' method + + Args: + user (User): The performing user + + Returns: + + """ if self.object_to_remove is not None and self.is_checked(): - self.object_to_remove.is_active = False - self.object_to_remove.deleted_on = timezone.now() - self.object_to_remove.deleted_by = user - self.object_to_remove.save() + with transaction.atomic(): + self.object_to_remove.is_active = False + action = UserActionLogEntry.objects.create( + user=user, + timestamp=timezone.now(), + action=UserActionLogEntryEnum.DELETED.value + ) + self.object_to_remove.deleted = action + #self.object_to_remove.deleted_on = timezone.now() + #self.object_to_remove.deleted_by = user + self.object_to_remove.save() return self.object_to_remove @@ -169,9 +186,15 @@ class RemoveModalForm(BaseModalForm): self.form_caption = _("Are you sure?") def save(self): - if hasattr(self.instance, "deleted_on"): - self.instance.deleted_on = timezone.now() - self.instance.deleted_by = self.user + if hasattr(self.instance, "deleted"): + action = UserActionLogEntry.objects.create( + user=self.user, + timestamp=timezone.now(), + action=UserActionLogEntryEnum.DELETED.value, + ) + self.instance.deleted = action + #self.instance.deleted_on = timezone.now() + #self.instance.deleted_by = self.user self.instance.save() else: # If the class does not provide restorable delete functionality, we must delete the entry finally @@ -270,8 +293,12 @@ class NewDocumentForm(BaseModalForm): def save(self): with transaction.atomic(): + action = UserActionLogEntry.objects.create( + user=self.user, + action=UserActionLogEntryEnum.CREATED.value, + ) doc = Document.objects.create( - created_by=self.user, + created=action, title=self.cleaned_data["title"], comment=self.cleaned_data["comment"], document=self.cleaned_data["file"], diff --git a/konova/models.py b/konova/models.py index e47764f7..4df4a91a 100644 --- a/konova/models.py +++ b/konova/models.py @@ -14,6 +14,7 @@ from django.db import models from konova.enums import DeadlineTypeEnum from konova.settings import DEFAULT_SRID +from user.models import UserActionLogEntry class UuidModel(models.Model): @@ -33,8 +34,9 @@ class BaseResource(UuidModel): """ A basic resource model, which defines attributes for every derived model """ - created_on = models.DateTimeField(auto_now_add=True, null=True) - created_by = models.ForeignKey(User, null=True, on_delete=models.SET_NULL, related_name="+") + created = models.ForeignKey(UserActionLogEntry, on_delete=models.SET_NULL, null=True, blank=True, related_name='+') + #created_on = models.DateTimeField(auto_now_add=True, null=True) + #created_by = models.ForeignKey(User, null=True, on_delete=models.SET_NULL, related_name="+") class Meta: abstract = True @@ -48,8 +50,9 @@ class BaseObject(BaseResource): """ identifier = models.CharField(max_length=1000, null=True, blank=True) title = models.CharField(max_length=1000, null=True, blank=True) - deleted_on = models.DateTimeField(null=True, blank=True) - deleted_by = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, related_name="+") + deleted = models.ForeignKey(UserActionLogEntry, on_delete=models.SET_NULL, null=True, blank=True, related_name='+') + #deleted_on = models.DateTimeField(null=True, blank=True) + #deleted_by = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, related_name="+") comment = models.TextField(null=True, blank=True) class Meta: diff --git a/konova/views.py b/konova/views.py index 8f53aa99..9a33a17f 100644 --- a/konova/views.py +++ b/konova/views.py @@ -62,8 +62,7 @@ def home_view(request: HttpRequest): # First fetch all valid objects (undeleted, only newest versions) interventions = Intervention.objects.filter( - deleted_on=None, - deleted_by=None, + deleted=None, next_version=None, ) # Then fetch only user related ones @@ -73,16 +72,14 @@ def home_view(request: HttpRequest): # Repeat for other objects comps = Compensation.objects.filter( - deleted_on=None, - deleted_by=None, + deleted=None, next_version=None, ) user_comps = comps.filter( intervention__users__in=[user] ) eco_accs = EcoAccount.objects.filter( - deleted_on=None, - deleted_by=None, + deleted=None, next_version=None, ) user_ecco_accs = eco_accs.filter( diff --git a/organisation/admin.py b/organisation/admin.py index 8fd4a529..52d6cfe2 100644 --- a/organisation/admin.py +++ b/organisation/admin.py @@ -6,8 +6,7 @@ from organisation.models import Organisation class OrganisationAdmin(admin.ModelAdmin): list_display = [ "name", - "created_on", - "created_by", + "created", ]