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
*
This commit is contained in:
mipel 2021-08-02 11:52:20 +02:00
parent 6bc8ada286
commit 0797a6b99f
17 changed files with 138 additions and 60 deletions

View File

@ -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",
]

View File

@ -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),

View File

@ -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)

View File

@ -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"),

View File

@ -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,

View File

@ -7,8 +7,8 @@ class InterventionAdmin(admin.ModelAdmin):
list_display = [
"id",
"title",
"created_on",
"deleted_on",
"created",
"deleted",
]

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -122,15 +122,15 @@
</tr>
<tr>
<th scope="row">{% trans 'Binding on' %}</th>
<td class="align-middle">{{intervention.legal.binding_on|default_if_none:""}}</td>
<td class="align-middle">{{intervention.legal.binding_date|default_if_none:""}}</td>
</tr>
<tr>
<th scope="row">{% trans 'Last modified' %}</th>
<td class="align-middle">
{{intervention.created_on|default_if_none:""|naturalday}}
{{intervention.created.timestamp|default_if_none:""|naturalday}}
<br>
{% trans 'by' %}
{{intervention.created_by|default_if_none:""}}
{{intervention.created.user|default_if_none:""}}
</td>
</tr>
</table>

View File

@ -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)

View File

@ -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",
]

View File

@ -55,6 +55,8 @@ class UserActionLogEntryEnum(BaseEnum):
"""
CHECKED = "Checked"
RECORDED = "Recorded"
CREATED = "Created"
DELETED = "Deleted"
class DeadlineTypeEnum(BaseEnum):

View File

@ -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"],

View File

@ -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:

View File

@ -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(

View File

@ -6,8 +6,7 @@ from organisation.models import Organisation
class OrganisationAdmin(admin.ModelAdmin):
list_display = [
"name",
"created_on",
"created_by",
"created",
]