Compare commits

..

1 Commits

Author SHA1 Message Date
Frédéric Péters 125f1bc797 general: add journal app (#86632)
gitea/chrono/pipeline/head There was a failure building this commit Details
2024-04-23 14:52:31 +02:00
5 changed files with 223 additions and 53 deletions

View File

@ -2277,6 +2277,12 @@ class Event(WithInspectMixin, models.Model):
return self.label
return date_format(localtime(self.start_datetime), format='DATETIME_FORMAT')
def get_time_label(self):
date_str = date_format(localtime(self.start_datetime), format='SHORT_DATETIME_FORMAT')
if self.label:
return f'{self.label} ({date_str})'
return date_str
@functional.cached_property
def cancellation_status(self):
if self.cancelled:
@ -3150,7 +3156,7 @@ class Booking(models.Model):
'booking:cancel',
request=request,
agenda=self.event.agenda,
extra_data={'booking_id': self.id, 'event': str(self.event), 'event_id': self.event.id},
extra_data={'booking': self, 'event': event},
)
self.secondary_booking_set.update(cancellation_datetime=timestamp)
self.cancellation_datetime = timestamp
@ -3178,8 +3184,7 @@ class Booking(models.Model):
request=request,
agenda=self.event.agenda,
extra_data={
'event': str(self.event),
'event_id': self.event.id,
'event': self.event,
'user_name': self.user_name,
},
)
@ -3207,8 +3212,7 @@ class Booking(models.Model):
request=request,
agenda=self.event.agenda,
extra_data={
'event': str(self.event),
'event_id': self.event.id,
'event': self.event,
'user_name': self.user_name,
},
)
@ -3235,8 +3239,7 @@ class Booking(models.Model):
request=request,
agenda=self.event.agenda,
extra_data={
'event': str(self.event),
'event_id': self.event.id,
'event': self.event,
'user_name': self.user_name,
},
)

View File

@ -1337,9 +1337,8 @@ class EventsAgendaFillslot(APIView):
request=request,
agenda=event.agenda,
extra_data={
'booking_id': new_booking.id,
'event': str(event),
'event_id': event.id,
'booking': new_booking,
'event': event,
'primary_booking_id': primary_booking.id if primary_booking else None,
},
)
@ -1586,9 +1585,8 @@ class MeetingsAgendaFillslot(APIView):
request=request,
agenda=event.agenda,
extra_data={
'booking_id': booking.id,
'event': str(event),
'event_id': event.id,
'booking': booking,
'event': event,
},
)

View File

@ -19,10 +19,17 @@ from .models import AuditEntry
def audit(action, request=None, user=None, agenda=None, extra_data=None):
action_type, action_code = action.split(':', 1)
extra_data = extra_data or {}
if 'event' in extra_data:
extra_data['event_id'] = extra_data['event'].id
extra_data['event'] = extra_data['event'].get_time_label()
if 'booking' in extra_data:
extra_data['booking_id'] = extra_data['booking'].id
del extra_data['booking']
return AuditEntry.objects.create(
user=request.user if request else user,
action_type=action_type,
action_code=action_code,
agenda=agenda,
extra_data=extra_data or {},
extra_data=extra_data,
)

View File

@ -3342,7 +3342,7 @@ class EventPresenceView(EventCheckMixin, ViewableAgendaMixin, FormView):
request=request,
agenda=self.event.agenda,
extra_data={
'event_id': self.event.id,
'event': self.event,
'check_type_slug': qs_kwargs['type_slug'],
},
)
@ -3383,8 +3383,7 @@ class EventAbsenceView(EventCheckMixin, ViewableAgendaMixin, FormView):
request=request,
agenda=self.event.agenda,
extra_data={
'event': str(self.event),
'event_id': self.event.id,
'event': self.event,
'check_type_slug': qs_kwargs['type_slug'],
},
)
@ -3408,8 +3407,7 @@ class EventCheckedView(EventCheckMixin, ViewableAgendaMixin, View):
request=request,
agenda=self.agenda,
extra_data={
'event': str(self.event),
'event_id': self.event.id,
'event': self.event,
},
)
self.event.async_notify_checked()

View File

