async def remove_user( user_id: str, user: UserInfo = Depends(Authentication()), ): if 'admin' not in user['roles']: raise HTTPException(401) result = await async_user_collection.delete_one({'_id': user_id}) if result.deleted_count != 1: raise HTTPException(404, "User does not exist") if user.picture: try: await async_user_picture_bucket.delete(user.picture) except gridfs.errors.NoFile: pass await async_session_collection.delete({'user_id': user_id}) await async_authorization_code_collection.delete({'user_id': user_id}) await async_token_collection.delete({'user_id': user_id}) await async_user_group_collection.update_many({'members': user_id}, { '$pull': { 'members': user_id, 'email_forward_members': user_id, 'email_allowed_forward_members': user_id, 'email_postbox_access_members': user_id, } }) await async_client_user_cache_collection.delete_many({'user_id': user_id})
async def request_reset_user_password( user_id: str, user: UserInfo = Depends(Authentication()), ): is_admin = 'admin' in user['roles'] if not is_admin: raise HTTPException(401) user_data = DotDict.from_obj(await async_user_collection.find_one( {'_id': user_id})) if user_data is None: raise HTTPException(404, "User not found") if user_data.get('registration_token'): await update_resend_registration(user_data) else: token_valid_until = int(time.time() + config.manager.token_valid.password_reset) user_data['password_reset_token'] = create_token( user_data['_id'], token_valid_until) await async_user_collection.update_one({'_id': user_data['_id']}, { '$set': { 'password_reset_token': user_data['password_reset_token'] }, }) await async_send_mail_reset_password(user_data, token_valid_until)
async def get_user( user_id: str, user: UserInfo = Depends(Authentication())) -> UserViewData: """Gets user data.""" is_admin = 'admin' in user['roles'] is_self = user.sub == user_id if not is_self and not is_admin: raise HTTPException(401) user_data = DotDict.from_obj(await async_user_collection.find_one( {'_id': user_id})) if user_data is None: raise HTTPException(404) user_data['sub'] = user_data['_id'] if user_data.get('picture') is not None: user_data[ 'picture'] = f"{config.oauth2.base_url}/picture/{user_data['picture']}" if 'password' in user_data: del user_data['password'] return UserViewData( user_id=user_data['_id'], properties=[ UserPropertyWithValue(key=prop, value=_get_user_property_value( prop, user_data, is_self, is_admin), **config.oauth2.user.properties[prop].dict()) for prop in config.manager.view if config.oauth2.user.properties[prop].can_read.has_access( is_self, is_admin) or config.oauth2.user.properties[prop]. can_edit.has_access(is_self, is_admin) ])
async def delete_group( group_id: str, user: UserInfo = Depends(Authentication()), ): """Deletes a group.""" if 'admin' not in user['roles']: raise HTTPException(401) await async_user_collection.update_many( {'groups': group_id}, { '$pull': { 'groups': group_id, 'email_forward_groups': group_id, 'email_allowed_forward_groups': group_id, 'email_postbox_access_groups': group_id, }, '$set': {'updated_at': int(time.time())}, } ) await async_client_collection.update_many( {'access_groups.group': group_id}, {'$pull': {'access_groups': {'group': group_id}}}, ) await async_client_user_cache_collection.delete_many({'groups': group_id}) await async_user_group_collection.update_many( {'member_groups': group_id}, {'$pull': { 'member_groups': group_id, }} ) result = await async_user_group_collection.delete_one({'_id': group_id}) if result.deleted_count != 1: raise HTTPException(404)
async def upload_picture( user_id: str, file: UploadFile = File(..., media_type='application/octet-stream'), user: UserInfo = Depends(Authentication(auto_error=False)), registration_token: Optional[str] = Header(None, alias="x-token"), ): """Uploads a new picture for the passed user.""" if user is not None: is_admin = 'admin' in user['roles'] is_self = user.sub == user_id if not is_self or not is_admin: raise HTTPException(401) user_data = await async_user_collection.find_one({'_id': user_id}) elif registration_token is not None: check_token(registration_token) user_data = await async_user_collection.find_one( {'registration_token': registration_token}) else: raise HTTPException(401) if user_data is None: raise HTTPException(404) user = User.validate(user_data) if user.picture is None: user.picture = generate_token(48) updated_at = int(time.time()) await async_user_collection.update_one( {'_id': user_id}, {'$set': { 'picture': user.picture, 'updated_at': updated_at }}) await async_client_user_cache_collection.update_many( {'user_id': user_data['_id']}, {'$set': { 'last_modified': updated_at }}, ) else: try: await async_user_picture_bucket.delete(user.picture) except gridfs.errors.NoFile: pass hash_ = hashlib.sha512() while True: chunk = await file.read(4 * 1024) if not chunk: break hash_.update(chunk) await file.seek(0) file.file.seek(0) await async_user_picture_bucket.upload_from_stream_with_id( user.picture, user.id, file.file, metadata={ 'content_type': file.content_type, 'hash': hash_.digest() })
async def get_clients( user: UserInfo = Depends(Authentication()), ) -> List[ClientInList]: """Gets all clients.""" if 'admin' not in user['roles']: raise HTTPException(401) return [ ClientInList.validate(Client.validate(client)) async for client in async_client_collection.find() ]
async def create_client( client_data: ClientInCreate = Body(...), user: UserInfo = Depends(Authentication()), ): """Creates a client.""" if 'admin' not in user['roles']: raise HTTPException(401) new_client = Client.validate(client_data) await async_client_collection.insert_one( new_client.dict(exclude_none=True, by_alias=True))
async def get_client( client_id: str, user: UserInfo = Depends(Authentication()), ): """Gets a client.""" if 'admin' not in user['roles']: raise HTTPException(401) client_data = await async_client_collection.find_one({'_id': client_id}) if client_data is None: raise HTTPException(404) return ClientInRead.validate(Client.validate(client_data))
async def get_group( group_id: str, user: UserInfo = Depends(Authentication()), ): """Gets a group.""" if 'admin' not in user['roles']: raise HTTPException(401) group_data = await async_user_group_collection.find_one({'_id': group_id}) if group_data is None: raise HTTPException(404) return GroupInRead.validate(UserGroup.validate(group_data))
async def get_groups( user: UserInfo = Depends(Authentication()), ) -> List[GroupInList]: """Gets all groups.""" if 'admin' in user['roles']: group_filter = {} else: group_filter = {'visible': True} return [ GroupInList.validate(UserGroup.validate(group)) async for group in async_user_group_collection.find(group_filter) ]
async def delete_client( client_id: str, user: UserInfo = Depends(Authentication()), ): """Deletes a client.""" if 'admin' not in user['roles']: raise HTTPException(401) await async_client_user_cache_collection.delete_many( {'client_id': client_id}) result = await async_client_collection.delete_one({'_id': client_id}) if result.deleted_count != 1: raise HTTPException(404)
async def resend_registration( user_id: str, user: UserInfo = Depends(Authentication()), ): """Sends the registration token email again.""" is_admin = 'admin' in user['roles'] if not is_admin: raise HTTPException(401) user_data = DotDict.from_obj(await async_user_collection.find_one( {'_id': user_id})) if user_data is None: raise HTTPException(404) await update_resend_registration(user_data)
async def create_user(no_registration: bool = Query(False), create_data: Dict[str, Any] = Body(...), user: UserInfo = Depends(Authentication())): """Updates user data.""" is_admin = 'admin' in user['roles'] if not is_admin: raise HTTPException(401) user_data = DotDict() await _update_user(user_data, create_data, is_new=True, is_admin=True, no_registration=no_registration)
async def create_group( group_data: GroupInCreate = Body(...), user: UserInfo = Depends(Authentication()), ): """Creates a group.""" if 'admin' not in user['roles']: raise HTTPException(401) new_group = UserGroup.validate(group_data) new_group.id = new_group.id.lower() if not new_group.enable_email: new_group.email_forward_members = [] new_group.email_allowed_forward_members = [] if not new_group.enable_postbox: new_group.email_postbox_access_members = [] await async_user_group_collection.insert_one(new_group.dict(exclude_none=True, by_alias=True)) timestamp = int(time.time()) if new_group.members: await async_client_user_cache_collection.delete_many({'user_id': {'$in': new_group.members}}) await async_user_collection.update_many( {'_id': {'$in': new_group.members}}, { '$addToSet': {'groups': new_group.id}, '$set': {'updated_at': timestamp}, } ) if new_group.email_forward_members: await async_user_collection.update_many( {'_id': {'$in': new_group.email_forward_members}}, { '$addToSet': {'email_forward_groups': new_group.id}, '$set': {'updated_at': timestamp}, } ) if new_group.email_allowed_forward_members: await async_user_collection.update_many( {'_id': {'$in': new_group.email_allowed_forward_members}}, { '$addToSet': {'email_allowed_forward_groups': new_group.id}, '$set': {'updated_at': timestamp}, } ) if new_group.email_postbox_access_members: await async_user_collection.update_many( {'_id': {'$in': new_group.email_postbox_access_members}}, { '$addToSet': {'email_postbox_access_groups': new_group.id}, '$set': {'updated_at': timestamp}, } )
async def reverify_email( user_id: str, user: UserInfo = Depends(Authentication()), ): """Updates user data.""" is_admin = 'admin' in user['roles'] is_self = user.sub == user_id if not is_self and not is_admin: raise HTTPException(401) user_data = DotDict.from_obj(await async_user_collection.find_one( {'_id': user_id})) if user_data is None: raise HTTPException(404) user_data['email_verified'] = False await _update_user(user_data, {'email': user_data['email']}, is_admin=is_admin, is_self=is_self)
async def update_user(user_id: str, update_data: Dict[str, Any] = Body(...), user: UserInfo = Depends(Authentication())): """Updates user data.""" is_admin = 'admin' in user['roles'] is_self = user.sub == user_id if not is_self and not is_admin: raise HTTPException(401) user_data = DotDict.from_obj(await async_user_collection.find_one( {'_id': user_id})) if user_data is None: raise HTTPException(404) if not update_data: return await _update_user(user_data, update_data, is_admin=is_admin, is_self=is_self)
def get_create_user(user: UserInfo = Depends( Authentication())) -> UserViewData: """Gets user data for creation.""" is_admin = 'admin' in user['roles'] if not is_admin: raise HTTPException(401) return UserViewData( user_id="new", properties=[ UserPropertyWithValue( key=prop, value=config.oauth2.user.properties[prop].default, **config.oauth2.user.properties[prop].dict()) for prop in config.manager.view if config.oauth2.user.properties[prop].can_read.has_access( is_admin=is_admin) or config.oauth2.user.properties[prop]. can_edit.has_access(is_admin=is_admin) ])
async def update_client( client_id: str, client_update: ClientInWrite, user: UserInfo = Depends(Authentication()), ): """Updates a client.""" if 'admin' not in user['roles']: raise HTTPException(401) if await async_client_collection.count_documents({'_id': client_id}) != 1: raise HTTPException(404) client = Client.validate(client_update) await async_client_user_cache_collection.delete_many( {'client_id': client_id}) result = await async_client_collection.replace_one( {'_id': client_id}, client.dict(exclude_none=True, by_alias=True), ) if result.matched_count != 1: raise HTTPException(404)
async def get_users(user: UserInfo = Depends( Authentication())) -> UsersListViewData: """Gets user data.""" is_admin = 'admin' in user['roles'] if not is_admin: raise HTTPException(401) users_data = async_user_collection.find() users: List[UserListViewData] = [] async for user_data in users_data: user_data['sub'] = user_data['_id'] if user_data.get('picture') is not None: user_data[ 'picture'] = f"{config.oauth2.base_url}/picture/{user_data['picture']}" if 'password' in user_data: del user_data['password'] users.append( UserListViewData( user_id=user_data['_id'], properties=[ UserListProperty( key=prop, value=_get_user_property_value( prop, user_data, user_data['_id'] == user.sub, is_admin), ) for prop in config.manager.list if config.oauth2.user.properties[prop].can_read.has_access( user_data['_id'] == user.sub, is_admin) or config.oauth2.user.properties[prop].can_edit.has_access( user_data['_id'] == user.sub, is_admin) ])) return UsersListViewData( properties=[ UserPropertyWithKey(key=prop, **config.oauth2.user.properties[prop].dict()) for prop in config.manager.list ], users=users, )
async def update_group( group_id: str, group_update: GroupInWrite, user: UserInfo = Depends(Authentication()), ): """Updates a group.""" if 'admin' not in user['roles']: raise HTTPException(401) group_data = await async_user_group_collection.find_one({'_id': group_id}) if group_data is None: raise HTTPException(404) group = UserGroup.validate(group_data) if not group_update.enable_email: group_update.email_forward_members = [] group_update.email_allowed_forward_members = [] if not group_update.enable_postbox: group_update.email_postbox_access_members = [] await _update_groups( group, group_update, attr_name='members', add_user_attr_name='groups', pull_user_attr_names=('groups', 'email_forward_groups', 'email_allowed_forward_groups'), pull_group_attr_names=( 'email_forward_members', 'email_allowed_forward_members', 'email_postbox_access_members' ), clear_cache=True, ) await _update_groups( group, group_update, attr_name='email_allowed_forward_members', add_user_attr_name='email_allowed_forward_groups', pull_user_attr_names=('email_forward_groups', 'email_allowed_forward_groups'), pull_group_attr_names=('email_forward_members',), clear_cache=False, ) await _update_groups( group, group_update, attr_name='email_forward_members', add_user_attr_name='email_forward_groups', pull_user_attr_names=('email_forward_groups',), clear_cache=False, ) await _update_groups( group, group_update, attr_name='email_postbox_access_members', add_user_attr_name='email_postbox_access_groups', pull_user_attr_names=('email_postbox_access_groups',), clear_cache=False, ) group.update_from(group_update) result = await async_user_group_collection.replace_one( {'_id': group_id}, group.dict(exclude_none=True, by_alias=True), ) if result.matched_count != 1: raise HTTPException(404)