from datetime import datetime from apiserver import database from apiserver.apierrors import errors from apiserver.apimodels.auth import GetTokenResponse, CreateUserRequest, Credentials as CredModel from apiserver.apimodels.users import CreateRequest as Users_CreateRequest from apiserver.bll.user import UserBLL from apiserver.config import config from apiserver.config.info import get_version, get_build_number from apiserver.database.errors import translate_errors_context from apiserver.database.model.auth import User, Role, Credentials from apiserver.database.model.company import Company from apiserver.service_repo import APICall, ServiceRepo from apiserver.service_repo.auth import Identity, Token, get_client_id, get_secret_key log = config.logger("AuthBLL") class AuthBLL: @staticmethod def get_token_for_user( user_id: str, company_id: str = None, expiration_sec: int = None, entities: dict = None, ) -> GetTokenResponse: with translate_errors_context(): query = dict(id=user_id) if company_id: query.update(company=company_id) user = User.objects(**query).first() if not user: raise errors.bad_request.InvalidUserId(**query) company_id = company_id or user.company company = Company.objects(id=company_id).only("id", "name").first() if not company: raise errors.bad_request.InvalidId( "invalid company associated with user", company=company ) identity = Identity( user=user_id, company=company_id, role=user.role, user_name=user.name, company_name=company.name, ) token = Token.create_encoded_token( identity=identity, entities=entities, expiration_sec=expiration_sec, api_version=str(ServiceRepo.max_endpoint_version()), server_version=str(get_version()), server_build=str(get_build_number()), ) return GetTokenResponse(token=token.decode("ascii")) @staticmethod def create_user(request: CreateUserRequest, call: APICall = None) -> str: """ Create a new user in both the auth database and the backend database :param request: New user details :param call: API call that triggered this call. If not None, new backend user creation will be performed using a new call in the same transaction. :return: The new user's ID """ with translate_errors_context(): if not Company.objects(id=request.company).only("id"): raise errors.bad_request.InvalidId(company=request.company) user = User( id=database.utils.id(), name=request.name, company=request.company, role=request.role or Role.user, email=request.email, created=datetime.utcnow(), ) user.save() users_create_request = Users_CreateRequest( id=user.id, name=request.name, company=request.company, family_name=request.family_name, given_name=request.given_name, avatar=request.avatar, ) try: UserBLL.create(users_create_request) except Exception as ex: user.delete() raise errors.server_error.GeneralError( "failed adding new user", ex=str(ex) ) return user.id @staticmethod def delete_user( identity: Identity, user_id: str, company_id: str = None, call: APICall = None ): """ Delete an existing user from both the auth database and the backend database :param identity: Calling user identity :param user_id: ID of user to delete :param company_id: Company of user to delete :param call: API call that triggered this call. If not None, backend user deletion will be performed using a new call in the same transaction. """ if user_id == identity.user: raise errors.bad_request.FieldsValueError( "cannot delete yourself", user=user_id ) if not company_id: company_id = identity.company if ( identity.role not in Role.get_system_roles() and company_id != identity.company ): raise errors.bad_request.FieldsNotAllowedForRole( "must be empty or your own company", role=identity.role, field="company" ) with translate_errors_context(): query = dict(id=user_id, company=company_id) res = User.objects(**query).delete() if not res: raise errors.bad_request.InvalidUserId(**query) try: UserBLL.delete(user_id) except Exception as ex: log.error(f"Exception calling users.delete: {str(ex)}") @classmethod def create_credentials( cls, user_id: str, company_id: str, role: str = None ) -> CredModel: with translate_errors_context(): query = dict(id=user_id, company=company_id) user = User.objects(**query).first() if not user: raise errors.bad_request.InvalidUserId(**query) cred = CredModel(access_key=get_client_id(), secret_key=get_secret_key()) user.credentials.append( Credentials(key=cred.access_key, secret=cred.secret_key) ) user.save() return cred