@ -3,7 +3,7 @@ import datetime
import pytest
from pyquery import PyQuery
from chrono.agendas.models import Agenda
from chrono.agendas.models import Agenda, Booking, Event
from chrono.apps.journal.models import AuditEntry
from chrono.apps.journal.utils import audit
from chrono.utils.timezone import make_aware
@ -44,6 +44,17 @@ def test_journal_browse(app, admin_user, manager_user, settings):
Agenda.objects.create(label='Baz', kind='events'),
]
event = Event.objects.create(
start_datetime=make_aware(datetime.datetime(2024, 1, 2, 3, 4)), places=20, agenda=agendas[0]
)
booking = Booking.objects.create(event=event)
event2 = Event.objects.create(
start_datetime=make_aware(datetime.datetime(2024, 1, 2, 3, 4)),
places=20,
label='foobar',
agenda=agendas[0],
)
for i in range(20):
user = admin_user if i % 3 else manager_user
agenda = agendas[i % 3]
@ -52,7 +63,7 @@ def test_journal_browse(app, admin_user, manager_user, settings):
'booking:cancel',
user=user,
agenda=agenda,
extra_data={'booking_id': 1, 'event': 'foobar', 'event_id': 1},
extra_data={'booking': booking, 'event': event},
)
entry.timestamp = make_aware(
datetime.datetime(2024, 1, 1) + datetime.timedelta(days=i, hours=i, minutes=i)
@ -60,7 +71,7 @@ def test_journal_browse(app, admin_user, manager_user, settings):
entry.save()
entry = audit(
'check:absence', user=user, agenda=agenda, extra_data={'user_name': 'User', 'event': 'foobar'}
'check:absence', user=user, agenda=agenda, extra_data={'user_name': 'User', 'event': event2}
)
entry.timestamp = make_aware(
datetime.datetime(2024, 1, 2) + datetime.timedelta(days=i, hours=i, minutes=i)
@ -71,31 +82,131 @@ def test_journal_browse(app, admin_user, manager_user, settings):
resp = app.get('/manage/journal/')
assert [[x.text for x in PyQuery(x).find('td')] for x in resp.pyquery('tbody tr')] == [
['Jan. 21, 2024, 7:19 p.m.', 'Admin', 'Bar', 'marked absence of User in foobar'],
['Jan. 20, 2024, 7:19 p.m.', 'Admin', 'Bar', 'cancellation of booking (1) in event "foobar"'],
['Jan. 20, 2024, 6:18 p.m.', 'Manager', 'Foo', 'marked absence of User in foobar'],
['Jan. 19, 2024, 6:18 p.m.', 'Manager', 'Foo', 'cancellation of booking (1) in event "foobar"'],
['Jan. 19, 2024, 5:17 p.m.', 'Admin', 'Baz', 'marked absence of User in foobar'],
['Jan. 18, 2024, 5:17 p.m.', 'Admin', 'Baz', 'cancellation of booking (1) in event "foobar"'],
['Jan. 18, 2024, 4:16 p.m.', 'Admin', 'Bar', 'marked absence of User in foobar'],
['Jan. 17, 2024, 4:16 p.m.', 'Admin', 'Bar', 'cancellation of booking (1) in event "foobar"'],
['Jan. 17, 2024, 3:15 p.m.', 'Manager', 'Foo', 'marked absence of User in foobar'],
['Jan. 16, 2024, 3:15 p.m.', 'Manager', 'Foo', 'cancellation of booking (1) in event "foobar"'],
[
'Jan. 21, 2024, 7:19 p.m.',
'Admin',
'Bar',
'marked absence of User in foobar (01/02/2024 3:04 a.m.)',
],
[
'Jan. 20, 2024, 7:19 p.m.',
'Admin',
'Bar',
'cancellation of booking (1) in event "01/02/2024 3:04 a.m."',
],
[
'Jan. 20, 2024, 6:18 p.m.',
'Manager',
'Foo',
'marked absence of User in foobar (01/02/2024 3:04 a.m.)',
],
[
'Jan. 19, 2024, 6:18 p.m.',
'Manager',
'Foo',
'cancellation of booking (1) in event "01/02/2024 3:04 a.m."',
],
[
'Jan. 19, 2024, 5:17 p.m.',
'Admin',
'Baz',
'marked absence of User in foobar (01/02/2024 3:04 a.m.)',
],
[
'Jan. 18, 2024, 5:17 p.m.',
'Admin',
'Baz',
'cancellation of booking (1) in event "01/02/2024 3:04 a.m."',
],
[
'Jan. 18, 2024, 4:16 p.m.',
'Admin',
'Bar',
'marked absence of User in foobar (01/02/2024 3:04 a.m.)',
],
[
'Jan. 17, 2024, 4:16 p.m.',
'Admin',
'Bar',
'cancellation of booking (1) in event "01/02/2024 3:04 a.m."',
],
[
'Jan. 17, 2024, 3:15 p.m.',
'Manager',
'Foo',
'marked absence of User in foobar (01/02/2024 3:04 a.m.)',
],
[
'Jan. 16, 2024, 3:15 p.m.',
'Manager',
'Foo',
'cancellation of booking (1) in event "01/02/2024 3:04 a.m."',
],
]
resp = resp.click('2') # pagination
assert [[x.text for x in PyQuery(x).find('td')] for x in resp.pyquery('tbody tr')] == [
['Jan. 16, 2024, 2:14 p.m.', 'Admin', 'Baz', 'marked absence of User in foobar'],
['Jan. 15, 2024, 2:14 p.m.', 'Admin', 'Baz', 'cancellation of booking (1) in event "foobar"'],
['Jan. 15, 2024, 1:13 p.m.', 'Admin', 'Bar', 'marked absence of User in foobar'],
['Jan. 14, 2024, 1:13 p.m.', 'Admin', 'Bar', 'cancellation of booking (1) in event "foobar"'],
['Jan. 14, 2024, 12:12 p.m.', 'Manager', 'Foo', 'marked absence of User in foobar'],
['Jan. 13, 2024, 12:12 p.m.', 'Manager', 'Foo', 'cancellation of booking (1) in event "foobar"'],
['Jan. 13, 2024, 11:11 a.m.', 'Admin', 'Baz', 'marked absence of User in foobar'],
['Jan. 12, 2024, 11:11 a.m.', 'Admin', 'Baz', 'cancellation of booking (1) in event "foobar"'],
['Jan. 12, 2024, 10:10 a.m.', 'Admin', 'Bar', 'marked absence of User in foobar'],
['Jan. 11, 2024, 10:10 a.m.', 'Admin', 'Bar', 'cancellation of booking (1) in event "foobar"'],
[
'Jan. 16, 2024, 2:14 p.m.',
'Admin',
'Baz',
'marked absence of User in foobar (01/02/2024 3:04 a.m.)',
],
[
'Jan. 15, 2024, 2:14 p.m.',
'Admin',
'Baz',
'cancellation of booking (1) in event "01/02/2024 3:04 a.m."',
],
[
'Jan. 15, 2024, 1:13 p.m.',
'Admin',
'Bar',
'marked absence of User in foobar (01/02/2024 3:04 a.m.)',
],
[
'Jan. 14, 2024, 1:13 p.m.',
'Admin',
'Bar',
'cancellation of booking (1) in event "01/02/2024 3:04 a.m."',
],
[
'Jan. 14, 2024, 12:12 p.m.',
'Manager',
'Foo',
'marked absence of User in foobar (01/02/2024 3:04 a.m.)',
],
[
'Jan. 13, 2024, 12:12 p.m.',
'Manager',
'Foo',
'cancellation of booking (1) in event "01/02/2024 3:04 a.m."',
],
[
'Jan. 13, 2024, 11:11 a.m.',
'Admin',
'Baz',
'marked absence of User in foobar (01/02/2024 3:04 a.m.)',
],
[
'Jan. 12, 2024, 11:11 a.m.',
'Admin',
'Baz',
'cancellation of booking (1) in event "01/02/2024 3:04 a.m."',
],
[
'Jan. 12, 2024, 10:10 a.m.',
'Admin',
'Bar',
'marked absence of User in foobar (01/02/2024 3:04 a.m.)',
],
[
'Jan. 11, 2024, 10:10 a.m.',
'Admin',
'Bar',
'cancellation of booking (1) in event "01/02/2024 3:04 a.m."',
],
]
# filters
@ -103,15 +214,30 @@ def test_journal_browse(app, admin_user, manager_user, settings):
resp.form['timestamp'].value = '2024-01-19'
resp = resp.form.submit()
assert [[x.text for x in PyQuery(x).find('td')] for x in resp.pyquery('tbody tr')] == [
['Jan. 19, 2024, 6:18 p.m.', 'Manager', 'Foo', 'cancellation of booking (1) in event "foobar"'],
['Jan. 19, 2024, 5:17 p.m.', 'Admin', 'Baz', 'marked absence of User in foobar'],
[
'Jan. 19, 2024, 6:18 p.m.',
'Manager',
'Foo',
'cancellation of booking (1) in event "01/02/2024 3:04 a.m."',
],
[
'Jan. 19, 2024, 5:17 p.m.',
'Admin',
'Baz',
'marked absence of User in foobar (01/02/2024 3:04 a.m.)',
],
]
assert resp.form['timestamp'].value == '2024-01-19'
resp.form['agenda'].value = agendas[0].id
resp = resp.form.submit()
assert [[x.text for x in PyQuery(x).find('td')] for x in resp.pyquery('tbody tr')] == [
['Jan. 19, 2024, 6:18 p.m.', 'Manager', 'Foo', 'cancellation of booking (1) in event "foobar"']
[
'Jan. 19, 2024, 6:18 p.m.',
'Manager',
'Foo',
'cancellation of booking (1) in event "01/02/2024 3:04 a.m."',
]
]
resp.form['agenda'].value = agendas[1].id
@ -122,13 +248,48 @@ def test_journal_browse(app, admin_user, manager_user, settings):
resp.form['action_type'].value = 'booking'
resp = resp.form.submit()
assert [[x.text for x in PyQuery(x).find('td')] for x in resp.pyquery('tbody tr')] == [
['Jan. 20, 2024, 7:19 p.m.', 'Admin', 'Bar', 'cancellation of booking (1) in event "foobar"'],
['Jan. 17, 2024, 4:16 p.m.', 'Admin', 'Bar', 'cancellation of booking (1) in event "foobar"'],
['Jan. 14, 2024, 1:13 p.m.', 'Admin', 'Bar', 'cancellation of booking (1) in event "foobar"'],
['Jan. 11, 2024, 10:10 a.m.', 'Admin', 'Bar', 'cancellation of booking (1) in event "foobar"'],
['Jan. 8, 2024, 7:07 a.m.', 'Admin', 'Bar', 'cancellation of booking (1) in event "foobar"'],
['Jan. 5, 2024, 4:04 a.m.', 'Admin', 'Bar', 'cancellation of booking (1) in event "foobar"'],
['Jan. 2, 2024, 1:01 a.m.', 'Admin', 'Bar', 'cancellation of booking (1) in event "foobar"'],
[
'Jan. 20, 2024, 7:19 p.m.',
'Admin',
'Bar',
'cancellation of booking (1) in event "01/02/2024 3:04 a.m."',
],
[
'Jan. 17, 2024, 4:16 p.m.',
'Admin',
'Bar',
'cancellation of booking (1) in event "01/02/2024 3:04 a.m."',
],
[
'Jan. 14, 2024, 1:13 p.m.',
'Admin',
'Bar',
'cancellation of booking (1) in event "01/02/2024 3:04 a.m."',
],
[
'Jan. 11, 2024, 10:10 a.m.',
'Admin',
'Bar',
'cancellation of booking (1) in event "01/02/2024 3:04 a.m."',
],
[
'Jan. 8, 2024, 7:07 a.m.',
'Admin',
'Bar',
'cancellation of booking (1) in event "01/02/2024 3:04 a.m."',
],
[
'Jan. 5, 2024, 4:04 a.m.',
'Admin',
'Bar',
'cancellation of booking (1) in event "01/02/2024 3:04 a.m."',
],
[
'Jan. 2, 2024, 1:01 a.m.',
'Admin',
'Bar',
'cancellation of booking (1) in event "01/02/2024 3:04 a.m."',
],
]
@ -139,11 +300,14 @@ def test_journal_browse_invalid_or_unknown_event(app, admin_user, settings):
AuditEntry.objects.all().delete()
agenda = Agenda.objects.create(label='Foo', kind='events')
event = Event.objects.create(
start_datetime=make_aware(datetime.datetime(2024, 1, 2, 3, 4)), places=20, agenda=agenda
)
entry = audit(
'booking:cancel',
user=admin_user,
agenda=agenda,
extra_data={'event': 'foobar', 'event_id': 1}, # missing booking_id
extra_data={'event': event}, # missing booking_id
)
entry.timestamp = make_aware(datetime.datetime(2024, 1, 1))
entry.save()