Orgs: allow setting org admin via web interface / PATCH request

This commit is contained in:
Sybren A. Stüvel 2017-08-23 17:13:39 +02:00
parent a5d11ec31b
commit f1edb901d1
5 changed files with 122 additions and 2 deletions

View File

@ -144,6 +144,22 @@ class OrgManager:
return org_doc
def assign_admin(self, org_id: bson.ObjectId, *, user_id: bson.ObjectId):
"""Assigns a user as admin user for this organization."""
assert isinstance(org_id, bson.ObjectId)
assert isinstance(user_id, bson.ObjectId)
org_coll = current_app.db('organizations')
users_coll = current_app.db('users')
if users_coll.count({'_id': user_id}) == 0:
raise ValueError('User not found')
self._log.info('Updating organization %s, setting admin user to %s', org_id, user_id)
org_coll.update_one({'_id': org_id},
{'$set': {'admin_uid': user_id}})
def remove_user(self,
org_id: bson.ObjectId,
*,

View File

@ -64,6 +64,26 @@ class OrganizationPatchHandler(patch_handler.AbstractPatchHandler):
org_doc = current_app.org_manager.assign_single_user(org_id, user_id=user_oid)
return jsonify(org_doc)
@authorization.require_login()
def patch_assign_admin(self, org_id: bson.ObjectId, patch: dict):
"""Assigns a single user by User ID as admin of the organization.
The calling user must be admin of the organization.
"""
self._assert_is_admin(org_id)
# Do some basic validation.
try:
user_id = patch['user_id']
except KeyError:
raise wz_exceptions.BadRequest('No key "user_id" in patch.')
user_oid = str2id(user_id)
log.info('User %s uses PATCH to set user %s as admin for organization %s',
current_user().user_id, user_oid, org_id)
current_app.org_manager.assign_admin(org_id, user_id=user_oid)
@authorization.require_login()
def patch_remove_user(self, org_id: bson.ObjectId, patch: dict):
"""Removes a user from an organization.

View File

@ -9,8 +9,7 @@ from pillar import current_app
from pillar.api.utils import authorization, str2id, gravatar
from pillar.web.system_util import pillar_api
from pillarsdk import Organization
from pillarsdk import Organization, User
log = logging.getLogger(__name__)
blueprint = Blueprint('pillar.web.organizations', __name__, url_prefix='/organizations')
@ -51,6 +50,8 @@ def view_embed(organization_id: str):
member['avatar'] = gravatar(member.get('email'))
member['_id'] = str(member['_id'])
admin_user = User.find(organization.admin_uid, api=api)
# Make sure it's never None
organization.unknown_members = organization.unknown_members or []
@ -61,6 +62,7 @@ def view_embed(organization_id: str):
return render_template('organizations/view_embed.html',
organization=organization,
admin_user=admin_user,
members=members,
can_edit=can_edit,
can_super_edit=can_super_edit,

View File

@ -39,6 +39,12 @@
placeholder="Organization roles",
value="{{ organization.org_roles | hide_none | sort | join(' ') }}")
| {% endif %}
.input-group
input#admin-select.form-control(
name='admin_user',
type='text',
placeholder='Administrator',
value='{{ admin_user.full_name }}')
.input-group
button#item-save.btn.btn-default.btn-block(type='submit')
i.pi-check
@ -49,6 +55,7 @@
p.item-description {{ organization.description | hide_none }}
p.item-website {{ organization.website | hide_none }}
p.item-location {{ organization.location | hide_none }}
p.item-admin-user {{ admin_user.full_name }}
| {% endif %}
| {% endif %}
@ -201,6 +208,14 @@ script.
}
}
);
$('#admin-select').userSearch(
'{{config.ALGOLIA_USER}}',
'{{config.ALGOLIA_PUBLIC_KEY}}',
'{{config.ALGOLIA_INDEX_USERS}}',
function (event, hit, dataset) {
setAdmin(hit.objectID);
}
);
function addUser(userId) {
if (!userId || userId.length == 0) {
@ -225,6 +240,25 @@ script.
});
};
function setAdmin(userId) {
if (!userId || userId.length == 0) {
toastr.error('Please select a user from the list');
return;
}
patchOrganization({
op: 'assign-admin',
user_id: userId
})
.done(function (data) {
window.location.reload();
toastr.info('Updated admin user');
})
.fail(function (err) {
var msg = xhrErrorResponseMessage(err);
toastr.error('Could not add member: ' + msg);
});
};
});
| {% endif %}

View File

@ -357,6 +357,54 @@ class OrganizationPatchTest(AbstractPillarTest):
self.assertEqual('Open Source animation studio', db_org['description'])
self.assertEqual('https://blender.institute/', db_org['website'])
def test_assign_admin(self):
self.enter_app_context()
om = self.app.org_manager
admin_uid = self.create_user(24 * 'a', token='admin-token')
new_admin_uid = self.create_user(24 * 'b', token='other-admin-token')
org_doc = om.create_new_org('Хакеры', admin_uid, 25)
org_id = org_doc['_id']
# Try the PATCH to assign the other user as admin
self.patch(f'/api/organizations/{org_id}',
json={
'op': 'assign-admin',
'user_id': str(new_admin_uid),
},
auth_token='admin-token',
expected_status=204)
db = self.app.db('organizations')
db_org = db.find_one(org_id)
self.assertEqual(new_admin_uid, db_org['admin_uid'])
def test_assign_admin_as_nonadmin(self):
self.enter_app_context()
om = self.app.org_manager
admin_uid = self.create_user(24 * 'a', token='admin-token')
new_admin_uid = self.create_user(24 * 'b', token='other-admin-token')
org_doc = om.create_new_org('Хакеры', admin_uid, 25)
org_id = org_doc['_id']
# Try the PATCH to assign the other user as admin
self.patch(f'/api/organizations/{org_id}',
json={
'op': 'assign-admin',
'user_id': str(new_admin_uid),
},
auth_token='other-admin-token',
expected_status=403)
db = self.app.db('organizations')
db_org = db.find_one(org_id)
self.assertEqual(admin_uid, db_org['admin_uid'])
class OrganizationResourceEveTest(AbstractPillarTest):
"""Test GET/POST/PUT access to Organization resource"""