From 4a7ecffc089a51b027aa0415bd13450a45bd60ce Mon Sep 17 00:00:00 2001 From: kevgliss Date: Tue, 1 Jun 2021 10:58:48 -0700 Subject: [PATCH] Bugfix/role cli (#1243) * Switching from autocomplete component to combobox component * Fixing UI and CLI for updating user roles --- src/dispatch/auth/models.py | 3 + src/dispatch/auth/service.py | 76 ++++++++++++++++++++ src/dispatch/cli.py | 14 +++- src/dispatch/static/dispatch/src/auth/api.js | 2 +- 4 files changed, 91 insertions(+), 4 deletions(-) diff --git a/src/dispatch/auth/models.py b/src/dispatch/auth/models.py index 4c6af11dc461..23711c2b650d 100644 --- a/src/dispatch/auth/models.py +++ b/src/dispatch/auth/models.py @@ -150,6 +150,9 @@ class UserUpdate(DispatchBase): id: int password: Optional[str] + projects: Optional[List[UserProject]] + organization: Optional[List[UserOrganization]] + @validator("password", pre=True, always=True) def hash(cls, v): return hash_password(str(v)) diff --git a/src/dispatch/auth/service.py b/src/dispatch/auth/service.py index 0c320d2d199f..cf83ad94ac4a 100644 --- a/src/dispatch/auth/service.py +++ b/src/dispatch/auth/service.py @@ -30,6 +30,8 @@ DispatchUser, DispatchUserOrganization, DispatchUserProject, + UserOrganization, + UserProject, UserRegister, UserUpdate, ) @@ -51,6 +53,63 @@ def get_by_email(*, db_session, email: str) -> Optional[DispatchUser]: return db_session.query(DispatchUser).filter(DispatchUser.email == email).one_or_none() +def create_or_update_project_role(*, db_session, user: DispatchUser, role_in: UserProject): + """Creates a new project role or updates an existing role.""" + if not role_in.project.id: + project = project_service.get_by_name(db_session=db_session, name=role_in.project.name) + project_id = project.id + else: + project_id = role_in.project.id + + project_role = ( + db_session.query(DispatchUserProject) + .filter( + DispatchUserProject.dispatch_user_id == user.id, + ) + .filter(DispatchUserProject.project_id == project_id) + .one_or_none() + ) + + if not project_role: + return DispatchUserProject( + project_id=project_id, + role=role_in.role, + ) + project_role.role = role_in.role + return project_role + + +def create_or_update_organization_role( + *, db_session, user: DispatchUser, role_in: UserOrganization +): + """Creates a new organization role or updates an existing role.""" + if not role_in.organization.id: + organization = organization_service.get_by_name( + db_session=db_session, name=role_in.organization.name + ) + organization_id = organization.id + else: + organization_id = role_in.organization.id + + organization_role = ( + db_session.query(DispatchUserOrganization) + .filter( + DispatchUserOrganization.dispatch_user_id == user.id, + ) + .filter(DispatchUserOrganization.organization_id == organization_id) + .one_or_none() + ) + + if not organization_role: + return DispatchUserOrganization( + organization_id=organization.id, + role=role_in.role, + ) + + organization_role.role = role_in + return organization_role + + def create(*, db_session, user_in: UserRegister) -> DispatchUser: """Creates a new dispatch user.""" # pydantic forces a string password, but we really want bytes @@ -105,6 +164,23 @@ def update(*, db_session, user: DispatchUser, user_in: UserUpdate) -> DispatchUs if user_in.password: password = bytes(user_in.password, "utf-8") user.password = password + + if user_in.projects: + roles = [] + for role in user_in.projects: + roles.append( + create_or_update_project_role(db_session=db_session, user=user, role_in=role) + ) + user.projects = roles + + if user_in.organization: + roles = [] + for role in user_in.organizations: + roles.append( + create_or_update_organization_role(db_session=db_session, user=user, role_in=role) + ) + user.organizations = roles + db_session.add(user) db_session.commit() return user diff --git a/src/dispatch/cli.py b/src/dispatch/cli.py index e3de6dab1bda..b2acf553bff5 100644 --- a/src/dispatch/cli.py +++ b/src/dispatch/cli.py @@ -195,17 +195,22 @@ def dispatch_user(): @dispatch_user.command("update") @click.argument("email") +@click.option( + "--project", + "-p", + help="Project to assign the role.", +) @click.option( "--role", "-r", type=click.Choice(UserRoles), help="Role to be assigned to the user.", ) -def update_user(email: str, role: str): +def update_user(email: str, role: str, project: str): """Updates a user's roles.""" from dispatch.database.core import SessionLocal from dispatch.auth import service as user_service - from dispatch.auth.models import UserUpdate + from dispatch.auth.models import UserUpdate, UserProject db_session = SessionLocal() user = user_service.get_by_email(email=email, db_session=db_session) @@ -213,7 +218,10 @@ def update_user(email: str, role: str): click.secho(f"No user found. Email: {email}", fg="red") return - user_service.update(user=user, user_in=UserUpdate(id=user.id, role=role), db_session=db_session) + project = UserProject(role=role, project={"name": project}) + user_service.update( + user=user, user_in=UserUpdate(id=user.id, projects=[project]), db_session=db_session + ) click.secho("User successfully updated.", fg="green") diff --git a/src/dispatch/static/dispatch/src/auth/api.js b/src/dispatch/static/dispatch/src/auth/api.js index dd0a1c0ac53a..e1e376d1de1e 100644 --- a/src/dispatch/static/dispatch/src/auth/api.js +++ b/src/dispatch/static/dispatch/src/auth/api.js @@ -4,7 +4,7 @@ const resource = "users" export default { getAll(options) { - return API.get(`/${resource}/`, { params: { ...options } }) + return API.get(`/${resource}`, { params: { ...options } }) }, get(userId) { return API.get(`/${resource}/${userId}`)