import sys
import logging
from collections import OrderedDict

from pylons import c
from ming.orm import session
from bson import ObjectId

from allura import model as M
from forgewiki.wiki_main import ForgeWikiApp

log = logging.getLogger('fix-home-permissions')
handler = logging.StreamHandler(sys.stdout)
log.addHandler(handler)

TEST = sys.argv[-1].lower() == 'test'

def main():

    if TEST:
        log.info('Examining permissions for all Home Wikis')
    else:
        log.info('Fixing permissions for all Home Wikis')

    for some_projects in chunked_project_iterator({'neighborhood_id': {'$nin': [ObjectId('4be2faf8898e33156f00003e'),       # /u
                                                                                ObjectId('4dbf2563bfc09e6362000005')]}}):   # /motorola
        for project in some_projects:
            c.project = project
            home_app = project.app_instance('home')
            if isinstance(home_app, ForgeWikiApp):
                log.info('Examining permissions in project "%s".' % project.shortname)
                root_project = project.root_project or project
                authenticated_role = project_role(root_project, '*authenticated')
                member_role = project_role(root_project, 'Member')

                # remove *authenticated create/update permissions
                new_acl = OrderedDict(
                    ((ace.role_id, ace.access, ace.permission), ace)
                    for ace in home_app.acl
                    if not (
                        ace.role_id==authenticated_role._id and ace.access==M.ACE.ALLOW and ace.permission in ('create', 'edit', 'delete', 'unmoderated_post')
                    )
                )
                if (member_role._id, M.ACE.ALLOW, 'update') in new_acl:
                    del new_acl[(member_role._id, M.ACE.ALLOW, 'update')]

                # add member create/edit permissions
                new_acl[(member_role._id, M.ACE.ALLOW, 'create')] = M.ACE.allow(member_role._id, 'create')
                new_acl[(member_role._id, M.ACE.ALLOW, 'edit')] = M.ACE.allow(member_role._id, 'edit')
                new_acl[(member_role._id, M.ACE.ALLOW, 'unmoderated_post')] = M.ACE.allow(member_role._id, 'unmoderated_post')

                if TEST:
                    log.info('...would update acl for home app in project "%s".' % project.shortname)
                else:
                    log.info('...updating acl for home app in project "%s".' % project.shortname)
                    home_app.config.acl = map(dict, new_acl.values())
                    session(home_app.config).flush()

PAGESIZE=1024

def chunked_project_iterator(q_project):
    '''shamelessly copied from refresh-all-repos.py'''
    page = 0
    while True:
        results = (M.Project.query
                   .find(q_project)
                   .skip(PAGESIZE*page)
                   .limit(PAGESIZE)
                   .all())
        if not results: break
        yield results
        page += 1

def project_role(project, name):
    role = M.ProjectRole.query.get(project_id=project._id, name=name)
    if role is None:
        role = M.ProjectRole(project_id=project._id, name=name)
    return role

if __name__ == '__main__':
    main()
