[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 | |
---|
| 24 | role = {} |
---|
| 25 | people_name = {} # username -> full name |
---|
| 26 | people_id = {} # username -> MIT ID |
---|
| 27 | |
---|
| 28 | all_spaces = {} # Space.pk -> Space |
---|
| 29 | |
---|
| 30 | def fill_people(holder): |
---|
| 31 | if not holder.person in people_name: |
---|
| 32 | try: |
---|
| 33 | person = groups.models.AthenaMoiraAccount.objects.get(username=holder.person) |
---|
| 34 | people_name[holder.person] = person.format() |
---|
| 35 | people_id[holder.person] = person.mit_id |
---|
| 36 | except groups.models.AthenaMoiraAccount.DoesNotExist: |
---|
| 37 | people_name[holder.person] = "<%s>" % (holder.person, ) |
---|
| 38 | people_id[holder.person] = None |
---|
| 39 | |
---|
| 40 | class GroupInfo(object): |
---|
| 41 | def __init__(self, group, ): |
---|
| 42 | self.group = group |
---|
| 43 | self.offices = {} # Space.pk -> (ID -> (Set name, Set name)) |
---|
| 44 | if not role: |
---|
| 45 | role['office'] = groups.models.OfficerRole.objects.get(slug='office-access') |
---|
| 46 | |
---|
| 47 | def learn_access(self, space_pk, old, new): |
---|
| 48 | group_pk = self.group.pk |
---|
| 49 | if group_pk in old: |
---|
| 50 | old_access = old[group_pk] |
---|
| 51 | else: old_access = {} |
---|
| 52 | if group_pk in new: |
---|
| 53 | new_access = new[group_pk] |
---|
| 54 | else: new_access = {} |
---|
| 55 | assert space_pk not in self.offices |
---|
| 56 | |
---|
| 57 | # Let's fill out the self.offices set. |
---|
| 58 | self.offices[space_pk] = collections.defaultdict(lambda: (set(), set())) |
---|
| 59 | space_data = self.offices[space_pk] |
---|
| 60 | for mit_id, old_set in old_access.items(): |
---|
| 61 | space_data[mit_id][0].extend(old_set) |
---|
| 62 | for mit_id, new_set in new_access.items(): |
---|
| 63 | space_data[mit_id][1].extend(new_set_set) |
---|
| 64 | |
---|
| 65 | def add_space_signatories(self, old_time, new_time, ): |
---|
| 66 | group = self.group |
---|
| 67 | old_people = group.officers(as_of=old_time, role=role['office']) |
---|
| 68 | new_people = group.officers(as_of=new_time, role=role['office']) |
---|
| 69 | for holder in old_people: |
---|
| 70 | fill_people(holder) |
---|
| 71 | for holder in new_people: |
---|
| 72 | fill_people(holder) |
---|
| 73 | for office_id, office_data in self.offices.items(): |
---|
| 74 | for holder in old_people: |
---|
| 75 | holder_name = people_name[holder.person] |
---|
| 76 | holder_id = people_id[holder.person] |
---|
| 77 | office_data[holder_id][0].add(holder_name) |
---|
| 78 | for holder in new_people: |
---|
| 79 | holder_name = people_name[holder.person] |
---|
| 80 | holder_id = people_id[holder.person] |
---|
| 81 | office_data[holder_id][1].add(holder_name) |
---|
| 82 | |
---|
| 83 | def list_changes(self, ): |
---|
| 84 | cac_lines = [] |
---|
| 85 | group_lines = [] |
---|
| 86 | def append_change(mit_id, verb, name): |
---|
| 87 | cac_lines.append("%s:\t%s:\t%s" % (mit_id, verb, name)) |
---|
| 88 | group_lines.append("%s:\t%s" % (verb, name)) |
---|
| 89 | changes = False |
---|
| 90 | for space_pk, space_data in self.offices.items(): |
---|
| 91 | line = "Changes in %s:" % (all_spaces[space_pk].number, ) |
---|
| 92 | cac_lines.append(line) |
---|
| 93 | group_lines.append(line) |
---|
| 94 | for mit_id, (old_names, new_names) in space_data.items(): |
---|
| 95 | if mit_id is None: mit_id = "ID unknown" |
---|
| 96 | if old_names == new_names: |
---|
| 97 | pass |
---|
| 98 | else: |
---|
| 99 | changes = True |
---|
| 100 | for name in old_names: |
---|
| 101 | if name in new_names: |
---|
| 102 | append_change(mit_id, "Keep", name) |
---|
| 103 | else: |
---|
| 104 | append_change(mit_id, "Remove", name) |
---|
| 105 | for name in new_names: |
---|
| 106 | if name in old_names: |
---|
| 107 | pass |
---|
| 108 | else: |
---|
| 109 | append_change(mit_id, "Add", name) |
---|
| 110 | cac_lines.append("") |
---|
| 111 | group_lines.append("") |
---|
| 112 | |
---|
| 113 | cac_msg = "\n".join(cac_lines) |
---|
| 114 | group_msg = "\n".join(group_lines) |
---|
| 115 | return changes, cac_msg, group_msg |
---|
| 116 | |
---|
| 117 | def init_groups(the_groups, assignments): |
---|
| 118 | for assignment in assignments: |
---|
| 119 | group = assignment.group |
---|
| 120 | if group.id not in the_groups: |
---|
| 121 | the_groups[group.id] = GroupInfo(group) |
---|
| 122 | |
---|
| 123 | def space_specific_access(group_data, old_time, new_time, ): |
---|
| 124 | process_spaces = space.models.Space.objects.all() |
---|
| 125 | #process_spaces = process_spaces.filter(number="W20-467") |
---|
| 126 | for the_space in process_spaces: |
---|
| 127 | old_data = the_space.build_access(time=old_time) |
---|
| 128 | new_data = the_space.build_access(time=new_time) |
---|
| 129 | all_spaces[the_space.pk] = the_space |
---|
| 130 | init_groups(group_data, old_data[1]) |
---|
| 131 | init_groups(group_data, new_data[1]) |
---|
| 132 | for group_pk, group in group_data.items(): |
---|
| 133 | if group_pk in old_data[0] or group_pk in new_data[0]: |
---|
| 134 | group.learn_access(the_space.pk, old_data[0], new_data[0]) |
---|
| 135 | |
---|
| 136 | |
---|
| 137 | def space_access_diffs(): |
---|
| 138 | new_time = datetime.datetime.utcnow() |
---|
| 139 | old_time = new_time - datetime.timedelta(days=1) |
---|
| 140 | group_data = {} # Group.pk -> GroupInfo |
---|
| 141 | changed_groups = [] |
---|
| 142 | space_specific_access(group_data, old_time, new_time) |
---|
| 143 | for group_pk, group_info in group_data.items(): |
---|
| 144 | group_info.add_space_signatories(old_time, new_time) |
---|
| 145 | changes, cac_changes, group_changes = group_info.list_changes() |
---|
| 146 | if changes: |
---|
| 147 | changed_groups.append((group_info.group, cac_changes, group_changes)) |
---|
| 148 | |
---|
| 149 | asa_rcpts = ['asa-space@mit.edu', 'asa-db@mit.edu', ] |
---|
| 150 | util.emails.email_from_template( |
---|
| 151 | tmpl='space/cac-change-email.txt', |
---|
| 152 | context={'changed_groups': changed_groups}, |
---|
| 153 | subject="Office access updates", |
---|
| 154 | to=['caclocks@mit.edu'], |
---|
| 155 | cc=asa_rcpts, |
---|
| 156 | ).send() |
---|
| 157 | for group, cac_msg, group_msg in changed_groups: |
---|
| 158 | util.emails.email_from_template( |
---|
| 159 | tmpl='space/group-change-email.txt', |
---|
| 160 | context={ |
---|
| 161 | 'group':group, |
---|
| 162 | 'msg':group_msg, |
---|
| 163 | }, |
---|
| 164 | subject="Office access updates", |
---|
| 165 | to=[group.officer_email], |
---|
| 166 | cc=asa_rcpts, |
---|
| 167 | ).send() |
---|
| 168 | |
---|
| 169 | |
---|
| 170 | if __name__ == "__main__": |
---|
| 171 | space_access_diffs() |
---|