[60ada4]: / scripts / add_user_to_group.py  Maximize  Restore  History

Download this file

147 lines (119 with data), 6.4 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""
Add a user to group on a project.
Especially useful for making admin1 a neighborhood admin after loading a
production dataset.
Example:
# Add admin1 to Admin group for the entire /p/ neighborhood:
$ paster script production.ini ../scripts/add_user_to_group.py -- admin1 Admin
# Add admin1 to Member group on project /p/allura:
$ paster script production.ini ../scripts/add_user_to_group.py -- admin1 Member allura
# Add admin1 to Developer group on project /berlios/codeblocks:
$ paster script production.ini ../scripts/add_user_to_group.py -- admin1 Developer codeblocks --nbhd=/berlios/
# Add admin1 to Admin group for entire berlios neighborhood:
$ paster script production.ini ../scripts/add_user_to_group.py -- admin1 Admin --nbhd=/berlios/
# Replace admin1 with admin2 in all individual projects in berlios neighborhood:
$ paster script production.ini ../scripts/add_user_to_group.py -- admin2 Admin ALLPROJECTS --nbhd=/berlios/ --replace-users admin1
"""
import logging
from allura import model as M
from allura.lib.utils import chunked_find
from allura.model import main_orm_session
from ming.odm import ThreadLocalODMSession
log = logging.getLogger(__name__)
def main(options):
nbhd = M.Neighborhood.query.get(url_prefix=options.nbhd)
if not nbhd:
return "Couldn't find neighborhood with url_prefix '%s'" % options.nbhd
user = M.User.by_username(options.user)
if not user:
return "Couldn't find user with username '%s'" % options.user
replace_users = []
for replace_username in options.replace_users:
u = M.User.by_username(replace_username)
if not u:
return "Couldn't find user with username '%s'" % replace_username
else:
replace_users.append(u)
if options.project == 'ALLPROJECTS':
for chunk in chunked_find(M.Project, dict(
neighborhood_id=nbhd._id,
shortname={'$ne': '--init--'},
)):
for p in chunk:
update_project(options, user, p, replace_users=replace_users)
# clears User, Project, ProjectRole... so they're not taking up memory and making flush_all() be slow
main_orm_session.clear()
else:
project = M.Project.query.get(neighborhood_id=nbhd._id,
shortname=options.project)
if not project:
return "Couldn't find project with shortname '%s'" % options.project
update_project(options, user, project, replace_users=replace_users)
def update_project(options, user, project, replace_users=None):
project_role = M.ProjectRole.by_name(options.group, project=project)
if not project_role:
return f"Couldn't find group (ProjectRole) with name '{options.group}' in {project.url()}"
found_any_replace_users = False
for replace_user in replace_users:
replace_user_perm = M.ProjectRole.by_user(replace_user, project=project)
if not replace_user_perm or project_role._id not in replace_user_perm.roles:
log.info('Cannot replace %s they are not %s of %s', replace_user.username, options.group, project.url())
continue
found_any_replace_users = True
if options.dry_run:
log.info('Would remove %s as %s of %s', replace_user.username, options.group, project.url())
else:
replace_user_perm.roles.remove(project_role._id)
if len(replace_user_perm.roles) == 0:
# user has no roles in this project any more, so don't leave a useless doc around
replace_user_perm.delete()
ThreadLocalODMSession.flush_all()
if replace_users and not found_any_replace_users:
log.info('Not adding %s since no replace-users found on %s', user.username, project.url())
return
user_roles = M.ProjectRole.by_user(user, project=project, upsert=True).roles
if project_role._id in user_roles:
log.info('%s is already %s of %s', user.username, options.group, project.url())
return
if options.dry_run:
log.info('Would add %s as %s of %s', user.username, options.group, project.url())
else:
user_roles.append(project_role._id)
ThreadLocalODMSession.flush_all()
def parse_options():
import argparse
parser = argparse.ArgumentParser(description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('user', help='Username to add')
parser.add_argument('group', help='Group (ProjectRole) name, e.g. Admin, '
'Member, Developer, etc.')
parser.add_argument('project', nargs='?', default='--init--',
help='Project shortname. Default is --init-- (the neighborhood itself). '
'Use "ALLPROJECTS" for all projects within a neighborhood')
parser.add_argument('--nbhd', default='/p/', help='Neighborhood '
'url_prefix. Default is /p/.')
parser.add_argument('--replace-users', nargs='*',
help='If specified, remove these username(s) and only add the new user if one of the replace '
'user(s) was found and removed from each project')
parser.add_argument('--dry-run', action='store_true',
help='Dry-run actions logged to log file')
return parser.parse_args()
if __name__ == '__main__':
import sys
sys.exit(main(parse_options()))