Switch to side-by-side view

--- a/scripts/update-acls.py
+++ b/scripts/update-acls.py
@@ -2,9 +2,9 @@
 from optparse import OptionParser
 from pprint import pformat
 
+import bson
 from pylons import c
 from ming.base import Object
-from ming.orm import ThreadLocalORMSession
 
 from allura import model as M
 from allura.command.show_models import dfs, build_model_inheritance_graph
@@ -15,70 +15,72 @@
 optparser = OptionParser(usage='allurapaste script <ini file> -- %prog [options] [neighborhood1...]')
 optparser.add_option('-t', '--test',  dest='test', action='store_true')
 
+main_db = M.main_doc_session.db
+c_neighborhood =  main_db.neighborhood
+c_project =  main_db.project
+c_user = main_db.user
+c_project_role = main_db.project_role
+c.project = Object(
+    database_uri=c_project.find().next()['database_uri'])
+
+project_db = M.project_doc_session.db
+c_app_config = project_db.config
+
 def main():
     global options
     options, neighborhoods = optparser.parse_args()
-    neighborhood = M.main_doc_session.db.neighborhood
-    project = M.main_doc_session.db.project
-    c.project = Object(
-        database_uri=project.find().next()['database_uri'])
-    app_config = M.project_doc_session.db.config
     if neighborhoods:
         log.info('Updating neighborhoods: %s', neighborhoods)
-        q_neighborhoods = list(neighborhood.find(dict(name={'$in': neighborhoods })))
+        q_neighborhoods = list(c_neighborhood.find(dict(name={'$in': neighborhoods })))
         neighborhood_ids=[ n['_id'] for n in q_neighborhoods ]
-        q_projects = list(project.find(dict(neighborhood_id={'$in': neighborhood_ids})))
+        q_projects = list(c_project.find(dict(neighborhood_id={'$in': neighborhood_ids})))
         project_ids = list(p['_id'] for p in q_projects)
-        q_app_config = list(app_config.find(dict(project_id={'$in': project_ids})))
+        q_app_config = list(c_app_config.find(dict(project_id={'$in': project_ids})))
         log.info('... %d neighborhoods', len(q_neighborhoods))
         log.info('... %d projects', len(q_projects))
         log.info('... %d app configs', len(q_app_config))
     else:
-        q_neighborhoods = neighborhood.find()
-        q_projects = project.find()
-        q_app_config = app_config.find()
+        q_neighborhoods = c_neighborhood.find()
+        q_projects = c_project.find()
+        q_app_config = c_app_config.find()
         log.info('Updating all neighborhoods')
     # Update project acls
     log.info('====================================')
     log.info('Update project ACLs')
     for p in q_projects:
         update_project_acl(p)
-        if not options.test: project.save(p)
+        if not options.test: c_project.save(p)
     # Update neighborhood acls
     log.info('====================================')
     log.info('Update neighborhood ACLs')
     for n in q_neighborhoods:
-        p = project.find(dict(
+        p = c_project.find(dict(
                 neighborhood_id=n['_id'], shortname='--init--')).next()
-        update_neighborhood_acl(n, p)
+        update_neighborhood_acl(n,p)
         if not options.test:
-            neighborhood.save(n)
-            project.save(p)
-            ThreadLocalORMSession.flush_all()
-            ThreadLocalORMSession.close_all()
+            c_neighborhood.save(n)
+            c_project.save(p)
     graph = build_model_inheritance_graph()
     # Update app config acls
     log.info('====================================')
     log.info('Update appconfig ACLs')
     for ac in q_app_config:
-        simple_acl_update(ac)
-        if not options.test: app_config.save(ac)
+        simple_acl_update(ac, 'app_config')
+        if not options.test: c_app_config.save(ac)
         # Update artifact acls
         log.info('====================================')
-        log.info('Update artifact ACLs')
+        log.info('Update artifact ACLs for %s', ac['_id'])
         for _, a_cls in dfs(M.Artifact, graph):
-            artifact = M.project_doc_session.db[
-                a_cls.__mongometa__.name]
-            for a in artifact.find(dict(app_config_id=ac['_id'])):
+            c_artifact = project_db[a_cls.__mongometa__.name]
+            for a in c_artifact.find(dict(app_config_id=ac['_id'])):
                 empty_acl = not a['acl']
-                simple_acl_update(a)
-                if not options.test and not empty_acl: artifact.save(a)
+                simple_acl_update(a, a_cls.__mongometa__.name)
+                if not options.test and not empty_acl: c_artifact.save(a)
 
 def update_project_acl(project_doc):
     '''Convert the old dict-style ACL to a list of ALLOW ACEs. Also move the
     security,tool,delete perms to 'admin'
     '''
-    project_role = M.project_doc_session.db.project_role
     if not isinstance(project_doc['acl'], dict):
         log.warning('Project %s is already updated', project_doc['shortname'])
         return
@@ -93,7 +95,7 @@
     for perm, role_ids in sorted(project_doc['acl'].iteritems()):
         perm = perm_map[perm]
         for rid in role_ids:
-            if project_role.find(dict(_id=rid)).count() == 0: continue
+            if c_project_role.find(dict(_id=rid)).count() == 0: continue
             _grant(new_acl, perm, rid)
     if options.test:
         log.info('--- update %s\n%s\n%s\n---',
@@ -107,23 +109,30 @@
     if options.test: log.info('Update nbhd %s', neighborhood_doc['name'])
     if 'acl' not in neighborhood_doc:
         log.warning('Neighborhood %s already updated', neighborhood_doc['name'])
+        return
     p = Object(init_doc)
     p.root_project=p
-    r_auth = M.ProjectRole.authenticated(p)._id
-    r_admin = M.ProjectRole.by_name('Admin', p)._id
+    r_anon = _project_role(init_doc['_id'], '*anonymous')
+    r_auth = _project_role(init_doc['_id'], '*authenticated')
+    r_admin = _project_role(init_doc['_id'], 'Admin')
     acl = neighborhood_doc['acl']
     new_acl = list(init_doc['acl'])
     assert acl['read'] == [None] # nbhd should be public
     for uid in acl['admin'] + acl['moderate']:
-        u = M.User.query.get(_id=uid)
-        if options.test: log.info('... grant nbhd admin to: %s', u.username)
-        role =  M.ProjectRole.upsert(user_id=uid, project_id=init_doc['_id'])
-        if r_admin not in role.roles:
-            role.roles.append(r_admin)
-    _grant(new_acl, 'register', r_admin)
+        u = c_user.find(dict(_id=uid)).next()
+        if options.test:
+            log.info('... grant nbhd admin to: %s', u['username'])
+            continue
+        role =  _project_role(init_doc['_id'], user_id=uid)
+        if r_admin['_id'] not in role['roles']:
+            role['roles'].append(r_admin['_id'])
+            c_project_role.save(role)
+    _grant(new_acl, 'read', r_anon['_id'])
+    _grant(new_acl, 'admin', r_admin['_id'])
+    _grant(new_acl, 'register', r_admin['_id'])
     if acl['create'] == [ ]:
         if options.test: log.info('grant register to auth')
-        _grant(new_acl, 'register', r_auth)
+        _grant(new_acl, 'register', r_auth['_id'])
     del neighborhood_doc['acl']
     if options.test:
         log.info('--- new init acl:\n%s\n%s\n---',
@@ -131,10 +140,26 @@
                  pformat(map(_format_ace, new_acl)))
     init_doc['acl'] = new_acl
 
-def simple_acl_update(doc):
+def _project_role(project_id, name=None, user_id=None):
+    doc = dict(project_id=project_id)
+    if name:
+        doc['name'] = name
+    else:
+        doc['user_id'] = user_id
+    for role in c_project_role.find(doc):
+        return role
+    assert name is None
+    doc.update(
+        _id=bson.ObjectId(),
+        roles=[])
+    c_project_role.save(doc)
+    return doc
+                                 
+
+def simple_acl_update(doc, collection_name):
     '''Update dict-style to list-style ACL'''
     if not isinstance(doc['acl'], dict):
-        log.warning('Already upgraded %s' % doc)
+        log.warning('Already upgraded %s: %s', collection_name, doc)
         return
 
     new_acl = []
@@ -142,7 +167,8 @@
         for rid in role_ids:
             _grant(new_acl, perm, rid)
     if options.test and doc['acl']:
-        log.info('--- update\n%s\n%s\n---',
+        log.info('--- update %s %s\n%s\n%s\n---',
+                 collection_name, doc['_id'],
                  pformat(_format_acd(doc['acl'])),
                  pformat(map(_format_ace, new_acl)))
     doc['acl'] = new_acl
@@ -161,12 +187,13 @@
         ace['access'], ace['permission'], _format_role(ace['role_id']))
 
 def _format_role(rid):
-    role = M.ProjectRole.query.get(_id=rid)
-    if role:
-        if role.name:
-            return role.name
-        if role.user:
-            return role.user.username
+    for role in c_project_role.find(dict(_id=rid)):
+        if role['name']:
+            return role['name']
+        if role['user_id']:
+            u = c_user.find(_id=role['user_id']).next()
+            return u['username']
+        break
     return '--invalid--'
 
 def _format_acd(acd):