Skip to content

Commit 3f9dbea

Browse files
committed
Expanded the send_gdpr_consent_request command to add support for deletion dates, email reminder interval, email sending rate limiting, and sending to a list of users.
- Legacy-Id: 15460
1 parent 75f7035 commit 3f9dbea

1 file changed

Lines changed: 66 additions & 13 deletions

File tree

ietf/utils/management/commands/send_gdpr_consent_request.py

Lines changed: 66 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,93 @@
22
# -*- coding: utf-8 -*-
33
from __future__ import unicode_literals, print_function
44

5-
import syslog
65
import datetime
6+
import sys
7+
import time
78

89
from django.conf import settings
9-
from django.core.management.base import BaseCommand
10+
from django.core.management.base import BaseCommand, CommandError
1011

1112
import debug # pyflakes:ignore
1213

13-
from ietf.person.models import Person
14+
from ietf.person.models import Person, PersonEvent
1415
from ietf.utils.mail import send_mail
15-
16-
def log(message):
17-
syslog.syslog(message)
16+
from ietf.utils.log import log
1817

1918
class Command(BaseCommand):
20-
help = (u"Send GDPR consent requests to those that need it")
19+
help = (u"""
20+
Send GDPR consent request emails to persons who have not indicated consent
21+
to having their personal information stored. Each send is logged as a
22+
PersonEvent.
23+
24+
By default email sending happens at a rate of 1 message per second; the
25+
rate can be adjusted with the -r option. At the start of a run, an estimate
26+
is given of how many persons to send to, and how long the run will take.
27+
28+
By default, emails are not sent out if there is less than 6 days since the
29+
previous consent request email. The interval can be adjusted with the -m
30+
option. One effect of this is that it is possible to break of a run and
31+
re-start it with for instance a different rate, without having duplicate
32+
messages go out to persons that were handled in the interrupted run.
33+
""")
2134

2235
def add_arguments(self, parser):
23-
parser.add_argument('-n', '--dry-run', dest='dryrun', action='store_true', default=False,
36+
parser.add_argument('-n', '--dry-run', action='store_true', default=False,
2437
help="Don't send email, just list recipients")
38+
parser.add_argument('-d', '--date', help="Date of deletion (mentioned in message)")
39+
parser.add_argument('-m', '--minimum-interval', type=int, default=6,
40+
help="Minimum interval between re-sending email messages, default: %(default)s days")
41+
parser.add_argument('-r', '--rate', type=float, default=1.0,
42+
help='Rate of sending mail, default: %(default)s/s')
43+
parser.add_argument('user', nargs='*')
44+
2545

2646
def handle(self, *args, **options):
27-
for person in Person.objects.exclude(consent=True):
28-
fields = ', '.join(person.needs_consent())
47+
event_type = 'gdpr_notice_email'
48+
# Arguments
49+
# --date
50+
if 'date' in options and options['date'] != None:
51+
try:
52+
date = datetime.datetime.strptime(options['date'], "%Y-%m-%d").date()
53+
except ValueError as e:
54+
raise CommandError('%s' % e)
55+
else:
2956
date = datetime.date.today() + datetime.timedelta(days=30)
57+
days = (date - datetime.date.today()).days
58+
if days <= 1:
59+
raise CommandError('date must be more than 1 day in the future')
60+
# --rate
61+
delay = 1.0/options['rate']
62+
# --minimum_interval
63+
minimum_interval = options['minimum_interval']
64+
latest_previous = datetime.datetime.now() - datetime.timedelta(days=minimum_interval)
65+
# user
66+
self.stdout.write('Querying the database for matching person records ...')
67+
if 'user' in options and options['user']:
68+
persons = Person.objects.filter(user__username__in=options['user'])
69+
else:
70+
persons = Person.objects.exclude(consent=True).exclude(personevent__time__gt=latest_previous, personevent__type=event_type)
71+
# Report the size of the run
72+
runtime = persons.count() * delay
73+
self.stdout.write('Sending to %d users; estimated time a bit more than %d:%02d hours' % (persons.count(), runtime//3600, runtime%3600//60))
74+
for person in persons:
75+
fields = ', '.join(person.needs_consent())
3076
if fields and person.email_set.exists():
31-
if options['dryrun']:
77+
if options['dry_run']:
3278
print(("%-32s %-32s %-32s %-32s %s" % (person.email(), person.name_from_draft or '', person.name, person.ascii, fields)).encode('utf8'))
3379
else:
3480
to = [ e.address for e in person.email_set.filter(active=True) ]
3581
if not to:
3682
to = [ e.address for e in person.email_set.all() ]
83+
self.stdout.write("Sendimg email to %s" % to)
3784
send_mail(None, to, None,
3885
subject='Personal Information in the IETF Datatracker',
3986
template='utils/personal_information_notice.txt',
40-
context={'fields': fields, 'person': person, 'settings': settings, 'date': date, }, )
41-
87+
context={
88+
'date': date, 'days': days, 'fields': fields,
89+
'person': person, 'settings': settings,
90+
},
91+
)
92+
e = PersonEvent.objects.create(person=person, type='gdpr_notice_email',
93+
desc="Sent GDPR notice email to %s with confirmation deadline %s" % (to, date))
94+
time.sleep(delay)

0 commit comments

Comments
 (0)