async def create_role(self, data, utilizer, event_service): resource = generate_slug(data) resource['membership_id'] = utilizer['membership_id'] role = await self._check_slug_conflict(resource) role['_id'] = ObjectId() role['membership_owner'] = resource.get('membership_owner', False) role['sys'] = { 'created_at': datetime.datetime.utcnow(), 'created_by': utilizer.get('username', utilizer.get('name')) } await self.db.roles.insert_one(role) role['_id'] = str(role['_id']) await event_service.on_event((Event(**{ 'document': role, 'prior': {}, 'utilizer': utilizer, 'type': 'RoleCreatedEvent', 'membership_id': utilizer['membership_id'], 'sys': { 'created_at': datetime.datetime.utcnow(), 'created_by': utilizer.get('username', utilizer.get('name')) } }))) return role
async def create_application(self, resource, utilizer, event_service): resource['membership_id'] = utilizer['membership_id'] resource['_id'] = ObjectId() resource['sys'] = { 'created_at': datetime.datetime.utcnow(), 'created_by': utilizer.get('username', utilizer.get('name')) } await self.role_service.get_role_by_slug(resource['role'], utilizer['membership_id']) await self._ensure_name_is_unique_in_membership(resource) resource = generate_app_secrets(resource) await self.db.applications.insert_one(resource) await event_service.on_event((Event( **{ 'document': resource, 'prior': {}, 'utilizer': utilizer, 'type': 'ApplicationCreatedEvent', 'membership_id': utilizer['membership_id'], 'sys': { 'created_at': datetime.datetime.utcnow(), 'created_by': utilizer.get('username', utilizer.get( 'name')) } }))) return resource
async def set_password(self, payload, membership_id, event_service): email = payload['email'].lower() password = payload['password'] reset_token = payload['reset_token'] user = await self._find_user_by_query({ 'email': email, 'reset_password.reset_token': reset_token, 'membership_id': membership_id }) await asyncio.gather( self._reset_user_password(user, password), event_service.on_event( Event( **{ 'document': user, 'prior': {}, 'utilizer': user, 'type': 'PasswordResetEvent', 'membership_id': user['membership_id'], 'sys': { 'created_at': datetime.datetime.utcnow() } }))) await self.user_service.revoke_and_delete_old_active_tokens(user)
async def verify_token(self, token, settings, event_service): await ensure_token_is_not_revoked(self.db, token) user = await self.validate_token(token, settings['application_secret'], verify=True) token_response = { 'verified': True, 'refreshable': user['decoded_token'].get('rf'), 'token': token } await event_service.on_event( Event( **{ 'document': token_response, 'prior': {}, 'utilizer': user, 'type': 'TokenVerifiedEvent', 'membership_id': user['membership_id'], 'sys': { 'created_at': datetime.datetime.utcnow() } })) return token_response
async def reset_password(self, payload, membership_id, event_service): email = payload['email'].lower() user = await self._find_user_by_query({ 'email': email, 'membership_id': membership_id }) password_reset = generate_password_reset_fields() user = await self._set_reset_password_to_user( user['_id'], membership_id, { 'reset_password': password_reset, 'ip_info': user.get('ip_info', {}) }) await event_service.on_event( Event( **{ 'document': password_reset, 'prior': {}, 'utilizer': user, 'type': 'PasswordResetEvent', 'membership_id': user['membership_id'], 'sys': { 'created_at': datetime.datetime.utcnow() } })) return user
async def update_user(self, resource_id, data, utilizer, user_type_service, event_service): membership_id = utilizer['membership_id'] resource = await self._find_user(resource_id, membership_id) provided_data = pop_non_updatable_fields(data) await validate_user_model_by_user_type(membership_id, resource, user_type_service, operation=OperationTypes.UPDATE) resource = prepare_user_fields(resource, utilizer['membership_id'], data.get('password'), opt='update') _resource = copy.deepcopy(resource) _resource.update(provided_data) if _resource == resource: raise ErtisError(err_code="errors.identicalDocument", err_msg="Identical document error", status_code=409) if _resource['username'] != resource['username']: await self.revoke_and_delete_old_active_tokens(_resource) resource['sys'].update({ 'modified_at': datetime.datetime.utcnow(), 'modified_by': utilizer.get('username', utilizer.get('name')) }) provided_data['sys'] = resource['sys'] resource = await self.update_user_with_body(resource_id, utilizer['membership_id'], provided_data) resource.pop('password') resource['_id'] = str(resource['_id']) _resource['_id'] = str(_resource['_id']) await event_service.on_event((Event( **{ 'document': resource, 'prior': _resource, 'utilizer': utilizer, 'type': 'UserUpdatedEvent', 'membership_id': utilizer['membership_id'], 'sys': { 'created_at': datetime.datetime.utcnow(), 'created_by': utilizer.get('username', utilizer.get( 'name')) } }))) return resource
async def create_provider(self, resource, utilizer): resource['membership_id'] = utilizer['membership_id'] resource['_id'] = ObjectId() resource['sys'] = { 'created_at': datetime.datetime.utcnow(), 'created_by': utilizer.get('username', utilizer.get('name')) } resource['slug'] = slugify(resource['name']) default_role = resource.get('default_role') exists_role = await self.db.roles.find_one({ "slug": default_role, "membership_id": utilizer['membership_id'] }) if not exists_role: raise ErtisError( err_code="errors.roleNotFound", err_msg="Role not found by given slug: <{}>".format( default_role), status_code=400) exist_provider = await self.db.providers.find_one({ 'slug': resource['slug'], 'membership_id': utilizer['membership_id'] }) if exist_provider: raise ErtisError( err_msg= "Provider already exists in db with given generated slug: <{}>" .format(resource['slug']), err_code="errors.resourceAlreadyExists", status_code=409) await self.db.providers.insert_one(resource) await self.event_service.on_event((Event( **{ 'document': resource, 'prior': {}, 'utilizer': utilizer, 'type': 'ProviderCreatedEvent', 'membership_id': utilizer['membership_id'], 'sys': { 'created_at': datetime.datetime.utcnow(), 'created_by': utilizer.get('username', utilizer.get( 'name')) } }))) return resource
async def refresh_token(self, do_revoke, refreshable_token, settings, event_service): revoke_flag = True if do_revoke == 'true' else False user = await self._load_user(refreshable_token, settings['application_secret'], settings['verify_token']) if user['decoded_token']['rf'] is False: raise ErtisError(err_msg="Provided token is not refreshable", err_code="errors.refreshableTokenError", status_code=400) membership = await self.db.memberships.find_one( {'_id': maybe_object_id(user['membership_id'])}) await ensure_token_is_not_revoked(self.db, refreshable_token) refreshed_token = await self._refresh_token( refreshable_token, user, settings['application_secret'], membership['token_ttl'], membership['refresh_token_ttl']) tasks = [ self._update_user_with_token(refreshed_token, user), event_service.on_event((Event( **{ 'document': refreshed_token, 'prior': {}, 'utilizer': user, 'type': 'TokenRefreshedEvent', 'membership_id': user['membership_id'], 'sys': { 'created_at': datetime.datetime.utcnow() } }))) ] if revoke_flag: tasks.append( self.revoke_token(refreshable_token, settings, event_service, user=user)) tasks.append( self._remove_from_active_tokens(user, refreshable_token, user['decoded_token']['rf'])) tasks.append( self._insert_active_tokens(user, refreshed_token, membership)) await asyncio.gather(*tasks) return refreshed_token
async def delete_role(self, resource_id, utilizer, event_service): role = await self.get_role(resource_id, utilizer["membership_id"]) await self._remove_role(resource_id, utilizer['membership_id']) role['_id'] = str(role['_id']) await event_service.on_event((Event(**{ 'document': {}, 'prior': role, 'utilizer': utilizer, 'type': 'RoleDeletedEvent', 'membership_id': utilizer['membership_id'], 'sys': { 'created_at': datetime.datetime.utcnow(), 'created_by': utilizer.get('username', utilizer.get('name')) } })))
async def update_user_type(self, user_type_id, data, utilizer, event_service): membership_id = utilizer['membership_id'] resource = await self.get_user_type(membership_id, user_type_id=user_type_id) _resource = copy.deepcopy(resource) _resource.update(data) if _resource == resource: raise ErtisError(err_code="errors.identicalDocumentError", err_msg="Identical document error", status_code=409) resource = disallow_update_fields(resource, _resource) resource = regenerate_slug_by_name(resource, _resource) validate(resource) resource['sys'].update({ 'modified_at': datetime.datetime.utcnow(), 'modified_by': utilizer.get('username', utilizer.get('name')) }) data['sys'] = resource['sys'] resource = await update_user_type_with_body(self.db, user_type_id, membership_id, data) resource['_id'] = str(resource['_id']) _resource['_id'] = str(_resource['_id']) await event_service.on_event((Event( **{ 'document': resource, 'prior': _resource, 'utilizer': utilizer, 'type': 'UserTypeUpdatedEvent', 'membership_id': utilizer['membership_id'], 'sys': { 'created_at': datetime.datetime.utcnow(), 'created_by': utilizer.get('username', utilizer.get( 'name')) } }))) return resource
async def create_user(self, resource, membership_id, utilizer, user_type_service, event_service, creator=None): await validate_user_model_by_user_type(membership_id, resource, user_type_service, operation=OperationTypes.CREATE, creator=creator) resource = prepare_user_fields(resource, membership_id, resource['password']) await self._ensure_email_and_username_available(resource) _ = await self.role_service.get_role_by_slug(resource["role"], membership_id) resource['sys'] = { 'created_at': datetime.datetime.utcnow(), 'created_by': utilizer.get('username', utilizer.get('name')) } await self.db.users.insert_one(resource) resource.pop('password', None) resource['_id'] = str(resource['_id']) await event_service.on_event((Event( **{ 'document': resource, 'prior': {}, 'utilizer': utilizer, 'type': 'UserCreatedEvent', 'membership_id': utilizer['membership_id'], 'sys': { 'created_at': datetime.datetime.utcnow(), 'created_by': utilizer.get('username', utilizer.get( 'name')) } }))) return resource
async def delete_provider(self, provider_id, utilizer, event_service): provider = await find_provider(self.db, utilizer['membership_id'], provider_id) await remove_provider(self.db, utilizer['membership_id'], provider_id) provider['_id'] = str(provider['_id']) await event_service.on_event((Event( **{ 'document': {}, 'prior': provider, 'utilizer': utilizer, 'type': 'ProviderDeletedEvent', 'membership_id': utilizer['membership_id'], 'sys': { 'created_at': datetime.datetime.utcnow(), 'created_by': utilizer.get('username', utilizer.get( 'name')) } })))
async def revoke_token(self, token, settings, event_service, user=None): if not user: user = await self.validate_token(token, settings['application_secret'], verify=True) membership = await self.db.memberships.find_one( {'_id': maybe_object_id(user['membership_id'])}) await ensure_token_is_not_revoked(self.db, token) now = datetime.datetime.utcnow() await self.db.revoked_tokens.insert_one({ 'token': token, 'refreshable': user['decoded_token']['rf'], 'revoked_at': now, 'token_owner': user, 'expire_date': now + datetime.timedelta(0, membership['refresh_token_ttl'] * 60) }) await self._remove_from_active_tokens(user, token, user['decoded_token']['rf']) await asyncio.gather( self._update_user_token_status(user, token, 'revoked'), event_service.on_event( Event( **{ 'document': { 'token': token }, 'prior': {}, 'utilizer': user, 'type': 'TokenRevokedEvent', 'membership_id': user['membership_id'], 'sys': { 'created_at': datetime.datetime.utcnow() } })))
async def update_provider(self, provider_id, data, utilizer, event_service): resource = await find_provider(self.db, utilizer['membership_id'], provider_id) _resource = copy.deepcopy(resource) provided_body = pop_non_updatable_fields(data) resource.update(provided_body) if resource == _resource: raise ErtisError(err_msg="Identical document error", err_code="errors.identicalDocument", status_code=409) resource['sys'].update({ 'modified_at': datetime.datetime.utcnow(), 'modified_by': utilizer.get('username', utilizer.get('name')) }) provided_body['sys'] = resource['sys'] updated_provider = await update_provider_with_body( self.db, provider_id, utilizer['membership_id'], provided_body) _resource['_id'] = str(_resource['_id']) updated_provider['_id'] = str(updated_provider['_id']) await event_service.on_event((Event( **{ 'document': updated_provider, 'prior': _resource, 'utilizer': utilizer, 'type': 'ProviderUpdatedEvent', 'membership_id': utilizer['membership_id'], 'sys': { 'created_at': datetime.datetime.utcnow(), 'created_by': utilizer.get('username', utilizer.get( 'name')) } }))) return updated_provider
async def delete_application(self, application_id, utilizer, event_service): application = await self._find_application(application_id, utilizer['membership_id']) await self._remove_application(utilizer['membership_id'], application_id) application['_id'] = str(application['_id']) await event_service.on_event((Event( **{ 'document': {}, 'prior': application, 'utilizer': utilizer, 'type': 'ApplicationDeletedEvent', 'membership_id': utilizer['membership_id'], 'sys': { 'created_at': datetime.datetime.utcnow(), 'created_by': utilizer.get('username', utilizer.get( 'name')) } })))
async def change_password(self, payload, user, event_service): user_id = payload.get('user_id') password = payload.get('password') password_confirm = payload.get('password_confirm') if not (user['role_definition']['membership_owner'] or user_id == str(user['_id'])): raise ErtisError(err_msg="User cannot change other users password", err_code="errors.userCannotChangeOthersPassword", status_code=403) if password != password_confirm: raise ErtisError( err_code="errors.passwordAndPasswordConfirmDoesNotMatch", err_msg="Password and password confirm does not match", status_code=400) hashed_password = hash_user_password(password) await asyncio.gather( self.user_service.update_user_with_body( user_id, user['membership_id'], { 'password': hashed_password, 'ip_info': user.get('ip_info', {}) }), event_service.on_event( Event( **{ 'document': user, 'prior': {}, 'utilizer': user, 'type': 'PasswordChangedEvent', 'membership_id': user['membership_id'], 'sys': { 'created_at': datetime.datetime.utcnow() } })), self.user_service.revoke_and_delete_old_active_tokens(user), )
async def generate_token(self, settings, membership, payload, event_service, **kwargs): membership_id = str(membership['_id']) skip_auth = False payload['username'] = payload['username'].lower() token_generation_parameters = { 'body': payload, 'application_secret': settings['application_secret'], 'token_ttl': membership['token_ttl'], 'refresh_token_ttl': membership['refresh_token_ttl'], 'membership_id': membership_id, 'skip_auth': skip_auth, **kwargs } user = await self._find_user(payload['username'], membership_id) self._check_user_status(user) token = await self._craft_token(user, **token_generation_parameters) await asyncio.gather( self._update_user_with_token(token, user), event_service.on_event((Event( **{ 'document': token, 'prior': {}, 'utilizer': user, 'type': 'TokenCreatedEvent', 'membership_id': membership_id, 'sys': { 'created_at': datetime.datetime.utcnow() } }))), self._insert_active_tokens(user, token, membership)) return token
async def create_user_type(self, resource, utilizer, event_service): membership_id = utilizer['membership_id'] resource = slugify_name(resource) await ensure_user_type_not_exists(resource['slug'], membership_id, self.db) resource['_id'] = ObjectId() resource['sys'] = { 'created_by': utilizer.get('username', utilizer.get('name')), 'created_at': datetime.datetime.utcnow() } resource['membership_id'] = membership_id resource = set_additional_parameters_to_false(resource) resource = fill_min_max_fields_if_not_given(resource) validate(resource) await self.db.user_types.insert_one(resource) resource['_id'] = str(resource['_id']) await event_service.on_event((Event( **{ 'document': resource, 'prior': {}, 'utilizer': utilizer, 'type': 'UserTypeCreatedEvent', 'membership_id': utilizer['membership_id'], 'sys': { 'created_at': datetime.datetime.utcnow(), 'created_by': utilizer.get('username', utilizer.get( 'name')) } }))) return resource
async def delete_user(self, resource_id, utilizer, event_service): if str(utilizer['_id']) == resource_id: raise ErtisError(err_code="errors.userCannotDeleteHerself", err_msg="User can not delete herself", status_code=400) user = await self._find_user(resource_id, utilizer["membership_id"]) user['_id'] = str(user['_id']) await self._remove_user(resource_id, utilizer['membership_id']) await event_service.on_event((Event( **{ 'document': {}, 'prior': user, 'utilizer': utilizer, 'type': 'UserDeletedEvent', 'membership_id': utilizer['membership_id'], 'sys': { 'created_at': datetime.datetime.utcnow(), 'created_by': utilizer.get('username', utilizer.get( 'name')) } })))
async def update_application(self, application_id, data, utilizer, event_service): resource = await self._find_application(application_id, utilizer['membership_id']) provided_body = pop_non_updatable_fields(data) _resource = self._check_identicality(resource, provided_body) resource['sys'].update({ 'modified_at': datetime.datetime.utcnow(), 'modified_by': utilizer.get('username', utilizer.get('name')) }) provided_body['sys'] = resource['sys'] updated_application = await self._update_application_with_body( application_id, utilizer['membership_id'], provided_body) _resource['_id'] = str(_resource['_id']) updated_application['_id'] = str(updated_application['_id']) await event_service.on_event((Event( **{ 'document': updated_application, 'prior': _resource, 'utilizer': utilizer, 'type': 'ApplicationUpdatedEvent', 'membership_id': utilizer['membership_id'], 'sys': { 'created_at': datetime.datetime.utcnow(), 'created_by': utilizer.get('username', utilizer.get( 'name')) } }))) return updated_application