source: asadb/groups/import_signatories.py

space-accessstablestage
Last change on this file was 00079cf, checked in by Alex Dehnert <adehnert@…>, 14 years ago

Stuff with group admins

  • Create a new group-admin role, which can manage a group's database entry (Trac: #78)
  • Script to import old signatories on a temporary basis, and only for groups that haven't really updated their group entry
  • Property mode set to 100755
File size: 7.2 KB
Line 
1#!/usr/bin/python
2import collections
3import csv
4import datetime
5import os
6import sys
7
8if __name__ == '__main__':
9    cur_file = os.path.abspath(__file__)
10    django_dir = os.path.abspath(os.path.join(os.path.dirname(cur_file), '..'))
11    sys.path.append(django_dir)
12    os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
13
14import groups.models
15from django.db import transaction
16
17
18def dictize_line(header, line,):
19    line_dict = {}
20    for key, elem in zip(header, line, ):
21        line_dict[key]=elem
22    return line_dict
23
24def db_parse_date(string, allow_none=False):
25    if not string:
26        return None
27    else:
28        return datetime.datetime.strptime(string, '%d-%b-%y').date()
29
30def load_django(stats, ):
31    zero_time = datetime.time()
32    office_holders = groups.models.OfficeHolder.current_holders.all()
33    dj_map = collections.defaultdict(lambda: None)
34    for office_holder in office_holders:
35        if office_holder.start_time.time() == zero_time:
36            key = (office_holder.person, office_holder.role.slug, office_holder.group.pk)
37            dj_map[key] = office_holder
38    stats['dj_total_current'] = len(office_holders)
39    stats['dj_distinct_current'] = len(office_holders)
40    return dj_map
41
42def load_warehouse(stats, ):
43    indb = sys.stdin
44    reader = csv.reader(indb)
45    header = reader.next()
46    wh_map = collections.defaultdict(set)
47    stats['wh_entries'] = 0
48    for line in reader:
49        d = dictize_line(header, line)
50        role_slug = d['ASA_OFFICER_ROLE_KEY'].lower()
51        person = d['KERBEROS_NAME']
52        group_id = int(d['ASA_STUDENT_GROUP_KEY'])
53        start = db_parse_date(d['EFFECTIVE_DATE'], True)
54        expiry = db_parse_date(d['EXPIRATION_DATE'], True)
55        key = (person, role_slug, group_id, )
56        wh_map[key].add((start, expiry, ))
57        stats['wh_entries'] += 1
58    stats['wh_size'] = len(wh_map)
59    return wh_map
60
61def load_roles():
62    all_roles = groups.models.OfficerRole.objects.all()
63    role_map = {}
64    for role in all_roles:
65        role_map[role.slug] = role
66    return role_map
67
68def load_groups():
69    all_groups = groups.models.Group.objects.all()
70    group_map = {}
71    for group in all_groups:
72        group_map[group.pk] = group
73    return group_map
74
75@transaction.commit_on_success
76def perform_sync(stats, dj_map, wh_map, roles=None, dj_groups=None, ):
77    # Statistics
78    stats['loops'] = 0
79    stats['postdate_start'] = 0
80    stats['kept'] = 0
81    stats['expired'] = 0
82    stats['missing_wh'] = 0
83    stats['added'] = 0
84    stats['missing_rg'] = 0
85    stats['missing_role'] = 0
86
87    today = datetime.date.today()
88    if roles is None:
89        roles = load_roles()
90    if dj_groups is None:
91        dj_groups = load_groups()
92    for key in set(dj_map.keys()).union(wh_map.keys()):
93        stats['loops'] += 1
94        if stats['loops'] % 1000 == 0:
95            print "Sync: at loop %d" % (stats['loops'], )
96        dj_holder = dj_map[key]
97        wh_times = wh_map[key]
98        person, role_slug, group_id = key
99        if dj_holder:
100            if len(wh_times) > 0:
101                found_current = False
102                for start, expiry in wh_times:
103                    if start > today: # people *actually* post-date effective dates?
104                        stats['postdate_start'] += 1
105                    elif expiry is None:
106                        found_current = True
107                    elif expiry >= today:
108                        found_current = True
109                    else: # already expired
110                        pass
111                if found_current:
112                    stats['kept'] += 1
113                else:
114                    # expire it
115                    dj_holder.expire()
116                    stats['expired'] += 1
117            else:
118                # Weird. This person doesn't appear in Warehouse
119                stats['missing_wh'] += 1
120        else:
121            for start, expiry in wh_times:
122                if start <= today and (expiry is None or expiry > today):
123                    if group_id in dj_groups and role_slug in roles:
124                        # New signatory
125                        role = roles[role_slug]
126                        group = dj_groups[group_id]
127                        if expiry is None: expiry = groups.models.OfficeHolder.END_NEVER
128                        dj_holder = groups.models.OfficeHolder(
129                            person=person, role=role, group=group,
130                            start_time=start, end_time=expiry
131                        )
132                        dj_holder.save()
133                        stats['added'] += 1
134                    else:
135                        if role_slug not in roles:
136                            stats['missing_role'] += 1
137                        else:
138                            print "Missing role or group: person=%s, role=%s, group=%d, start=%s, expiry=%s" % (
139                                person, role_slug, group_id, start, expiry,
140                            )
141                            stats['missing_rg'] += 1
142
143
144if __name__ == '__main__':
145    stats = {
146        'group_ign': 0,
147    }
148
149    mode = 'all'
150    roles = None # default
151    if len(sys.argv) > 1:
152        if sys.argv[1] == 'squash':
153            mode = 'squash'
154        elif sys.argv[1] == 'all':
155            pass
156        else:
157            raise NotImplementedError
158    if mode == 'squash':
159        roles = load_roles()
160        repl = roles['temp-admin']
161        for slug, role in roles.items():
162            if slug in ('president', 'treasurer', 'financial', ):
163                roles[slug] = repl
164            else:
165                del roles[slug]
166
167    print "Phase 1: %s: Loading Django officer information" % (datetime.datetime.now(), )
168    dj_map = load_django(stats)
169    print "Phase 1: %s: Complete: Loading Django officer information" % (datetime.datetime.now(), )
170
171    print "Phase 2: %s: Loading Django group information" % (datetime.datetime.now(), )
172    dj_groups = load_groups()
173    if mode == 'squash':
174        for pk, group in dj_groups.items():
175            if len(group.officers()) > 1:
176                stats['group_ign'] += 1
177                del dj_groups[pk]
178            else:
179                print "Keeping ", group
180    print "Phase 2: %s: Complete: Loading Django group information" % (datetime.datetime.now(), )
181
182    print "Phase 3: %s: Loading warehouse officer information" % (datetime.datetime.now(), )
183    wh_map = load_warehouse(stats)
184    print "Phase 3: %s: Complete: Loading warehouse officer information" % (datetime.datetime.now(), )
185
186    print "Phase 4: %s: Performing sync" % (datetime.datetime.now(), )
187    perform_sync(stats, dj_map, wh_map, roles, dj_groups, )
188    print "Phase 4: %s: Complete: Performing sync" % (datetime.datetime.now(), )
189
190    print """
191    All phases complete. Statistics:
192   
193    Django current:         %(dj_total_current)6d
194    Django distinct:        %(dj_distinct_current)6d
195    Django ignored groups:  %(group_ign)6d
196
197    Warehouse p/r/g tuples: %(wh_size)6d
198    Warehouse entries:      %(wh_entries)6d
199
200    Time around sync loop:  %(loops)6d
201    Postdated start date:   %(postdate_start)6d
202    People kept:            %(kept)6d
203    People expired:         %(expired)6d
204    People missing from WH: %(missing_wh)6d
205    People in missing group:%(missing_rg)6d
206    People for missing role:%(missing_role)6d
207    People added:           %(added)6d
208    """ % stats
Note: See TracBrowser for help on using the repository browser.