Resend a workspace member's invite
This commit is contained in:
parent
280f0162ed
commit
a725310535
@ -4,6 +4,8 @@ from sqlalchemy.orm.exc import NoResultFound
|
|||||||
from atst.database import db
|
from atst.database import db
|
||||||
from atst.models.invitation import Invitation, Status as InvitationStatus
|
from atst.models.invitation import Invitation, Status as InvitationStatus
|
||||||
from atst.domain.workspace_roles import WorkspaceRoles
|
from atst.domain.workspace_roles import WorkspaceRoles
|
||||||
|
from atst.domain.authz import Authorization, Permissions
|
||||||
|
from atst.domain.workspaces import Workspaces
|
||||||
|
|
||||||
from .exceptions import NotFoundError
|
from .exceptions import NotFoundError
|
||||||
|
|
||||||
@ -104,3 +106,18 @@ class Invitations(object):
|
|||||||
def revoke(cls, token):
|
def revoke(cls, token):
|
||||||
invite = Invitations._get(token)
|
invite = Invitations._get(token)
|
||||||
return Invitations._update_status(invite, InvitationStatus.REVOKED)
|
return Invitations._update_status(invite, InvitationStatus.REVOKED)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def resend(cls, user, workspace_id, token):
|
||||||
|
workspace = Workspaces.get(user, workspace_id)
|
||||||
|
Authorization.check_workspace_permission(
|
||||||
|
user,
|
||||||
|
workspace,
|
||||||
|
Permissions.ASSIGN_AND_UNASSIGN_ATAT_ROLE,
|
||||||
|
"resend a workspace invitation",
|
||||||
|
)
|
||||||
|
|
||||||
|
previous_invitation = Invitations._get(token)
|
||||||
|
Invitations._update_status(previous_invitation, InvitationStatus.REVOKED)
|
||||||
|
|
||||||
|
return Invitations.create(user, previous_invitation.workspace_role)
|
||||||
|
@ -109,6 +109,12 @@ class WorkspaceRole(Base, mixins.TimestampsMixin, mixins.AuditableMixin):
|
|||||||
def has_environment_roles(self):
|
def has_environment_roles(self):
|
||||||
return self.num_environment_roles > 0
|
return self.num_environment_roles > 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def can_resend_invitation(self):
|
||||||
|
return self.latest_invitation and (
|
||||||
|
self.latest_invitation.is_rejected or self.latest_invitation.is_expired
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
Index(
|
Index(
|
||||||
"workspace_role_user_workspace",
|
"workspace_role_user_workspace",
|
||||||
|
@ -374,3 +374,9 @@ def revoke_invitation(workspace_id, token):
|
|||||||
Invitations.revoke(token)
|
Invitations.revoke(token)
|
||||||
|
|
||||||
return redirect(url_for("workspaces.workspace_members", workspace_id=workspace.id))
|
return redirect(url_for("workspaces.workspace_members", workspace_id=workspace.id))
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/workspaces/<workspace_id>/invitations/<token>/resend", methods=["POST"])
|
||||||
|
def resend_invitation(workspace_id, token):
|
||||||
|
Invitations.resend(g.current_user, workspace_id, token)
|
||||||
|
return redirect(url_for("workspaces.workspace_members", workspace_id=workspace_id))
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
{% if editable %}
|
{% if editable %}
|
||||||
<a href='{{ url_for("users.user") }}' class='icon-link'>edit account details</a>
|
<a href='{{ url_for("users.user") }}' class='icon-link'>edit account details</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<div>
|
||||||
{% if member.latest_invitation.is_pending %}
|
{% if member.latest_invitation.is_pending %}
|
||||||
{{ ConfirmationButton(
|
{{ ConfirmationButton(
|
||||||
"Revoke Invitation",
|
"Revoke Invitation",
|
||||||
@ -46,6 +47,15 @@
|
|||||||
form.csrf_token
|
form.csrf_token
|
||||||
) }}
|
) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if member.can_resend_invitation %}
|
||||||
|
{{ ConfirmationButton (
|
||||||
|
"Resend Invitation",
|
||||||
|
url_for("workspaces.resend_invitation", workspace_id=workspace.id, token=member.latest_invitation.token),
|
||||||
|
form.csrf_token,
|
||||||
|
confirm_msg="Are you sure? This will invalidate the previously sent invitation."
|
||||||
|
)}}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -103,3 +103,13 @@ def test_revoke_invitation():
|
|||||||
assert invite.is_pending
|
assert invite.is_pending
|
||||||
Invitations.revoke(invite.token)
|
Invitations.revoke(invite.token)
|
||||||
assert invite.is_revoked
|
assert invite.is_revoked
|
||||||
|
|
||||||
|
|
||||||
|
def test_resend_invitation():
|
||||||
|
workspace = WorkspaceFactory.create()
|
||||||
|
user = UserFactory.create()
|
||||||
|
ws_role = WorkspaceRoleFactory.create(user=user, workspace=workspace)
|
||||||
|
invite = Invitations.create(workspace.owner, ws_role)
|
||||||
|
Invitations.resend(workspace.owner, workspace.id, invite.token)
|
||||||
|
assert ws_role.invitations[0].is_revoked
|
||||||
|
assert ws_role.invitations[1].is_pending
|
||||||
|
@ -96,3 +96,17 @@ def test_status_when_invitation_is_expired():
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
assert workspace_role.display_status == "Invite expired"
|
assert workspace_role.display_status == "Invite expired"
|
||||||
|
|
||||||
|
|
||||||
|
def test_can_not_resend_invitation_if_active():
|
||||||
|
workspace_role = WorkspaceRoleFactory.create(
|
||||||
|
invitations=[InvitationFactory.create(status=InvitationStatus.ACCEPTED)]
|
||||||
|
)
|
||||||
|
assert not workspace_role.can_resend_invitation
|
||||||
|
|
||||||
|
|
||||||
|
def test_can_resend_invitation_if_expired():
|
||||||
|
workspace_role = WorkspaceRoleFactory.create(
|
||||||
|
invitations=[InvitationFactory.create(status=InvitationStatus.REJECTED_EXPIRED)]
|
||||||
|
)
|
||||||
|
assert workspace_role.can_resend_invitation
|
||||||
|
Loading…
x
Reference in New Issue
Block a user