Skip to content

Commit

Permalink
Merge 1d00d6c into 074d9b0
Browse files Browse the repository at this point in the history
  • Loading branch information
felixrindt committed Apr 5, 2021
2 parents 074d9b0 + 1d00d6c commit 606b70f
Show file tree
Hide file tree
Showing 40 changed files with 1,879 additions and 94 deletions.
2 changes: 1 addition & 1 deletion ephios/core/consequences.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def execute(cls, consequence):

@classmethod
def render(cls, consequence):
return _("{user} logs {hours:.1f} hours on {date}. Reason: {reason}").format(
return _("{user} obtains {hours:.1f} working hours for {reason} on {date}").format(
user=consequence.user.get_full_name(),
hours=consequence.data.get("hours"),
reason=consequence.data.get("reason"),
Expand Down
10 changes: 9 additions & 1 deletion ephios/core/forms/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
from ephios.core.widgets import MultiUserProfileWidget
from ephios.extra.permissions import get_groups_with_perms
from ephios.extra.widgets import ColorInput, CustomDateInput, CustomTimeInput
from ephios.modellogging.log import add_log_recorder, update_log
from ephios.modellogging.recorders import InstanceActionType, PermissionLogRecorder


class EventForm(forms.ModelForm):
Expand Down Expand Up @@ -97,7 +99,10 @@ def __init__(self, **kwargs):

def save(self, commit=True):
self.instance.type = self.eventtype
event = super().save(commit=commit)
event: Event = super().save(commit=commit)

add_log_recorder(event, PermissionLogRecorder("view_event", _("Visible for")))
add_log_recorder(event, PermissionLogRecorder("change_event", _("Responsibles")))

# delete existing permissions
# (better implement https://github.com/django-guardian/django-guardian/issues/654)
Expand Down Expand Up @@ -126,6 +131,8 @@ def save(self, commit=True):
# Assign view_event to responsible users and to non-responsible users
# that already have some sort of participation for the event
# (-> they saw and interacted with it)
# We can't just do users that aren't included by group permissions,
# as they might get removed from that group.
assign_perm(
"view_event",
UserProfile.objects.filter(
Expand All @@ -139,6 +146,7 @@ def save(self, commit=True):
event,
)

update_log(event, InstanceActionType.CHANGE)
return event


Expand Down
72 changes: 50 additions & 22 deletions ephios/core/forms/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,53 @@
from ephios.core.widgets import MultiUserProfileWidget
from ephios.extra.permissions import PermissionField, PermissionFormMixin
from ephios.extra.widgets import CustomDateInput
from ephios.modellogging.log import add_log_recorder
from ephios.modellogging.recorders import DerivedFieldsLogRecorder

MANAGEMENT_PERMISSIONS = [
"auth.add_group",
"auth.change_group",
"auth.delete_group",
"auth.view_group",
"core.add_userprofile",
"core.change_userprofile",
"core.delete_userprofile",
"core.view_userprofile",
"core.view_event",
"core.add_event",
"core.change_event",
"core.delete_event",
"core.view_eventtype",
"core.add_eventtype",
"core.change_eventtype",
"core.delete_eventtype",
"core.view_qualification",
"core.add_qualification",
"core.change_qualification",
"core.delete_qualification",
"modellogging.view_logentry",
]


def get_group_permission_log_fields(group):
# This lives here because it is closely related to the fields on GroupForm below
if not group.pk:
return {}
perms = set(group.permissions.values_list("codename", flat=True))

return {
_("Can view past events"): "view_past_event" in perms,
_("Can add events"): "add_event" in perms,
_("Can edit users"): "change_userprofile" in perms,
_("Can manage ephios"): "change_group" in perms,
# force evaluation of querysets
_("Can publish events for groups"): set(
get_objects_for_group(group, "publish_event_for_group", klass=Group)
),
_("Can decide working hours for groups"): set(
get_objects_for_group(group, "decide_workinghours_for_group", klass=Group)
),
}


class GroupForm(PermissionFormMixin, ModelForm):
Expand Down Expand Up @@ -73,28 +120,7 @@ class GroupForm(PermissionFormMixin, ModelForm):
help_text=_(
"If checked, users in this group can manage users, groups, all group memberships, eventtypes and qualifications"
),
permissions=[
"auth.add_group",
"auth.change_group",
"auth.delete_group",
"auth.view_group",
"core.add_userprofile",
"core.change_userprofile",
"core.delete_userprofile",
"core.view_userprofile",
"core.view_event",
"core.add_event",
"core.change_event",
"core.delete_event",
"core.view_eventtype",
"core.add_eventtype",
"core.change_eventtype",
"core.delete_eventtype",
"core.view_qualification",
"core.add_qualification",
"core.change_qualification",
"core.delete_qualification",
],
permissions=MANAGEMENT_PERMISSIONS,
required=False,
)

Expand Down Expand Up @@ -143,6 +169,7 @@ def __init__(self, **kwargs):
)

def save(self, commit=True):
add_log_recorder(self.instance, DerivedFieldsLogRecorder(get_group_permission_log_fields))
group = super().save(commit)

group.user_set.set(self.cleaned_data["users"])
Expand All @@ -161,6 +188,7 @@ def save(self, commit=True):
self.cleaned_data["decide_workinghours_for_group"],
)

group.save() # logging
return group


Expand Down
84 changes: 84 additions & 0 deletions ephios/core/migrations/0008_auto_20210403_2348.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Generated by Django 3.1.7 on 2021-04-03 21:48

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("core", "0007_auto_20210324_2101"),
]

