Projet

Général

Profil

0001-agendas-add-anonymize-delay-45288.patch

Valentin Deniaud, 13 août 2020 15:37

Télécharger (8,36 ko)

Voir les différences:

Subject: [PATCH] agendas: add anonymize delay (#45288)

 .../management/commands/anonymize_bookings.py | 41 +++++++++++++++++
 .../migrations/0056_agenda_anonymize_delay.py | 31 +++++++++++++
 chrono/agendas/models.py                      | 10 ++++-
 chrono/manager/forms.py                       |  1 +
 debian/chrono.cron.daily                      |  3 ++
 tests/test_agendas.py                         | 45 +++++++++++++++++++
 tests/test_manager.py                         |  3 ++
 7 files changed, 133 insertions(+), 1 deletion(-)
 create mode 100644 chrono/agendas/management/commands/anonymize_bookings.py
 create mode 100644 chrono/agendas/migrations/0056_agenda_anonymize_delay.py
 create mode 100644 debian/chrono.cron.daily
chrono/agendas/management/commands/anonymize_bookings.py
1
# chrono - agendas system
2
# Copyright (C) 2020  Entr'ouvert
3
#
4
# This program is free software: you can redistribute it and/or modify it
5
# under the terms of the GNU Affero General Public License as published
6
# by the Free Software Foundation, either version 3 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU Affero General Public License for more details.
13
#
14
# You should have received a copy of the GNU Affero General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

  
17
from datetime import timedelta
18

  
19
from django.core.management.base import BaseCommand
20
from django.db.models import F
21
from django.utils import timezone
22

  
23
from chrono.agendas.models import Booking
24

  
25

  
26
class Command(BaseCommand):
27
    help = 'Anonymize bookings according to agendas delays'
28

  
29
    def handle(self, **options):
30
        bookings = Booking.objects.exclude(extra_data={'anonymized': True})
31
        bookings_to_anonymize = bookings.filter(
32
            creation_datetime__lt=timezone.now() - timedelta(days=1) * F('event__agenda__anonymize_delay')
33
        )
34

  
35
        bookings_to_anonymize.update(
36
            label='',
37
            user_display_label='',
38
            user_external_id='',
39
            user_name='',
40
            extra_data={'anonymized': True},
41
        )
chrono/agendas/migrations/0056_agenda_anonymize_delay.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2020-08-13 12:21
3
from __future__ import unicode_literals
4

  
5
import django.core.validators
6
from django.db import migrations, models
7

  
8

  
9
class Migration(migrations.Migration):
10

  
11
    dependencies = [
12
        ('agendas', '0055_booking_cancel_callback_url'),
13
    ]
14

  
15
    operations = [
16
        migrations.AddField(
17
            model_name='agenda',
18
            name='anonymize_delay',
19
            field=models.PositiveIntegerField(
20
                blank=True,
21
                default=None,
22
                help_text='After this delay, user data contained in bookings will be pruned.',
23
                null=True,
24
                validators=[
25
                    django.core.validators.MinValueValidator(30),
26
                    django.core.validators.MaxValueValidator(1000),
27
                ],
28
                verbose_name='Anonymize delay (in days)',
29
            ),
30
        ),
31
    ]
chrono/agendas/models.py
31 31
from django.contrib.auth.models import Group
32 32
from django.core.exceptions import FieldDoesNotExist
33 33
from django.core.exceptions import ValidationError
34
from django.core.validators import MaxValueValidator
34
from django.core.validators import MaxValueValidator, MinValueValidator
35 35
from django.db import models, transaction
36 36
from django.db.models import Count, Q, Case, When
37 37
from django.urls import reverse
......
124 124
        blank=True,
125 125
        validators=[MaxValueValidator(10000)],
126 126
    )  # eight weeks
127
    anonymize_delay = models.PositiveIntegerField(
128
        _('Anonymize delay (in days)'),
129
        default=None,
130
        null=True,
131
        blank=True,
132
        validators=[MinValueValidator(30), MaxValueValidator(1000)],
133
        help_text=_('After this delay, user data contained in bookings will be pruned.'),
134
    )
127 135
    real_agendas = models.ManyToManyField(
128 136
        'self',
129 137
        related_name='virtual_agendas',
chrono/manager/forms.py
71 71
            'view_role',
72 72
            'minimal_booking_delay',
73 73
            'maximal_booking_delay',
74
            'anonymize_delay',
74 75
            'default_view',
75 76
        ]
76 77

  
debian/chrono.cron.daily
1
#! /bin/sh
2

  
3
/sbin/runuser -u chrono /usr/bin/chrono-manage -- tenant_command anonymize_bookings --all-tenants
tests/test_agendas.py
1008 1008

  
1009 1009
    assert VirtualMember.objects.filter(virtual_agenda=new_agenda, real_agenda=agenda1).exists()
1010 1010
    assert VirtualMember.objects.filter(virtual_agenda=new_agenda, real_agenda=agenda2).exists()
1011

  
1012

  
1013
def test_anonymize_bookings(freezer):
1014
    freezer.move_to('2020-01-01')
1015
    agenda = Agenda.objects.create(label='Agenda', kind='events')
1016
    event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10, label='Event')
1017

  
1018
    for i in range(5):
1019
        Booking.objects.create(
1020
            event=event,
1021
            extra_data={'test': True},
1022
            label='john',
1023
            user_display_label='john',
1024
            user_external_id='john',
1025
            user_name='john',
1026
            backoffice_url='https://example.org',
1027
        )
1028

  
1029
    freezer.move_to('2020-04-01')
1030
    booking = Booking.objects.create(event=event, label='hop')
1031

  
1032
    freezer.move_to('2020-04-15')  # about 100 days after first bookings
1033
    call_command('anonymize_bookings')
1034
    assert not Booking.objects.filter(extra_data={'anonymized': True}).exists()
1035

  
1036
    # now ask for anonymization
1037
    agenda.anonymize_delay = 100
1038
    agenda.save()
1039

  
1040
    call_command('anonymize_bookings')
1041
    assert (
1042
        Booking.objects.filter(
1043
            label='',
1044
            user_display_label='',
1045
            user_external_id='',
1046
            user_name='',
1047
            backoffice_url='https://example.org',
1048
            extra_data={'anonymized': True},
1049
        ).count()
1050
        == 5
1051
    )
1052

  
1053
    booking.refresh_from_db()
1054
    assert booking.label == 'hop'
1055
    assert not booking.extra_data
tests/test_manager.py
868 868
    resp = app.get('/manage/agendas/%s/edit' % agenda_events.pk)
869 869
    assert resp.form['label'].value == 'Foo bar'
870 870
    resp.form['label'] = 'Foo baz'
871
    resp.form['anonymize_delay'] = 365
871 872
    assert 'default_view' in resp.context['form'].fields
872 873
    resp = resp.form.submit()
873 874
    assert resp.location.endswith('/manage/agendas/%s/settings' % agenda_events.pk)
......
875 876
    assert 'has_resources' not in resp.context
876 877
    assert 'Foo baz' in resp.text
877 878
    assert '<h2>Settings' in resp.text
879
    agenda_events.refresh_from_db()
880
    assert agenda_events.anonymize_delay == 365
878 881

  
879 882
    resp = app.get('/manage/agendas/%s/edit' % agenda_meetings.pk)
880 883
    assert 'default_view' not in resp.context['form'].fields
881
-