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() |
---|