operations = [
migrations.AlterModelOptions(
name="consequence",
options={"verbose_name": "Consequence"},
),
migrations.AlterModelOptions(
name="qualificationgrant",
options={"verbose_name": "Qualification grant"},
),
migrations.RemoveField(
model_name="consequence",
name="decided_by",
),
migrations.RemoveField(
model_name="consequence",
name="executed_at",
),
migrations.RemoveField(
model_name="consequence",
name="fail_reason",
),
migrations.AlterField(
model_name="abstractparticipation",
name="finished",
field=models.BooleanField(default=False, verbose_name="finished"),
),
migrations.AlterField(
model_name="consequence",
name="state",
field=models.TextField(
choices=[
("needs_confirmation", "needs confirmation"),
("executed", "executed"),
("failed", "failed"),
("denied", "denied"),
],
default="needs_confirmation",
max_length=31,
verbose_name="State",
),
),
migrations.AlterField(
model_name="localparticipation",
name="user",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
verbose_name="Participant",
),
),
migrations.AlterField(
model_name="shift",
name="event",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="shifts",
to="core.event",
verbose_name="event",
),
),
migrations.AlterField(
model_name="userprofile",
name="is_active",
field=models.BooleanField(default=True, verbose_name="Active"),
),
migrations.AlterField(
model_name="userprofile",
name="is_staff",
field=models.BooleanField(default=False, verbose_name="Staff user"),
),
]
57 changes: 52 additions & 5 deletions ephios/core/models/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
from polymorphic.models import PolymorphicModel

from ephios.extra.json import CustomJSONDecoder, CustomJSONEncoder
from ephios.modellogging.log import ModelFieldsLogConfig, register_model_for_logging
from ephios.modellogging.recorders import DerivedFieldsLogRecorder

if TYPE_CHECKING:
from ephios.core.models import UserProfile
Expand Down Expand Up @@ -59,7 +61,7 @@ class Event(Model):
description = TextField(_("description"), blank=True, null=True)
location = CharField(_("location"), max_length=254)
type = ForeignKey(EventType, on_delete=models.CASCADE, verbose_name=_("event type"))
active = BooleanField(default=False)
active = BooleanField(default=False, verbose_name=_("active"))

objects = ActiveManager()
all_objects = Manager()
Expand Down Expand Up @@ -108,6 +110,9 @@ def activate(self):
self.save()


register_model_for_logging(Event, ModelFieldsLogConfig())


class AbstractParticipation(PolymorphicModel):
class States(models.IntegerChoices):
REQUESTED = 0, _("requested")
Expand All @@ -130,7 +135,7 @@ def labels_dict(cls):
The finished flag is used to make sure the participation_finished signal is only sent out once, even
if the shift time is changed afterwards.
"""
finished = models.BooleanField(default=False)
finished = models.BooleanField(default=False, verbose_name=_("finished"))

@property
def hours_value(self):
Expand All @@ -151,9 +156,15 @@ def __str__(self):
return super().__str__()


PARTICIPATION_LOG_CONFIG = ModelFieldsLogConfig(
unlogged_fields=["id", "data", "abstractparticipation_ptr"],
attach_to_func=lambda instance: (Event, instance.shift.event_id),
)


class Shift(Model):
event = ForeignKey(
Event, on_delete=models.CASCADE, related_name="shifts", verbose_name=_("shifts")
Event, on_delete=models.CASCADE, related_name="shifts", verbose_name=_("event")
)
meeting_time = DateTimeField(_("meeting time"))
start_time = DateTimeField(_("start time"))
Expand All @@ -173,7 +184,10 @@ class Meta:
def signup_method(self):
from ephios.core.signup import signup_method_from_slug

return signup_method_from_slug(self.signup_method_slug, self)
try:
return signup_method_from_slug(self.signup_method_slug, self)
except ValueError:
return None

def get_start_end_time_display(self):
tz = pytz.timezone(settings.TIME_ZONE)
Expand All @@ -187,12 +201,42 @@ def get_participants(self, with_state_in=frozenset({AbstractParticipation.States
for participation in self.participations.filter(state__in=with_state_in):
yield participation.participant

def get_absolute_url(self):
return f"{self.event.get_absolute_url()}#shift-{self.pk}"

def __str__(self):
return f"{self.event.title} ({self.get_start_end_time_display()})"


class ShiftLogConfig(ModelFieldsLogConfig):
def __init__(self):
super().__init__(unlogged_fields=["id", "signup_method_slug", "signup_configuration"])

def object_to_attach_logentries_to(self, instance):
return Event, instance.event_id

def initial_log_recorders(self, instance):
# pylint: disable=undefined-variable
yield from super().initial_log_recorders(instance)
yield DerivedFieldsLogRecorder(
lambda shift: {
_("Signup method"): str(method.verbose_name)
if (method := shift.signup_method)
else None
}
)
yield DerivedFieldsLogRecorder(
lambda shift: method.get_signup_info() if (method := shift.signup_method) else {}
)


register_model_for_logging(Shift, ShiftLogConfig())


class LocalParticipation(AbstractParticipation):
user: "UserProfile" = ForeignKey("UserProfile", on_delete=models.CASCADE)
user: "UserProfile" = ForeignKey(
"UserProfile", on_delete=models.CASCADE, verbose_name=_("Participant")
)

def save(self, *args, **kwargs):
super().save(*args, **kwargs)
Expand All @@ -213,6 +257,9 @@ class Meta:
db_table = "localparticipation"


register_model_for_logging(LocalParticipation, PARTICIPATION_LOG_CONFIG)


class EventTypePreference(PerInstancePreferenceModel):
instance = ForeignKey(EventType, on_delete=models.CASCADE)

Expand Down

0 comments on commit 606b70f

Please sign in to comment.