Skip to content
Snippets Groups Projects
Verified Commit cce757a2 authored by Tom Teichler's avatar Tom Teichler :beers:
Browse files

Merge branch 'master' into renovate/django-polymorphic-3.x

parents 8b370f90 060e8cb7
No related branches found
No related tags found
1 merge request!355Update dependency django-polymorphic to v3
Pipeline #3681 passed
......@@ -14,7 +14,7 @@ from .registries import (
site_preferences_registry,
)
from .util.apps import AppConfig
from .util.core_helpers import get_site_preferences, has_person, lazy_preference
from .util.core_helpers import get_site_preferences, has_person
from .util.sass_helpers import clean_scss
......
......@@ -79,3 +79,15 @@ class SchoolTermRelatedQuerySet(QuerySet):
return self.for_school_term(current_school_term)
else:
return None
class GroupManager(CurrentSiteManagerWithoutMigrations):
"""Manager adding specific methods to groups."""
def get_queryset(self):
"""Ensure all related data is loaded as well."""
return super().get_queryset().select_related("school_term")
class GroupQuerySet(SchoolTermRelatedQuerySet):
pass
......@@ -115,7 +115,7 @@ class ExtensibleModel(models.Model, metaclass=_ExtensibleModelBase):
return CRUDEvent.objects.filter(
object_id=self.pk, content_type=content_type
).select_related("user")
).select_related("user", "user__person")
@property
def crud_event_create(self) -> Optional[CRUDEvent]:
......@@ -384,6 +384,7 @@ class AdvancedDeleteView(DeleteView):
We recommend to include the mixin :class:`reversion.views.RevisionMixin`
from `django-reversion` to enable soft-delete.
"""
success_message: Optional[str] = None
def delete(self, request, *args, **kwargs):
......
......@@ -19,11 +19,17 @@ from django.utils.text import slugify
from django.utils.translation import gettext_lazy as _
import jsonstore
from cache_memoize import cache_memoize
from dynamic_preferences.models import PerInstancePreferenceModel
from phonenumber_field.modelfields import PhoneNumberField
from polymorphic.models import PolymorphicModel
from .managers import CurrentSiteManagerWithoutMigrations, SchoolTermQuerySet
from .managers import (
CurrentSiteManagerWithoutMigrations,
GroupManager,
GroupQuerySet,
SchoolTermQuerySet,
)
from .mixins import ExtensibleModel, PureDjangoModel, SchoolTermRelatedExtensibleModel
from .tasks import send_notification
from .util.core_helpers import get_site_preferences, now_tomorrow
......@@ -59,6 +65,7 @@ class SchoolTerm(ExtensibleModel):
date_end = models.DateField(verbose_name=_("End date"))
@classmethod
@cache_memoize(3600)
def get_current(cls, day: Optional[date] = None):
if not day:
day = timezone.now().date()
......@@ -313,6 +320,8 @@ class Group(SchoolTermRelatedExtensibleModel):
classes, clubs, and the like.
"""
objects = GroupManager.from_queryset(GroupQuerySet)()
class Meta:
ordering = ["short_name", "name"]
verbose_name = _("Group")
......@@ -681,9 +690,10 @@ class CustomMenu(ExtensibleModel):
return self.name if self.name != "" else self.id
@classmethod
@cache_memoize(3600)
def get_default(cls, name):
"""Get a menu by name or create if it does not exist."""
menu, _ = cls.objects.get_or_create(name=name)
menu, _ = cls.objects.prefetch_related("items").get_or_create(name=name)
return menu
class Meta:
......
......@@ -208,7 +208,7 @@ if _settings.get("ldap.uri", None):
NestedGroupOfNamesType,
NestedGroupOfUniqueNamesType,
PosixGroupType,
) # noqa
)
# Enable Django's integration to LDAP
AUTHENTICATION_BACKENDS.append("django_auth_ldap.backend.LDAPBackend")
......@@ -413,6 +413,8 @@ DBBACKUP_COMPRESS_DB = _settings.get("backup.database.compress", True)
DBBACKUP_ENCRYPT_DB = _settings.get("backup.database.encrypt", DBBACKUP_GPG_RECIPIENT is not None)
DBBACKUP_COMPRESS_MEDIA = _settings.get("backup.media.compress", True)
DBBACKUP_ENCRYPT_MEDIA = _settings.get("backup.media.encrypt", DBBACKUP_GPG_RECIPIENT is not None)
DBBACKUP_CLEANUP_DB = _settings.get("backup.database.clean", True)
DBBACKUP_CLEANUP_MEDIA = _settings.get("backup.media.clean", True)
IMPERSONATE = {"USE_HTTP_REFERER": True, "REQUIRE_SUPERUSER": True, "ALLOW_SUPERUSER": True}
......
......@@ -19,12 +19,21 @@ def send_notification(notification: int, resend: bool = False) -> None:
def backup_data() -> None:
"""Backup database and media using django-dbbackup."""
# Assemble command-line options for dbbackup management command
db_options = (["-z"] if settings.DBBACKUP_COMPRESS_DB else []) + (
["-e"] if settings.DBBACKUP_ENCRYPT_DB else []
)
media_options = (["-z"] if settings.DBBACKUP_COMPRESS_MEDIA else []) + (
["-e"] if settings.DBBACKUP_ENCRYPT_MEDIA else []
)
db_options = []
if settings.DBBACKUP_COMPRESS_DB:
db_options.append("-z")
if settings.DBBACKUP_ENCRYPT_DB:
db_options.append("-e")
if settings.DBBACKUP_CLEANUP_DB:
db_options.append("-c")
media_options = []
if settings.DBBACKUP_COMPRESS_MEDIA:
media_options.append("-z")
if settings.DBBACKUP_ENCRYPT_MEDIA:
media_options.append("-e")
if settings.DBBACKUP_CLEANUP_MEDIA:
media_options.append("-c")
# Hand off to dbbackup's management commands
management.call_command("dbbackup", *db_options)
......
......@@ -13,8 +13,9 @@
{% has_perm 'core.edit_person' user person as can_change_person %}
{% has_perm 'core.change_person_preferences' user person as can_change_person_preferences %}
{% has_perm 'core.delete_person' user person as can_delete_person %}
{% has_perm "core.impersonate" user person as can_impersonate %}
{% if can_change_person or can_change_person_preferences or can_delete_person %}
{% if can_change_person or can_change_person_preferences or can_delete_person or can_impersonate %}
<p>
{% if can_change_person %}
<a href="{% url 'edit_person_by_id' person.id %}" class="btn waves-effect waves-light">
......@@ -36,6 +37,13 @@
{% trans "Change preferences" %}
</a>
{% endif %}
{% if can_impersonate and person.user %}
<a href="{% url "impersonate-start" person.user.id %}" class="btn waves-effect waves-light">
<i class="material-icons left">portrait</i>
{% trans "Impersonate" %}
</a>
{% endif %}
</p>
{% endif %}
......
......@@ -15,9 +15,8 @@ from django.shortcuts import get_object_or_404
from django.utils import timezone
from django.utils.functional import lazy
from django_global_request.middleware import get_request
from cache_memoize import cache_memoize
from django_global_request.middleware import get_request
from aleksis.core.util import messages
......@@ -135,6 +134,7 @@ def lazy_get_favicon_url(
) -> Callable[[str, str], Any]:
"""Lazily get the URL to a favicon image."""
@cache_memoize(3600)
def _get_favicon_url(size: int, rel: str) -> Any:
from favicon.models import Favicon # noqa
......@@ -366,7 +366,6 @@ def queryset_rules_filter(
obj: Union[HttpRequest, Model], queryset: QuerySet, perm: str
) -> QuerySet:
"""Filter queryset by user and permission."""
wanted_objects = set()
if isinstance(obj, HttpRequest) and hasattr(obj, "user"):
obj = obj.user
......
......@@ -9,8 +9,9 @@ from guardian.shortcuts import get_objects_for_user
from rules import predicate
from ..models import Group
from .core_helpers import get_site_preferences, queryset_rules_filter
from .core_helpers import get_site_preferences
from .core_helpers import has_person as has_person_helper
from .core_helpers import queryset_rules_filter
def permission_validator(request: HttpRequest, perm: str) -> bool:
......@@ -65,13 +66,16 @@ def has_any_object(perm: str, klass):
@predicate(name)
def fn(user: User) -> bool:
try:
ct_perm = ContentType.objects.get(app_label=perm.split('.', 1)[0], permission__codename=perm.split('.', 1)[1])
ct_perm = ContentType.objects.get(
app_label=perm.split(".", 1)[0], permission__codename=perm.split(".", 1)[1]
)
except ContentType.DoesNotExist:
ct_perm = None
if ct_perm and ct_perm.model_class() == klass:
return get_objects_for_user(user, perm, klass).exists()
else:
return queryset_rules_filter(user, klass.objects.all(), perm).exists()
return fn
......
......@@ -377,7 +377,9 @@ class SystemStatus(MainView, PermissionRequiredMixin):
if inspect().registered_tasks():
job_list = list(inspect().registered_tasks().values())[0]
for job in job_list:
task_results.append(TaskResult.objects.filter(task_name=job).order_by("date_done").last())
task_results.append(
TaskResult.objects.filter(task_name=job).order_by("date_done").last()
)
context = {"plugins": self.plugins, "status_code": status_code, "tasks": task_results}
return self.render_to_response(context, status=status_code)
......
This diff is collapsed.
......@@ -37,7 +37,7 @@ django-middleware-global-request = "^0.1.2"
django-menu-generator = "^1.0.4"
django-tables2 = "^2.1"
Pillow = "^7.0"
django-phonenumber-field = {version = ">=3.0, <4.0", extras = ["phonenumbers"]}
django-phonenumber-field = {version = "<5.1", extras = ["phonenumbers"]}
django-sass-processor = "^0.8"
libsass = "^0.20.0"
colour = "^0.1.5"
......@@ -54,7 +54,7 @@ django-hattori = "^0.2"
psycopg2 = "^2.8"
django_select2 = "^7.1"
requests = "^2.22"
django-two-factor-auth = { version = "^1.11.0", extras = [ "yubikey", "phonenumbers", "call", "sms" ] }
django-two-factor-auth = { version = "^1.12.1", extras = [ "yubikey", "phonenumbers", "call", "sms" ] }
django-yarnpkg = "^6.0"
django-material = "^1.6.0"
django-pwa = "^1.0.8"
......@@ -63,7 +63,7 @@ django_widget_tweaks = "^1.4.5"
django-filter = "^2.2.0"
django-templated-email = "^2.3.0"
html2text = "^2020.0.0"
django-ckeditor = "^5.8.0"
django-ckeditor = "^6.0.0"
django-js-reverse = "^0.9.1"
calendarweek = "^0.4.3"
Celery = {version="^4.4.0", optional=true, extras=["django", "redis"]}
......@@ -72,7 +72,6 @@ django-celery-beat = {version="^2.0.0", optional=true}
django-celery-email = {version="^3.0.0", optional=true}
django-jsonstore = "^0.4.1"
django-polymorphic = "^3.0.0"
django-otp = "1.0.0"
django-colorfield = "^0.3.0"
django-bleach = "^0.6.1"
django-guardian = "^2.2.0"
......@@ -87,7 +86,7 @@ django-reversion = "^3.0.7"
django-favicon-plus-reloaded = "^1.0.4"
django-health-check = "^3.12.1"
psutil = "^5.7.0"
celery-progress = "^0.0.10"
celery-progress = "^0.0.12"
[tool.poetry.extras]
ldap = ["django-auth-ldap"]
......
......@@ -23,7 +23,7 @@ setenv =
[testenv:lint]
commands =
- poetry run black --check --diff aleksis/
- poetry run isort -c --diff --stdout -rc aleksis/
- poetry run isort -c --diff --stdout aleksis/
poetry run flake8 {posargs} aleksis/
[testenv:security]
......@@ -40,7 +40,7 @@ commands = poetry run make -C docs/ html {posargs}
[testenv:reformat]
commands =
poetry run isort -rc aleksis/
poetry run isort aleksis/
poetry run black aleksis/
[flake8]
......@@ -52,7 +52,6 @@ ignore = BLK100,E203,E231,W503,D100,D101,D102,D103,D104,D105,D106,D107,RST215,RS
line_length = 100
multi_line_output = 3
include_trailing_comma = 1
use_parantheses = 1
default_section = THIRDPARTY
known_first_party = aleksis
known_django = django
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment