Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • hansegucker/AlekSIS-Core
  • pinguin/AlekSIS-Core
  • AlekSIS/official/AlekSIS-Core
  • sunweaver/AlekSIS-Core
  • sggua/AlekSIS-Core
  • edward/AlekSIS-Core
  • magicfelix/AlekSIS-Core
7 results
Show changes
Commits on Source (30)
# Generated by Django 3.1.3 on 2020-11-16 13:04
from django.db import migrations, models
import django.utils.timezone
import model_utils.fields
class Migration(migrations.Migration):
dependencies = [
('core', '0004_add_permissions_for_group_stats'),
]
operations = [
migrations.AddField(
model_name='activity',
name='created',
field=model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created'),
),
migrations.AddField(
model_name='activity',
name='modified',
field=model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified'),
),
migrations.AddField(
model_name='notification',
name='created',
field=model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created'),
),
migrations.AddField(
model_name='notification',
name='modified',
field=model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified'),
),
]
...@@ -19,7 +19,6 @@ from django.views.generic import CreateView, UpdateView ...@@ -19,7 +19,6 @@ from django.views.generic import CreateView, UpdateView
from django.views.generic.edit import DeleteView, ModelFormMixin from django.views.generic.edit import DeleteView, ModelFormMixin
import reversion import reversion
from easyaudit.models import CRUDEvent
from guardian.admin import GuardedModelAdmin from guardian.admin import GuardedModelAdmin
from jsonstore.fields import IntegerField, JSONFieldMixin from jsonstore.fields import IntegerField, JSONFieldMixin
from material.base import Layout, LayoutNode from material.base import Layout, LayoutNode
...@@ -54,8 +53,7 @@ class ExtensibleModel(models.Model, metaclass=_ExtensibleModelBase): ...@@ -54,8 +53,7 @@ class ExtensibleModel(models.Model, metaclass=_ExtensibleModelBase):
This base model ensures all objects in AlekSIS apps fulfill the This base model ensures all objects in AlekSIS apps fulfill the
following properties: following properties:
* crud_events property to retrieve easyaudit's CRUD event log * `versions` property to retrieve all versions of the model from reversion
* created_at and updated_at properties based n CRUD events
* Allow injection of fields and code from AlekSIS apps to extend * Allow injection of fields and code from AlekSIS apps to extend
model functionality. model functionality.
...@@ -109,50 +107,30 @@ class ExtensibleModel(models.Model, metaclass=_ExtensibleModelBase): ...@@ -109,50 +107,30 @@ class ExtensibleModel(models.Model, metaclass=_ExtensibleModelBase):
pass pass
@property @property
def crud_events(self) -> QuerySet: def versions(self) -> List[Tuple[str, Tuple[Any, Any]]]:
"""Get all CRUD events connected to this object from easyaudit.""" """Get all versions of this object from django-reversion.
content_type = ContentType.objects.get_for_model(self)
return CRUDEvent.objects.filter( Includes diffs to previous version.
object_id=self.pk, content_type=content_type """
).select_related("user", "user__person") versions = reversion.models.Version.objects.get_for_object(self)
@property versions_with_changes = []
def crud_event_create(self) -> Optional[CRUDEvent]: for i, version in enumerate(versions):
"""Return create event of this object.""" diff = {}
return self.crud_events.filter(event_type=CRUDEvent.CREATE).latest("datetime") if i > 0:
prev_version = versions[i - 1]
@property for k, val in version.field_dict.items():
def crud_event_update(self) -> Optional[CRUDEvent]: prev_val = prev_version.field_dict.get(k, None)
"""Return last event of this object.""" if prev_val != val:
return self.crud_events.latest("datetime") diff[k] = (prev_val, val)
@property versions_with_changes.append((version, diff))
def created_at(self) -> Optional[datetime]:
"""Determine creation timestamp from CRUD log."""
if self.crud_event_create:
return self.crud_event_create.datetime
@property return versions_with_changes
def updated_at(self) -> Optional[datetime]:
"""Determine last timestamp from CRUD log."""
if self.crud_event_update:
return self.crud_event_update.datetime
extended_data = JSONField(default=dict, editable=False) extended_data = JSONField(default=dict, editable=False)
@property
def created_by(self) -> Optional[models.Model]:
"""Determine user who created this object from CRUD log."""
if self.crud_event_create:
return self.crud_event_create.user
@property
def updated_by(self) -> Optional[models.Model]:
"""Determine user who last updated this object from CRUD log."""
if self.crud_event_update:
return self.crud_event_update.user
extended_data = JSONField(default=dict, editable=False) extended_data = JSONField(default=dict, editable=False)
@classmethod @classmethod
......
...@@ -21,6 +21,7 @@ from django.utils.translation import gettext_lazy as _ ...@@ -21,6 +21,7 @@ from django.utils.translation import gettext_lazy as _
import jsonstore import jsonstore
from cache_memoize import cache_memoize from cache_memoize import cache_memoize
from dynamic_preferences.models import PerInstancePreferenceModel from dynamic_preferences.models import PerInstancePreferenceModel
from model_utils.models import TimeStampedModel
from phonenumber_field.modelfields import PhoneNumberField from phonenumber_field.modelfields import PhoneNumberField
from polymorphic.models import PolymorphicModel from polymorphic.models import PolymorphicModel
...@@ -440,7 +441,7 @@ class PersonGroupThrough(ExtensibleModel): ...@@ -440,7 +441,7 @@ class PersonGroupThrough(ExtensibleModel):
setattr(self, field_name, field_instance) setattr(self, field_name, field_instance)
class Activity(ExtensibleModel): class Activity(ExtensibleModel, TimeStampedModel):
"""Activity of a user to trace some actions done in AlekSIS in displayable form.""" """Activity of a user to trace some actions done in AlekSIS in displayable form."""
user = models.ForeignKey( user = models.ForeignKey(
...@@ -460,7 +461,7 @@ class Activity(ExtensibleModel): ...@@ -460,7 +461,7 @@ class Activity(ExtensibleModel):
verbose_name_plural = _("Activities") verbose_name_plural = _("Activities")
class Notification(ExtensibleModel): class Notification(ExtensibleModel, TimeStampedModel):
"""Notification to submit to a user.""" """Notification to submit to a user."""
sender = models.CharField(max_length=100, verbose_name=_("Sender")) sender = models.CharField(max_length=100, verbose_name=_("Sender"))
......
...@@ -64,7 +64,6 @@ INSTALLED_APPS = [ ...@@ -64,7 +64,6 @@ INSTALLED_APPS = [
"dbbackup", "dbbackup",
"settings_context_processor", "settings_context_processor",
"sass_processor", "sass_processor",
"easyaudit",
"django_any_js", "django_any_js",
"django_yarnpkg", "django_yarnpkg",
"django_tables2", "django_tables2",
...@@ -129,7 +128,6 @@ MIDDLEWARE = [ ...@@ -129,7 +128,6 @@ MIDDLEWARE = [
"impersonate.middleware.ImpersonateMiddleware", "impersonate.middleware.ImpersonateMiddleware",
"django.contrib.messages.middleware.MessageMiddleware", "django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware",
"easyaudit.middleware.easyaudit.EasyAuditMiddleware",
"maintenance_mode.middleware.MaintenanceModeMiddleware", "maintenance_mode.middleware.MaintenanceModeMiddleware",
"aleksis.core.util.middlewares.EnsurePersonMiddleware", "aleksis.core.util.middlewares.EnsurePersonMiddleware",
"django_prometheus.middleware.PrometheusAfterMiddleware", "django_prometheus.middleware.PrometheusAfterMiddleware",
......
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
<span class="badge new primary-color">{{ activity.app }}</span> <span class="badge new primary-color">{{ activity.app }}</span>
<span class="title">{{ activity.title }}</span> <span class="title">{{ activity.title }}</span>
<p> <p>
<i class="material-icons left">access_time</i> {{ activity.created_at }} <i class="material-icons left">access_time</i> {{ activity.created }}
</p> </p>
<p> <p>
{{ activity.description }} {{ activity.description }}
...@@ -71,7 +71,7 @@ ...@@ -71,7 +71,7 @@
<span class="badge new primary-color">{{ notification.app }}</span> <span class="badge new primary-color">{{ notification.app }}</span>
<span class="title">{{ notification.title }}</span> <span class="title">{{ notification.title }}</span>
<p> <p>
<i class="material-icons left">access_time</i> {{ notification.created_at }} <i class="material-icons left">access_time</i> {{ notification.created }}
</p> </p>
<p> <p>
{{ notification.description }} {{ notification.description }}
......
{% load i18n data_helpers %} {% load i18n data_helpers %}
<ul class="collection"> <div class="collection">
{% for event in obj.crud_events %} {% for version in obj.versions %}
{% if no_m2m and event.event_type == event.M2M_CHANGE or event.event_type == event.M2M_CHANGE_REV %} <div class="collection-item">
{% else %} <div class="left" style="margin-right: 10px;">
<li class="collection-item"> {% if forloop.first %}
<strong> <i class="material-icons">add_circle</i>
{% if event.event_type == event.CREATE %} {% else %}
{% blocktrans with person=event.user.person %} <i class="material-icons">edit</i>
Created by {{ person }}
{% endblocktrans %}
{% elif event.event_type == event.UPDATE %}
{% blocktrans with person=event.user.person %}
Updated by {{ person }}
{% endblocktrans %}
{% elif event.event_type == event.DELETE %}
{% blocktrans with person=event.user.person %}
Deleted by {{ person }}
{% endblocktrans %}
{% elif event.event_type == event.M2M_CHANGE %}
{% blocktrans with person=event.user.person %}
Updated by {{ person }}
{% endblocktrans %}
{% elif event.event_type == event.M2M_CHANGE_REV %}
{% blocktrans with person=event.user.person %}
Updated by {{ person }}
{% endblocktrans %}
{% endif %}
</strong>
<div class="left" style="margin-right: 10px;">
{% if event.event_type == event.CREATE %}
<i class="material-icons">add_circle</i>
{% elif event.event_type == event.UPDATE %}
<i class="material-icons">edit</i>
{% elif event.event_type == event.DELETE %}
<i class="material-icons">delete</i>
{% elif event.event_type == event.M2M_CHANGE %}
<i class="material-icons">edit</i>
{% elif event.event_type == event.M2M_CHANGE_REV %}
<i class="material-icons">edit</i>
{% endif %}
</div>
<div class="right">
{{ event.datetime }}
</div>
{% parse_json event.changed_fields as changed_fields %}
{% if changed_fields %}
<ul>
{% for field, change in changed_fields.items %}
{% verbose_name event.content_type.app_label event.content_type.model field as verbose_name %}
<li>
{{ verbose_name }}: <s>{{ change.0 }}</s> → {{ change.1 }}
</li>
{% endfor %}
</ul>
{% endif %} {% endif %}
</li> </div>
{% endif %} <strong>
{{ version.0.revision.get_comment }}
{% trans "Changed by" %} {% firstof version.0.revision.user.person _("Unknown") %}
</strong>
<div class="right">
{{ version.0.revision.date_created }}
</div>
{% if version.1 %}
<ul>
{% for field, change in version.1.items %}
{% verbose_name version.0.content_type.app_label version.0.content_type.model field as verbose_name %}
<li>
{{ verbose_name }}: <s>{{ change.0 }}</s> → {{ change.1 }}
</li>
{% endfor %}
</ul>
{% endif %}
</div>
{% endfor %} {% endfor %}
</ul> </div>
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
{% trans "More information" %} → {{ notification.link }} {% trans "More information" %} → {{ notification.link }}
{% endif %} {% endif %}
{% blocktrans with trans_sender=notification.sender trans_created_at=notification.created_at %} {% blocktrans with trans_sender=notification.sender trans_created_at=notification.created %}
Sent by {{ trans_sender }} at {{ trans_created_at }} Sent by {{ trans_sender }} at {{ trans_created_at }}
{% endblocktrans %} {% endblocktrans %}
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
</blockquote> </blockquote>
<p> <p>
{% blocktrans with trans_sender=notification.sender trans_created_at=notification.created_at %} {% blocktrans with trans_sender=notification.sender trans_created_at=notification.created %}
Sent by {{ trans_sender }} at {{ trans_created_at }} Sent by {{ trans_sender }} at {{ trans_created_at }}
{% endblocktrans %} {% endblocktrans %}
</p> </p>
......
import os import os
import sys
import time import time
from datetime import datetime, timedelta from datetime import datetime, timedelta
from importlib import import_module from importlib import import_module
...@@ -7,9 +8,9 @@ from operator import itemgetter ...@@ -7,9 +8,9 @@ from operator import itemgetter
from typing import Any, Callable, Optional, Sequence, Union from typing import Any, Callable, Optional, Sequence, Union
from uuid import uuid4 from uuid import uuid4
try: if sys.version_info >= (3, 9):
from importlib import metadata from importlib import metadata
except ImportError: else:
import importlib_metadata as metadata import importlib_metadata as metadata
from django.conf import settings from django.conf import settings
......
...@@ -17,6 +17,7 @@ from haystack.inputs import AutoQuery ...@@ -17,6 +17,7 @@ from haystack.inputs import AutoQuery
from haystack.query import SearchQuerySet from haystack.query import SearchQuerySet
from haystack.views import SearchView from haystack.views import SearchView
from health_check.views import MainView from health_check.views import MainView
from reversion import set_user
from rules.contrib.views import PermissionRequiredMixin, permission_required from rules.contrib.views import PermissionRequiredMixin, permission_required
from .filters import GroupFilter, PersonFilter from .filters import GroupFilter, PersonFilter
...@@ -308,6 +309,7 @@ def edit_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse ...@@ -308,6 +309,7 @@ def edit_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse
if request.method == "POST": if request.method == "POST":
if edit_person_form.is_valid(): if edit_person_form.is_valid():
with reversion.create_revision(): with reversion.create_revision():
set_user(request.user)
edit_person_form.save(commit=True) edit_person_form.save(commit=True)
messages.success(request, _("The person has been saved.")) messages.success(request, _("The person has been saved."))
...@@ -344,6 +346,7 @@ def edit_group(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse: ...@@ -344,6 +346,7 @@ def edit_group(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
if request.method == "POST": if request.method == "POST":
if edit_group_form.is_valid(): if edit_group_form.is_valid():
with reversion.create_revision(): with reversion.create_revision():
set_user(request.user)
group = edit_group_form.save(commit=True) group = edit_group_form.save(commit=True)
messages.success(request, _("The group has been saved.")) messages.success(request, _("The group has been saved."))
...@@ -543,6 +546,7 @@ def delete_person(request: HttpRequest, id_: int) -> HttpResponse: ...@@ -543,6 +546,7 @@ def delete_person(request: HttpRequest, id_: int) -> HttpResponse:
person = objectgetter_optional(Person)(request, id_) person = objectgetter_optional(Person)(request, id_)
with reversion.create_revision(): with reversion.create_revision():
set_user(request.user)
person.save() person.save()
person.delete() person.delete()
...@@ -556,6 +560,7 @@ def delete_group(request: HttpRequest, id_: int) -> HttpResponse: ...@@ -556,6 +560,7 @@ def delete_group(request: HttpRequest, id_: int) -> HttpResponse:
"""View to delete an group.""" """View to delete an group."""
group = objectgetter_optional(Group)(request, id_) group = objectgetter_optional(Group)(request, id_)
with reversion.create_revision(): with reversion.create_revision():
set_user(request.user)
group.save() group.save()
group.delete() group.delete()
......
This diff is collapsed.
...@@ -37,11 +37,10 @@ python = "^3.7" ...@@ -37,11 +37,10 @@ python = "^3.7"
Django = "^3.0" Django = "^3.0"
django-any-js = "^1.0" django-any-js = "^1.0"
django-debug-toolbar = "^2.0" django-debug-toolbar = "^2.0"
django-easy-audit = {version ="^1.2rc1", allow-prereleases = true}
django-middleware-global-request = "^0.1.2" django-middleware-global-request = "^0.1.2"
django-menu-generator = "^1.0.4" django-menu-generator = "^1.0.4"
django-tables2 = "^2.1" django-tables2 = "^2.1"
Pillow = "^7.0" Pillow = "^8.0"
django-phonenumber-field = {version = "<5.1", extras = ["phonenumbers"]} django-phonenumber-field = {version = "<5.1", extras = ["phonenumbers"]}
django-sass-processor = "^0.8" django-sass-processor = "^0.8"
libsass = "^0.20.0" libsass = "^0.20.0"
...@@ -69,8 +68,8 @@ html2text = "^2020.0.0" ...@@ -69,8 +68,8 @@ html2text = "^2020.0.0"
django-ckeditor = "^6.0.0" django-ckeditor = "^6.0.0"
django-js-reverse = "^0.9.1" django-js-reverse = "^0.9.1"
calendarweek = "^0.4.3" calendarweek = "^0.4.3"
Celery = {version="^4.4.0", optional=true, extras=["django", "redis"]} Celery = {version="^5.0.0", optional=true, extras=["django", "redis"]}
django-celery-results = {version="^1.1.2", optional=true} django-celery-results = {version="^2.0.0", optional=true}
django-celery-beat = {version="^2.0.0", optional=true} django-celery-beat = {version="^2.0.0", optional=true}
django-celery-email = {version="^3.0.0", optional=true} django-celery-email = {version="^3.0.0", optional=true}
django-jsonstore = "^0.4.1" django-jsonstore = "^0.4.1"
...@@ -91,7 +90,8 @@ django-health-check = "^3.12.1" ...@@ -91,7 +90,8 @@ django-health-check = "^3.12.1"
psutil = "^5.7.0" psutil = "^5.7.0"
celery-progress = "^0.0.14" celery-progress = "^0.0.14"
django-prometheus = "^2.1.0" django-prometheus = "^2.1.0"
importlib-metadata = {version = "^2.0.0", python = "<3.8"} importlib-metadata = {version = "^3.0.0", python = "<3.9"}
django-model-utils = "^4.0.0"
[tool.poetry.extras] [tool.poetry.extras]
ldap = ["django-auth-ldap"] ldap = ["django-auth-ldap"]
......
...@@ -49,9 +49,8 @@ exclude = migrations,tests ...@@ -49,9 +49,8 @@ exclude = migrations,tests
ignore = BLK100,E203,E231,W503,D100,D101,D102,D103,D104,D105,D106,D107,RST215,RST214,F821,F841,S106,T100,T101,DJ05 ignore = BLK100,E203,E231,W503,D100,D101,D102,D103,D104,D105,D106,D107,RST215,RST214,F821,F841,S106,T100,T101,DJ05
[isort] [isort]
profile = black
line_length = 100 line_length = 100
multi_line_output = 3
include_trailing_comma = 1
default_section = THIRDPARTY default_section = THIRDPARTY
known_first_party = aleksis known_first_party = aleksis
known_django = django known_django = django
......