diff --git a/atst/domain/workspace_users.py b/atst/domain/workspace_users.py index 940cf2a4..6fb761c3 100644 --- a/atst/domain/workspace_users.py +++ b/atst/domain/workspace_users.py @@ -33,6 +33,8 @@ class WorkspaceUsers(object): @classmethod def add(cls, user, workspace_id, role_name): role = Roles.get(role_name) + + new_workspace_role = None try: existing_workspace_role = ( db.session.query(WorkspaceRole) @@ -53,6 +55,8 @@ class WorkspaceUsers(object): db.session.add(user) db.session.commit() + return WorkspaceUser(user, new_workspace_role) + @classmethod def add_many(cls, workspace_id, workspace_user_dicts): workspace_users = [] diff --git a/atst/domain/workspaces.py b/atst/domain/workspaces.py index 6a513607..6570a831 100644 --- a/atst/domain/workspaces.py +++ b/atst/domain/workspaces.py @@ -7,6 +7,8 @@ from atst.domain.exceptions import NotFoundError, UnauthorizedError from atst.domain.roles import Roles from atst.domain.authz import Authorization from atst.models.permissions import Permissions +from atst.domain.users import Users +from atst.domain.workspace_users import WorkspaceUsers class Workspaces(object): @@ -61,6 +63,24 @@ class Workspaces(object): ) return workspaces + @classmethod + def create_member(cls, user, workspace, data): + if not Authorization.has_workspace_permission( + user, workspace, Permissions.ASSIGN_AND_UNASSIGN_ATAT_ROLE + ): + raise UnauthorizedError(user, "create workspace member") + + new_user = Users.get_or_create_by_dod_id( + data["dod_id"], + first_name=data["first_name"], + last_name=data["last_name"], + email=data["email"], + ) + workspace_user = WorkspaceUsers.add( + new_user, workspace.id, data["workspace_role"] + ) + return workspace_user + @classmethod def _create_workspace_role(cls, user, workspace, role_name): role = Roles.get(role_name) diff --git a/atst/forms/data.py b/atst/forms/data.py index 6a41c647..5c7f9b7a 100644 --- a/atst/forms/data.py +++ b/atst/forms/data.py @@ -106,27 +106,37 @@ COMPLETION_DATE_RANGES = [ WORKSPACE_ROLES = [ ( "owner", - "Workspace Owner", - "Can add, edit, deactivate access to all projects, environments, and members. Can view budget reports. Can start and edit JEDI Cloud requests.", + { + "name": "Workspace Owner", + "description": "Can add, edit, deactivate access to all projects, environments, and members. Can view budget reports. Can start and edit JEDI Cloud requests.", + }, ), ( "admin", - "Administrator", - "Can add and edit projects, environments, members, but cannot deactivate. Cannot view budget reports or JEDI Cloud requests.", + { + "name": "Administrator", + "description": "Can add and edit projects, environments, members, but cannot deactivate. Cannot view budget reports or JEDI Cloud requests.", + }, ), ( "developer", - "Developer", - "Can view only the projects and environments they are granted access to. Can also view members associated with each environment.", + { + "name": "Developer", + "description": "Can view only the projects and environments they are granted access to. Can also view members associated with each environment.", + }, ), ( "billing_auditor", - "Billing Auditor", - "Can view only the projects and environments they are granted access to. Can also view budgets and reports associated with the workspace.", + { + "name": "Billing Auditor", + "description": "Can view only the projects and environments they are granted access to. Can also view budgets and reports associated with the workspace.", + }, ), ( "security_auditor", - "Security Auditor", - "Can view only the projects and environments they are granted access to. Can also view activity logs.", + { + "name": "Security Auditor", + "description": "Can view only the projects and environments they are granted access to. Can also view activity logs.", + }, ), ] diff --git a/atst/models/workspace_user.py b/atst/models/workspace_user.py index 6faba2d6..5e3ee1ed 100644 --- a/atst/models/workspace_user.py +++ b/atst/models/workspace_user.py @@ -10,5 +10,9 @@ class WorkspaceUser(object): ) return set(workspace_permissions).union(atat_permissions) + @property + def workspace(self): + return self.workspace_role.workspace + def workspace_id(self): return self.workspace_role.workspace_id diff --git a/atst/routes/workspaces.py b/atst/routes/workspaces.py index fcc5f7ae..665d266c 100644 --- a/atst/routes/workspaces.py +++ b/atst/routes/workspaces.py @@ -101,3 +101,21 @@ def new_member(workspace_id): workspace = Workspaces.get(g.current_user, workspace_id) form = NewMemberForm() return render_template("member_new.html", workspace=workspace, form=form) + + +@bp.route("/workspaces//members/new", methods=["POST"]) +def create_member(workspace_id): + workspace = Workspaces.get(g.current_user, workspace_id) + form = NewMemberForm(http_request.form) + + if form.validate(): + new_member = Workspaces.create_member(g.current_user, workspace, form.data) + return redirect( + url_for( + "workspaces.workspace_members", + workspace_id=workspace.id, + newMemberName=new_member.user.full_name, + ) + ) + else: + return render_template("member_new.html", workspace=workspace, form=form) diff --git a/js/components/selector.js b/js/components/selector.js index b6c23023..15c60076 100644 --- a/js/components/selector.js +++ b/js/components/selector.js @@ -26,11 +26,14 @@ export default { computed: { label: function () { - return this.value - ? this.choices.find((choice) => { + if (this.value) { + const selectedChoice = this.choices.find((choice) => { return this.value === choice[0] })[1] - : this.defaultLabel + return selectedChoice.name + } else { + return this.defaultLabel + } } }, diff --git a/script/seed.py b/script/seed.py index 68df7b04..03bbbb5c 100644 --- a/script/seed.py +++ b/script/seed.py @@ -37,7 +37,8 @@ def seed_db(): Projects.create( workspace=workspace, name="First Project", - description="This is our first project." + description="This is our first project.", + environment_names=["dev", "staging", "prod"] ) diff --git a/templates/components/selector.html b/templates/components/selector.html index cfa44d0a..cb374286 100644 --- a/templates/components/selector.html +++ b/templates/components/selector.html @@ -44,13 +44,13 @@ v-bind:checked='value === choice[0]' v-on:change='change'/>