Handle registration of previously unknown organization members.

When a new user is created, two things happen:
  - before inserting into MongoDB, the organizational roles are given
  - after inserting, the organizations are updated to move the user from
    `unknown_members` to `members`.
This commit is contained in:
2017-08-23 13:41:17 +02:00
parent b53d485960
commit 72404d0fd9
4 changed files with 143 additions and 2 deletions

View File

@@ -252,6 +252,47 @@ class OrgManager:
org = self._get_org(org_id, projection={'admin_uid': 1})
return org['admin_uid'] == uid
def unknown_member_roles(self, member_email: str) -> typing.Set[str]:
"""Returns the set of organization roles for this user.
Assumes the user is not yet known, i.e. part of the unknown_members lists.
"""
org_coll = current_app.db('organizations')
# Aggregate all org-given roles for this user.
query = org_coll.aggregate([
{'$match': {'unknown_members': member_email}},
{'$project': {'org_roles': 1}},
{'$unwind': {'path': '$org_roles'}},
{'$group': {
'_id': None,
'org_roles': {'$addToSet': '$org_roles'},
}}])
# If the user has no organizations at all, the query will have no results.
try:
org_roles_doc = query.next()
except StopIteration:
return set()
return set(org_roles_doc['org_roles'])
def make_member_known(self, member_uid: bson.ObjectId, member_email: str):
"""Moves the given member from the unknown_members to the members lists."""
# This uses a direct PyMongo query rather than using Eve's put_internal,
# to prevent simultaneous updates from dropping users.
org_coll = current_app.db('organizations')
for org in org_coll.find({'unknown_members': member_email}):
self._log.info('Updating organization %s, marking member %s/%s as known',
org['_id'], member_uid, member_email)
org_coll.update_one({'_id': org['_id']},
{'$addToSet': {'members': member_uid},
'$pull': {'unknown_members': member_email}
})
def setup_app(app):
from . import patch, hooks

View File

@@ -71,6 +71,9 @@ def setup_app(app, api_prefix):
app.on_fetched_item_users += hooks.after_fetching_user
app.on_fetched_resource_users += hooks.after_fetching_user_resource
app.on_insert_users += hooks.before_inserting_users
app.on_inserted_users += hooks.after_inserting_users
app.register_api_blueprint(blueprint_api, url_prefix=api_prefix)
service.signal_user_changed_role.connect(_update_algolia_user_changed_role)

View File

@@ -1,11 +1,14 @@
import copy
import json
import bson
from eve.utils import parse_request
from flask import current_app, g
from flask import g
from werkzeug import exceptions as wz_exceptions
from pillar import current_app
from pillar.api.users.routes import log
from pillar.api.utils.authorization import user_has_role
from werkzeug import exceptions as wz_exceptions
USER_EDITABLE_FIELDS = {'full_name', 'username', 'email', 'settings'}
@@ -152,3 +155,45 @@ def post_GET_user(request, payload):
# json_data['computed_permissions'] = \
# compute_permissions(json_data['_id'], app.data.driver)
payload.data = json.dumps(json_data)
def grant_org_roles(user_doc):
"""Handle any organization this user may be part of."""
email = user_doc.get('email')
if not email:
log.warning('Unable to check new user for organization membership, no email address! %r',
user_doc)
return
org_roles = current_app.org_manager.unknown_member_roles(email)
if not org_roles:
log.debug('No organization roles for user %r', email)
return
log.info('Granting organization roles %r to user %r', org_roles, email)
new_roles = set(user_doc.get('roles') or []) | org_roles
user_doc['roles'] = list(new_roles)
def before_inserting_users(user_docs):
"""Grants organization roles to the created users."""
for user_doc in user_docs:
grant_org_roles(user_doc)
def after_inserting_users(user_docs):
"""Moves the users from the unknown_members to the members list of their organizations."""
om = current_app.org_manager
for user_doc in user_docs:
user_id = user_doc.get('_id')
user_email = user_doc.get('email')
if not user_id or not user_email:
log.warning('User created with _id=%r and email=%r, unable to check organizations',
user_id, user_email)
continue
om.make_member_known(user_id, user_email)