From 9597966bcd78243c56e56a9b1e364a6f6e28d7e5 Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Fri, 14 Dec 2018 10:03:41 -0500 Subject: [PATCH] Update function to determine when invite can be resent and added lots of tests --- atst/models/invitation.py | 5 +- atst/models/workspace_role.py | 13 ++- tests/domain/test_workspaces.py | 10 +- tests/routes/workspaces/test_members.py | 124 ++++++++++++++++++++---- 4 files changed, 127 insertions(+), 25 deletions(-) diff --git a/atst/models/invitation.py b/atst/models/invitation.py index 0b7d6686..6d471734 100644 --- a/atst/models/invitation.py +++ b/atst/models/invitation.py @@ -77,7 +77,10 @@ class Invitation(Base, TimestampsMixin, AuditableMixin): @property def is_expired(self): - return datetime.datetime.now(self.expiration_time.tzinfo) > self.expiration_time + return ( + datetime.datetime.now(self.expiration_time.tzinfo) > self.expiration_time + and not self.status == Status.ACCEPTED + ) @property def workspace(self): diff --git a/atst/models/workspace_role.py b/atst/models/workspace_role.py index 692cafbb..7a01dce9 100644 --- a/atst/models/workspace_role.py +++ b/atst/models/workspace_role.py @@ -117,6 +117,10 @@ class WorkspaceRole(Base, mixins.TimestampsMixin, mixins.AuditableMixin): def role_displayname(self): return self.role.display_name + @property + def is_active(self): + return self.status == Status.ACTIVE + @property def num_environment_roles(self): return ( @@ -147,8 +151,13 @@ class WorkspaceRole(Base, mixins.TimestampsMixin, mixins.AuditableMixin): @property def can_resend_invitation(self): - return self.latest_invitation and ( - self.latest_invitation.is_rejected or self.latest_invitation.is_expired + return not self.is_active and ( + self.latest_invitation + and ( + self.latest_invitation.is_rejected + or self.latest_invitation.is_expired + or self.latest_invitation.is_revoked + ) ) diff --git a/tests/domain/test_workspaces.py b/tests/domain/test_workspaces.py index 63b408d9..a039a19a 100644 --- a/tests/domain/test_workspaces.py +++ b/tests/domain/test_workspaces.py @@ -304,9 +304,11 @@ def test_can_create_workspaces_with_matching_names(): Workspaces.create(RequestFactory.create(), name=workspace_name) -def test_can_revoke_workspace_access(): +def test_can_revoke_workspace_access_for_active_member(): workspace = WorkspaceFactory.create() - workspace_role = WorkspaceRoleFactory.create(workspace=workspace) + workspace_role = WorkspaceRoleFactory.create( + workspace=workspace, status=WorkspaceRoleStatus.ACTIVE + ) Workspaces.revoke_access(workspace.owner, workspace.id, workspace_role.id) assert Workspaces.for_user(workspace_role.user) == [] @@ -314,7 +316,9 @@ def test_can_revoke_workspace_access(): def test_can_revoke_access(): workspace = WorkspaceFactory.create() owner_role = workspace.roles[0] - workspace_role = WorkspaceRoleFactory.create(workspace=workspace) + workspace_role = WorkspaceRoleFactory.create( + workspace=workspace, status=WorkspaceRoleStatus.ACTIVE + ) assert Workspaces.can_revoke_access_for(workspace, workspace_role) assert not Workspaces.can_revoke_access_for(workspace, owner_role) diff --git a/tests/routes/workspaces/test_members.py b/tests/routes/workspaces/test_members.py index 44a63879..2b58665c 100644 --- a/tests/routes/workspaces/test_members.py +++ b/tests/routes/workspaces/test_members.py @@ -1,12 +1,19 @@ from flask import url_for -from tests.factories import UserFactory, WorkspaceFactory, WorkspaceRoleFactory +from tests.factories import ( + UserFactory, + WorkspaceFactory, + WorkspaceRoleFactory, + InvitationFactory, +) from atst.domain.workspaces import Workspaces from atst.domain.workspace_roles import WorkspaceRoles from atst.domain.projects import Projects from atst.domain.environments import Environments from atst.domain.environment_roles import EnvironmentRoles from atst.queue import queue +from atst.models.workspace_role import Status as WorkspaceRoleStatus +from atst.models.invitation import Status as InvitationStatus def test_user_with_permission_has_add_member_link(client, user_session): @@ -174,10 +181,12 @@ def test_update_member_environment_role_with_no_data(client, user_session): assert EnvironmentRoles.get(user.id, env1_id).role == "developer" -def test_revoke_member_access(client, user_session): +def test_revoke_active_member_access(client, user_session): workspace = WorkspaceFactory.create() user = UserFactory.create() - member = WorkspaceRoles.add(user, workspace.id, "developer") + member = WorkspaceRoleFactory.create( + workspace=workspace, user=user, status=WorkspaceRoleStatus.ACTIVE + ) Projects.create( workspace.owner, workspace, @@ -195,22 +204,7 @@ def test_revoke_member_access(client, user_session): assert WorkspaceRoles.get_by_id(member.id).num_environment_roles == 0 -def test_shows_revoke_button(client, user_session): - workspace = WorkspaceFactory.create() - user = UserFactory.create() - member = WorkspaceRoleFactory.create(user=user, workspace=workspace) - user_session(workspace.owner) - response = client.get( - url_for( - "workspaces.view_member", - workspace_id=workspace.id, - member_id=member.user.id, - ) - ) - assert "Remove Workspace Access" in response.data.decode() - - -def test_does_not_show_revoke_button(client, user_session): +def test_does_not_show_any_buttons_if_owner(client, user_session): workspace = WorkspaceFactory.create() user_session(workspace.owner) response = client.get( @@ -221,3 +215,95 @@ def test_does_not_show_revoke_button(client, user_session): ) ) assert "Remove Workspace Access" not in response.data.decode() + assert "Resend Invitation" not in response.data.decode() + assert "Revoke Invitation" not in response.data.decode() + + +def test_only_shows_revoke_access_button_if_active(client, user_session): + workspace = WorkspaceFactory.create() + user = UserFactory.create() + member = WorkspaceRoleFactory.create( + user=user, workspace=workspace, status=WorkspaceRoleStatus.ACTIVE + ) + InvitationFactory.create( + user=workspace.owner, + workspace_role=member, + email=member.user.email, + status=InvitationStatus.ACCEPTED, + ) + user_session(workspace.owner) + response = client.get( + url_for( + "workspaces.view_member", + workspace_id=workspace.id, + member_id=member.user.id, + ) + ) + assert "Remove Workspace Access" in response.data.decode() + assert "Revoke Invitation" not in response.data.decode() + assert "Resend Invitation" not in response.data.decode() + + +def test_only_shows_revoke_invite_button_if_pending(client, user_session): + workspace = WorkspaceFactory.create() + member = WorkspaceRoleFactory.create( + workspace=workspace, status=WorkspaceRoleStatus.PENDING + ) + InvitationFactory.create( + user=workspace.owner, workspace_role=member, email=member.user.email + ) + user_session(workspace.owner) + response = client.get( + url_for( + "workspaces.view_member", + workspace_id=workspace.id, + member_id=member.user.id, + ) + ) + assert "Revoke Invitation" in response.data.decode() + assert "Remove Workspace Access" not in response.data.decode() + assert "Resend Invitation" not in response.data.decode() + + +def test_only_shows_resend_button_if_expired(client, user_session): + workspace = WorkspaceFactory.create() + member = WorkspaceRoleFactory.create(workspace=workspace) + InvitationFactory.create( + user=workspace.owner, + workspace_role=member, + email=member.user.email, + status=InvitationStatus.REJECTED_EXPIRED, + ) + user_session(workspace.owner) + response = client.get( + url_for( + "workspaces.view_member", + workspace_id=workspace.id, + member_id=member.user.id, + ) + ) + assert "Resend Invitation" in response.data.decode() + assert "Revoke Invitation" not in response.data.decode() + assert "Remove Workspace Access" not in response.data.decode() + + +def test_only_shows_resend_button_if_revoked(client, user_session): + workspace = WorkspaceFactory.create() + member = WorkspaceRoleFactory.create(workspace=workspace) + InvitationFactory.create( + user=workspace.owner, + workspace_role=member, + email=member.user.email, + status=InvitationStatus.REVOKED, + ) + user_session(workspace.owner) + response = client.get( + url_for( + "workspaces.view_member", + workspace_id=workspace.id, + member_id=member.user.id, + ) + ) + assert "Resend Invitation" in response.data.decode() + assert "Remove Workspace Access" not in response.data.decode() + assert "Revoke Invitation" not in response.data.decode()