[bec7760] | 1 | #!/usr/bin/python |
---|
| 2 | import collections |
---|
| 3 | import datetime |
---|
| 4 | import os |
---|
| 5 | import sys |
---|
| 6 | |
---|
| 7 | if __name__ == '__main__': |
---|
| 8 | cur_file = os.path.abspath(__file__) |
---|
| 9 | django_dir = os.path.abspath(os.path.join(os.path.dirname(cur_file), '..')) |
---|
| 10 | sys.path.append(django_dir) |
---|
| 11 | os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' |
---|
| 12 | |
---|
| 13 | from django.core.mail import EmailMessage |
---|
| 14 | from django.db import connection |
---|
| 15 | from django.db.models import Q |
---|
| 16 | from django.template import Context, Template |
---|
| 17 | from django.template.loader import get_template |
---|
| 18 | |
---|
| 19 | import groups.diffs |
---|
| 20 | import groups.models |
---|
| 21 | import space.models |
---|
| 22 | import util.emails |
---|
| 23 | |
---|
[57a2ad6] | 24 | role = { |
---|
| 25 | 'office': groups.models.OfficerRole.objects.get(slug='office-access') |
---|
| 26 | } |
---|
| 27 | |
---|
[bec7760] | 28 | people_name = {} # username -> full name |
---|
| 29 | people_id = {} # username -> MIT ID |
---|
| 30 | |
---|
| 31 | all_spaces = {} # Space.pk -> Space |
---|
| 32 | |
---|
[57a2ad6] | 33 | def bulk_fill_people(times): |
---|
| 34 | max_time = max(times) |
---|
| 35 | min_time = min(times) |
---|
| 36 | active_holders = groups.models.OfficeHolder.objects.filter( |
---|
| 37 | start_time__lte=max_time, |
---|
| 38 | end_time__gte=min_time, |
---|
| 39 | role__in=role.values(), |
---|
| 40 | ) |
---|
| 41 | usernames = active_holders.values_list('person', flat=True,) |
---|
| 42 | people = groups.models.AthenaMoiraAccount.objects.filter(username__in=usernames) |
---|
| 43 | for person in people: |
---|
| 44 | people_name[person.username] = person.format() |
---|
| 45 | people_id[person.username] = person.mit_id |
---|
| 46 | |
---|
[bec7760] | 47 | def fill_people(holder): |
---|
| 48 | if not holder.person in people_name: |
---|
[57a2ad6] | 49 | #print "Person %s not pre-cached" % (holder.person, ) |
---|
[bec7760] | 50 | try: |
---|
| 51 | person = groups.models.AthenaMoiraAccount.objects.get(username=holder.person) |
---|
| 52 | people_name[holder.person] = person.format() |
---|
| 53 | people_id[holder.person] = person.mit_id |
---|
| 54 | except groups.models.AthenaMoiraAccount.DoesNotExist: |
---|
| 55 | people_name[holder.person] = "<%s>" % (holder.person, ) |
---|
| 56 | people_id[holder.person] = None |
---|
| 57 | |
---|
| 58 | class GroupInfo(object): |
---|
| 59 | def __init__(self, group, ): |
---|
| 60 | self.group = group |
---|
| 61 | self.offices = {} # Space.pk -> (ID -> (Set name, Set name)) |
---|
| 62 | if not role: |
---|
| 63 | role['office'] = groups.models.OfficerRole.objects.get(slug='office-access') |
---|
| 64 | |
---|
| 65 | def learn_access(self, space_pk, old, new): |
---|
| 66 | group_pk = self.group.pk |
---|
| 67 | if group_pk in old: |
---|
| 68 | old_access = old[group_pk] |
---|
| 69 | else: old_access = {} |
---|
| 70 | if group_pk in new: |
---|
| 71 | new_access = new[group_pk] |
---|
| 72 | else: new_access = {} |
---|
| 73 | assert space_pk not in self.offices |
---|
| 74 | |
---|
| 75 | # Let's fill out the self.offices set. |
---|
| 76 | self.offices[space_pk] = collections.defaultdict(lambda: (set(), set())) |
---|
| 77 | space_data = self.offices[space_pk] |
---|
| 78 | for mit_id, old_set in old_access.items(): |
---|
[0d5dc3b] | 79 | space_data[mit_id][0].update(old_set) |
---|
[bec7760] | 80 | for mit_id, new_set in new_access.items(): |
---|
[0d5dc3b] | 81 | space_data[mit_id][1].update(new_set) |
---|
[bec7760] | 82 | |
---|
[6ae8c4a] | 83 | def add_office_signatories_per_time(self, ind, time): |
---|
[bec7760] | 84 | group = self.group |
---|
[6ae8c4a] | 85 | people = group.officers(as_of=time, role=role['office']) |
---|
| 86 | for holder in people: |
---|
[bec7760] | 87 | fill_people(holder) |
---|
| 88 | for office_id, office_data in self.offices.items(): |
---|
[6ae8c4a] | 89 | for holder in people: |
---|
[bec7760] | 90 | holder_name = people_name[holder.person] |
---|
| 91 | holder_id = people_id[holder.person] |
---|
[6ae8c4a] | 92 | office_data[holder_id][ind].add(holder_name) |
---|
| 93 | |
---|
| 94 | def add_office_signatories(self, old_time, new_time, ): |
---|
| 95 | group = self.group |
---|
| 96 | self.add_office_signatories_per_time(0, old_time) |
---|
| 97 | self.add_office_signatories_per_time(1, new_time) |
---|
[bec7760] | 98 | |
---|
| 99 | def list_changes(self, ): |
---|
| 100 | cac_lines = [] |
---|
| 101 | group_lines = [] |
---|
| 102 | def append_change(mit_id, verb, name): |
---|
| 103 | cac_lines.append("%s:\t%s:\t%s" % (mit_id, verb, name)) |
---|
| 104 | group_lines.append("%s:\t%s" % (verb, name)) |
---|
| 105 | changes = False |
---|
| 106 | for space_pk, space_data in self.offices.items(): |
---|
| 107 | line = "Changes in %s:" % (all_spaces[space_pk].number, ) |
---|
| 108 | cac_lines.append(line) |
---|
| 109 | group_lines.append(line) |
---|
| 110 | for mit_id, (old_names, new_names) in space_data.items(): |
---|
| 111 | if mit_id is None: mit_id = "ID unknown" |
---|
| 112 | if old_names == new_names: |
---|
| 113 | pass |
---|
| 114 | else: |
---|
| 115 | changes = True |
---|
| 116 | for name in old_names: |
---|
| 117 | if name in new_names: |
---|
| 118 | append_change(mit_id, "Keep", name) |
---|
| 119 | else: |
---|
| 120 | append_change(mit_id, "Remove", name) |
---|
| 121 | for name in new_names: |
---|
| 122 | if name in old_names: |
---|
| 123 | pass |
---|
| 124 | else: |
---|
| 125 | append_change(mit_id, "Add", name) |
---|
| 126 | cac_lines.append("") |
---|
| 127 | group_lines.append("") |
---|
| 128 | |
---|
| 129 | cac_msg = "\n".join(cac_lines) |
---|
| 130 | group_msg = "\n".join(group_lines) |
---|
| 131 | return changes, cac_msg, group_msg |
---|
| 132 | |
---|
| 133 | def init_groups(the_groups, assignments): |
---|
| 134 | for assignment in assignments: |
---|
| 135 | group = assignment.group |
---|
| 136 | if group.id not in the_groups: |
---|
| 137 | the_groups[group.id] = GroupInfo(group) |
---|
| 138 | |
---|
| 139 | def space_specific_access(group_data, old_time, new_time, ): |
---|
| 140 | process_spaces = space.models.Space.objects.all() |
---|
| 141 | #process_spaces = process_spaces.filter(number="W20-467") |
---|
| 142 | for the_space in process_spaces: |
---|
| 143 | old_data = the_space.build_access(time=old_time) |
---|
| 144 | new_data = the_space.build_access(time=new_time) |
---|
| 145 | all_spaces[the_space.pk] = the_space |
---|
| 146 | init_groups(group_data, old_data[1]) |
---|
| 147 | init_groups(group_data, new_data[1]) |
---|
| 148 | for group_pk, group in group_data.items(): |
---|
| 149 | if group_pk in old_data[0] or group_pk in new_data[0]: |
---|
| 150 | group.learn_access(the_space.pk, old_data[0], new_data[0]) |
---|
| 151 | |
---|
| 152 | |
---|
| 153 | def space_access_diffs(): |
---|
| 154 | new_time = datetime.datetime.utcnow() |
---|
| 155 | old_time = new_time - datetime.timedelta(days=1) |
---|
[57a2ad6] | 156 | bulk_fill_people([old_time, new_time]) |
---|
[bec7760] | 157 | group_data = {} # Group.pk -> GroupInfo |
---|
| 158 | changed_groups = [] |
---|
| 159 | space_specific_access(group_data, old_time, new_time) |
---|
| 160 | for group_pk, group_info in group_data.items(): |
---|
[6ae8c4a] | 161 | group_info.add_office_signatories(old_time, new_time) |
---|
[bec7760] | 162 | changes, cac_changes, group_changes = group_info.list_changes() |
---|
| 163 | if changes: |
---|
| 164 | changed_groups.append((group_info.group, cac_changes, group_changes)) |
---|
| 165 | |
---|
| 166 | asa_rcpts = ['asa-space@mit.edu', 'asa-db@mit.edu', ] |
---|
| 167 | util.emails.email_from_template( |
---|
| 168 | tmpl='space/cac-change-email.txt', |
---|
| 169 | context={'changed_groups': changed_groups}, |
---|
| 170 | subject="Office access updates", |
---|
| 171 | to=['caclocks@mit.edu'], |
---|
| 172 | cc=asa_rcpts, |
---|
| 173 | ).send() |
---|
| 174 | for group, cac_msg, group_msg in changed_groups: |
---|
| 175 | util.emails.email_from_template( |
---|
| 176 | tmpl='space/group-change-email.txt', |
---|
| 177 | context={ |
---|
| 178 | 'group':group, |
---|
| 179 | 'msg':group_msg, |
---|
| 180 | }, |
---|
| 181 | subject="Office access updates", |
---|
| 182 | to=[group.officer_email], |
---|
| 183 | cc=asa_rcpts, |
---|
| 184 | ).send() |
---|
| 185 | |
---|
| 186 | |
---|
| 187 | if __name__ == "__main__": |
---|
| 188 | space_access_diffs() |
---|