12 |
12 |
13 However you should really REALLY understand what it does before |
13 However you should really REALLY understand what it does before |
14 deciding to apply it for you. And then ADAPT it tou your needs. |
14 deciding to apply it for you. And then ADAPT it tou your needs. |
15 |
15 |
16 """ |
16 """ |
|
17 from __future__ import print_function |
17 |
18 |
18 import base64 |
19 import base64 |
19 from collections import defaultdict |
20 from collections import defaultdict |
20 |
21 |
21 from cubicweb.server.session import hooks_control |
22 from cubicweb.server.session import hooks_control |
26 except ValueError: |
27 except ValueError: |
27 print('you should specify the source name as script argument (i.e. after --' |
28 print('you should specify the source name as script argument (i.e. after --' |
28 ' on the command line)') |
29 ' on the command line)') |
29 sys.exit(1) |
30 sys.exit(1) |
30 except KeyError: |
31 except KeyError: |
31 print '%s is not an active source' % source_name |
32 print('%s is not an active source' % source_name) |
32 sys.exit(1) |
33 sys.exit(1) |
33 |
34 |
34 # check source is reachable before doing anything |
35 # check source is reachable before doing anything |
35 if not source.get_connection().cnx: |
36 if not source.get_connection().cnx: |
36 print '%s is not reachable. Fix this before running this script' % source_name |
37 print('%s is not reachable. Fix this before running this script' % source_name) |
37 sys.exit(1) |
38 sys.exit(1) |
38 |
39 |
39 def find_dupes(): |
40 def find_dupes(): |
40 # XXX this retrieves entities from a source name "ldap" |
41 # XXX this retrieves entities from a source name "ldap" |
41 # you will want to adjust |
42 # you will want to adjust |
50 def merge_dupes(dupes, docommit=False): |
51 def merge_dupes(dupes, docommit=False): |
51 gone_eids = [] |
52 gone_eids = [] |
52 CWUser = schema['CWUser'] |
53 CWUser = schema['CWUser'] |
53 for extid, eids in dupes.items(): |
54 for extid, eids in dupes.items(): |
54 newest = eids.pop() # we merge everything on the newest |
55 newest = eids.pop() # we merge everything on the newest |
55 print 'merging ghosts of', extid, 'into', newest |
56 print('merging ghosts of', extid, 'into', newest) |
56 # now we merge pairwise into the newest |
57 # now we merge pairwise into the newest |
57 for old in eids: |
58 for old in eids: |
58 subst = {'old': old, 'new': newest} |
59 subst = {'old': old, 'new': newest} |
59 print ' merging', old |
60 print(' merging', old) |
60 gone_eids.append(old) |
61 gone_eids.append(old) |
61 for rschema in CWUser.subject_relations(): |
62 for rschema in CWUser.subject_relations(): |
62 if rschema.final or rschema == 'identity': |
63 if rschema.final or rschema == 'identity': |
63 continue |
64 continue |
64 if CWUser.rdef(rschema, 'subject').composite == 'subject': |
65 if CWUser.rdef(rschema, 'subject').composite == 'subject': |
81 rql('DELETE X %s U WHERE U eid %%(old)s' % rschema, subst) |
82 rql('DELETE X %s U WHERE U eid %%(old)s' % rschema, subst) |
82 if not docommit: |
83 if not docommit: |
83 rollback() |
84 rollback() |
84 return |
85 return |
85 commit() # XXX flushing operations is wanted rather than really committing |
86 commit() # XXX flushing operations is wanted rather than really committing |
86 print 'clean up entities table' |
87 print('clean up entities table') |
87 sql('DELETE FROM entities WHERE eid IN (%s)' % (', '.join(str(x) for x in gone_eids))) |
88 sql('DELETE FROM entities WHERE eid IN (%s)' % (', '.join(str(x) for x in gone_eids))) |
88 commit() |
89 commit() |
89 |
90 |
90 def main(): |
91 def main(): |
91 dupes = find_dupes() |
92 dupes = find_dupes() |
92 if not dupes: |
93 if not dupes: |
93 print 'No duplicate user' |
94 print('No duplicate user') |
94 return |
95 return |
95 |
96 |
96 print 'Found %s duplicate user instances' % len(dupes) |
97 print('Found %s duplicate user instances' % len(dupes)) |
97 |
98 |
98 while True: |
99 while True: |
99 print 'Fix or dry-run? (f/d) ... or Ctrl-C to break out' |
100 print('Fix or dry-run? (f/d) ... or Ctrl-C to break out') |
100 answer = raw_input('> ') |
101 answer = raw_input('> ') |
101 if answer.lower() not in 'fd': |
102 if answer.lower() not in 'fd': |
102 continue |
103 continue |
103 print 'Please STOP THE APPLICATION INSTANCES (service or interactive), and press Return when done.' |
104 print('Please STOP THE APPLICATION INSTANCES (service or interactive), and press Return when done.') |
104 raw_input('<I swear all running instances and workers of the application are stopped>') |
105 raw_input('<I swear all running instances and workers of the application are stopped>') |
105 with hooks_control(session, session.HOOKS_DENY_ALL): |
106 with hooks_control(session, session.HOOKS_DENY_ALL): |
106 merge_dupes(dupes, docommit=answer=='f') |
107 merge_dupes(dupes, docommit=answer=='f') |
107 |
108 |
108 main() |
109 main() |