|
2 | 2 | # -*- coding: utf-8 -*- |
3 | 3 | from __future__ import unicode_literals, print_function |
4 | 4 |
|
5 | | -import syslog |
6 | 5 | import datetime |
| 6 | +import sys |
| 7 | +import time |
7 | 8 |
|
8 | 9 | from django.conf import settings |
9 | | -from django.core.management.base import BaseCommand |
| 10 | +from django.core.management.base import BaseCommand, CommandError |
10 | 11 |
|
11 | 12 | import debug # pyflakes:ignore |
12 | 13 |
|
13 | | -from ietf.person.models import Person |
| 14 | +from ietf.person.models import Person, PersonEvent |
14 | 15 | from ietf.utils.mail import send_mail |
15 | | - |
16 | | -def log(message): |
17 | | - syslog.syslog(message) |
| 16 | +from ietf.utils.log import log |
18 | 17 |
|
19 | 18 | 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 | + """) |
21 | 34 |
|
22 | 35 | 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, |
24 | 37 | 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 | + |
25 | 45 |
|
26 | 46 | 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: |
29 | 56 | 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()) |
30 | 76 | if fields and person.email_set.exists(): |
31 | | - if options['dryrun']: |
| 77 | + if options['dry_run']: |
32 | 78 | print(("%-32s %-32s %-32s %-32s %s" % (person.email(), person.name_from_draft or '', person.name, person.ascii, fields)).encode('utf8')) |
33 | 79 | else: |
34 | 80 | to = [ e.address for e in person.email_set.filter(active=True) ] |
35 | 81 | if not to: |
36 | 82 | to = [ e.address for e in person.email_set.all() ] |
| 83 | + self.stdout.write("Sendimg email to %s" % to) |
37 | 84 | send_mail(None, to, None, |
38 | 85 | subject='Personal Information in the IETF Datatracker', |
39 | 86 | 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