Merge pull request #440 from dod-ccpo/resend-invitation
Resend a workspace invitation
This commit is contained in:
commit
1b4d054d7e
@ -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
|
||||||
|
|
||||||
@ -52,11 +54,11 @@ class Invitations(object):
|
|||||||
return invite
|
return invite
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, workspace_role, inviter, user):
|
def create(cls, inviter, workspace_role):
|
||||||
invite = Invitation(
|
invite = Invitation(
|
||||||
workspace_role=workspace_role,
|
workspace_role=workspace_role,
|
||||||
inviter=inviter,
|
inviter=inviter,
|
||||||
user=user,
|
user=workspace_role.user,
|
||||||
status=InvitationStatus.PENDING,
|
status=InvitationStatus.PENDING,
|
||||||
expiration_time=Invitations.current_expiration_time(),
|
expiration_time=Invitations.current_expiration_time(),
|
||||||
)
|
)
|
||||||
@ -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)
|
||||||
|
@ -81,3 +81,11 @@ class Invitation(Base, TimestampsMixin, AuditableMixin):
|
|||||||
def workspace(self):
|
def workspace(self):
|
||||||
if self.workspace_role:
|
if self.workspace_role:
|
||||||
return self.workspace_role.workspace
|
return self.workspace_role.workspace
|
||||||
|
|
||||||
|
@property
|
||||||
|
def user_email(self):
|
||||||
|
return self.workspace_role.user.email
|
||||||
|
|
||||||
|
@property
|
||||||
|
def user_name(self):
|
||||||
|
return self.workspace_role.user.full_name
|
||||||
|
@ -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",
|
||||||
|
@ -7,10 +7,13 @@ from flask import (
|
|||||||
url_for,
|
url_for,
|
||||||
current_app as app,
|
current_app as app,
|
||||||
)
|
)
|
||||||
|
import pendulum
|
||||||
|
|
||||||
from . import redirect_after_login_url
|
from . import redirect_after_login_url
|
||||||
from atst.domain.users import Users
|
from atst.domain.users import Users
|
||||||
from atst.queue import queue
|
from atst.queue import queue
|
||||||
|
from tests.factories import random_service_branch
|
||||||
|
from atst.utils import pick
|
||||||
|
|
||||||
bp = Blueprint("dev", __name__)
|
bp = Blueprint("dev", __name__)
|
||||||
|
|
||||||
@ -21,6 +24,11 @@ _DEV_USERS = {
|
|||||||
"last_name": "Stevenson",
|
"last_name": "Stevenson",
|
||||||
"atat_role_name": "ccpo",
|
"atat_role_name": "ccpo",
|
||||||
"email": "sam@example.com",
|
"email": "sam@example.com",
|
||||||
|
"service_branch": random_service_branch(),
|
||||||
|
"phone_number": "1234567890",
|
||||||
|
"citizenship": "United States",
|
||||||
|
"designation": "Military",
|
||||||
|
"date_latest_training": pendulum.date(2018, 1, 1),
|
||||||
},
|
},
|
||||||
"amanda": {
|
"amanda": {
|
||||||
"dod_id": "2345678901",
|
"dod_id": "2345678901",
|
||||||
@ -28,6 +36,11 @@ _DEV_USERS = {
|
|||||||
"last_name": "Adamson",
|
"last_name": "Adamson",
|
||||||
"atat_role_name": "default",
|
"atat_role_name": "default",
|
||||||
"email": "amanda@example.com",
|
"email": "amanda@example.com",
|
||||||
|
"service_branch": random_service_branch(),
|
||||||
|
"phone_number": "1234567890",
|
||||||
|
"citizenship": "United States",
|
||||||
|
"designation": "Military",
|
||||||
|
"date_latest_training": pendulum.date(2018, 1, 1),
|
||||||
},
|
},
|
||||||
"brandon": {
|
"brandon": {
|
||||||
"dod_id": "3456789012",
|
"dod_id": "3456789012",
|
||||||
@ -35,6 +48,11 @@ _DEV_USERS = {
|
|||||||
"last_name": "Buchannan",
|
"last_name": "Buchannan",
|
||||||
"atat_role_name": "default",
|
"atat_role_name": "default",
|
||||||
"email": "brandon@example.com",
|
"email": "brandon@example.com",
|
||||||
|
"service_branch": random_service_branch(),
|
||||||
|
"phone_number": "1234567890",
|
||||||
|
"citizenship": "United States",
|
||||||
|
"designation": "Military",
|
||||||
|
"date_latest_training": pendulum.date(2018, 1, 1),
|
||||||
},
|
},
|
||||||
"christina": {
|
"christina": {
|
||||||
"dod_id": "4567890123",
|
"dod_id": "4567890123",
|
||||||
@ -42,6 +60,11 @@ _DEV_USERS = {
|
|||||||
"last_name": "Collins",
|
"last_name": "Collins",
|
||||||
"atat_role_name": "default",
|
"atat_role_name": "default",
|
||||||
"email": "christina@example.com",
|
"email": "christina@example.com",
|
||||||
|
"service_branch": random_service_branch(),
|
||||||
|
"phone_number": "1234567890",
|
||||||
|
"citizenship": "United States",
|
||||||
|
"designation": "Military",
|
||||||
|
"date_latest_training": pendulum.date(2018, 1, 1),
|
||||||
},
|
},
|
||||||
"dominick": {
|
"dominick": {
|
||||||
"dod_id": "5678901234",
|
"dod_id": "5678901234",
|
||||||
@ -49,6 +72,11 @@ _DEV_USERS = {
|
|||||||
"last_name": "Domingo",
|
"last_name": "Domingo",
|
||||||
"atat_role_name": "default",
|
"atat_role_name": "default",
|
||||||
"email": "dominick@example.com",
|
"email": "dominick@example.com",
|
||||||
|
"service_branch": random_service_branch(),
|
||||||
|
"phone_number": "1234567890",
|
||||||
|
"citizenship": "United States",
|
||||||
|
"designation": "Military",
|
||||||
|
"date_latest_training": pendulum.date(2018, 1, 1),
|
||||||
},
|
},
|
||||||
"erica": {
|
"erica": {
|
||||||
"dod_id": "6789012345",
|
"dod_id": "6789012345",
|
||||||
@ -56,6 +84,11 @@ _DEV_USERS = {
|
|||||||
"last_name": "Eichner",
|
"last_name": "Eichner",
|
||||||
"atat_role_name": "default",
|
"atat_role_name": "default",
|
||||||
"email": "erica@example.com",
|
"email": "erica@example.com",
|
||||||
|
"service_branch": random_service_branch(),
|
||||||
|
"phone_number": "1234567890",
|
||||||
|
"citizenship": "United States",
|
||||||
|
"designation": "Military",
|
||||||
|
"date_latest_training": pendulum.date(2018, 1, 1),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,10 +99,20 @@ def login_dev():
|
|||||||
user_data = _DEV_USERS[role]
|
user_data = _DEV_USERS[role]
|
||||||
user = Users.get_or_create_by_dod_id(
|
user = Users.get_or_create_by_dod_id(
|
||||||
user_data["dod_id"],
|
user_data["dod_id"],
|
||||||
atat_role_name=user_data["atat_role_name"],
|
**pick(
|
||||||
first_name=user_data["first_name"],
|
[
|
||||||
last_name=user_data["last_name"],
|
"atat_role_name",
|
||||||
email=user_data["email"],
|
"first_name",
|
||||||
|
"last_name",
|
||||||
|
"email",
|
||||||
|
"service_branch",
|
||||||
|
"phone_number",
|
||||||
|
"citizenship",
|
||||||
|
"designation",
|
||||||
|
"date_latest_training",
|
||||||
|
],
|
||||||
|
user_data,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
session["user_id"] = user.id
|
session["user_id"] = user.id
|
||||||
|
|
||||||
|
@ -103,6 +103,7 @@ def show_workspace(workspace_id):
|
|||||||
def workspace_members(workspace_id):
|
def workspace_members(workspace_id):
|
||||||
workspace = Workspaces.get_with_members(g.current_user, workspace_id)
|
workspace = Workspaces.get_with_members(g.current_user, workspace_id)
|
||||||
new_member_name = http_request.args.get("newMemberName")
|
new_member_name = http_request.args.get("newMemberName")
|
||||||
|
resent_invitation_to = http_request.args.get("resentInvitationTo")
|
||||||
new_member = next(
|
new_member = next(
|
||||||
filter(lambda m: m.user_name == new_member_name, workspace.members), None
|
filter(lambda m: m.user_name == new_member_name, workspace.members), None
|
||||||
)
|
)
|
||||||
@ -127,6 +128,7 @@ def workspace_members(workspace_id):
|
|||||||
status_choices=MEMBER_STATUSES,
|
status_choices=MEMBER_STATUSES,
|
||||||
members=members_list,
|
members=members_list,
|
||||||
new_member=new_member,
|
new_member=new_member,
|
||||||
|
resent_invitation_to=resent_invitation_to,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -255,11 +257,12 @@ def send_invite_email(owner_name, token, new_member_email):
|
|||||||
def create_member(workspace_id):
|
def create_member(workspace_id):
|
||||||
workspace = Workspaces.get(g.current_user, workspace_id)
|
workspace = Workspaces.get(g.current_user, workspace_id)
|
||||||
form = NewMemberForm(http_request.form)
|
form = NewMemberForm(http_request.form)
|
||||||
|
user = g.current_user
|
||||||
|
|
||||||
if form.validate():
|
if form.validate():
|
||||||
try:
|
try:
|
||||||
new_member = Workspaces.create_member(g.current_user, workspace, form.data)
|
new_member = Workspaces.create_member(user, workspace, form.data)
|
||||||
invite = Invitations.create(new_member, g.current_user, new_member.user)
|
invite = Invitations.create(user, new_member)
|
||||||
send_invite_email(
|
send_invite_email(
|
||||||
g.current_user.full_name, invite.token, new_member.user.email
|
g.current_user.full_name, invite.token, new_member.user.email
|
||||||
)
|
)
|
||||||
@ -373,3 +376,16 @@ 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):
|
||||||
|
invite = Invitations.resend(g.current_user, workspace_id, token)
|
||||||
|
send_invite_email(g.current_user.full_name, invite.token, invite.user_email)
|
||||||
|
return redirect(
|
||||||
|
url_for(
|
||||||
|
"workspaces.workspace_members",
|
||||||
|
workspace_id=workspace_id,
|
||||||
|
resentInvitationTo=invite.user_name,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
@ -12,8 +12,9 @@ from atst.domain.requests import Requests
|
|||||||
from atst.domain.workspaces import Workspaces
|
from atst.domain.workspaces import Workspaces
|
||||||
from atst.domain.projects import Projects
|
from atst.domain.projects import Projects
|
||||||
from atst.domain.workspace_roles import WorkspaceRoles
|
from atst.domain.workspace_roles import WorkspaceRoles
|
||||||
|
from atst.models.invitation import Status as InvitationStatus
|
||||||
from atst.domain.exceptions import AlreadyExistsError
|
from atst.domain.exceptions import AlreadyExistsError
|
||||||
from tests.factories import RequestFactory, TaskOrderFactory
|
from tests.factories import RequestFactory, TaskOrderFactory, InvitationFactory
|
||||||
from atst.routes.dev import _DEV_USERS as DEV_USERS
|
from atst.routes.dev import _DEV_USERS as DEV_USERS
|
||||||
|
|
||||||
WORKSPACE_USERS = [
|
WORKSPACE_USERS = [
|
||||||
@ -40,6 +41,41 @@ WORKSPACE_USERS = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
WORKSPACE_INVITED_USERS = [
|
||||||
|
{
|
||||||
|
"first_name": "Frederick",
|
||||||
|
"last_name": "Fitzgerald",
|
||||||
|
"email": "frederick@mil.gov",
|
||||||
|
"workspace_role": "developer",
|
||||||
|
"dod_id": "0000000004",
|
||||||
|
"status": InvitationStatus.REJECTED_WRONG_USER
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"first_name": "Gina",
|
||||||
|
"last_name": "Guzman",
|
||||||
|
"email": "gina@mil.gov",
|
||||||
|
"workspace_role": "developer",
|
||||||
|
"dod_id": "0000000005",
|
||||||
|
"status": InvitationStatus.REJECTED_EXPIRED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"first_name": "Hector",
|
||||||
|
"last_name": "Harper",
|
||||||
|
"email": "hector@mil.gov",
|
||||||
|
"workspace_role": "developer",
|
||||||
|
"dod_id": "0000000006",
|
||||||
|
"status": InvitationStatus.REVOKED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"first_name": "Isabella",
|
||||||
|
"last_name": "Ingram",
|
||||||
|
"email": "isabella@mil.gov",
|
||||||
|
"workspace_role": "developer",
|
||||||
|
"dod_id": "0000000007",
|
||||||
|
"status": InvitationStatus.PENDING
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def seed_db():
|
def seed_db():
|
||||||
users = []
|
users = []
|
||||||
@ -78,6 +114,13 @@ def seed_db():
|
|||||||
ws_role = Workspaces.create_member(user, workspace, workspace_role)
|
ws_role = Workspaces.create_member(user, workspace, workspace_role)
|
||||||
WorkspaceRoles.enable(ws_role)
|
WorkspaceRoles.enable(ws_role)
|
||||||
|
|
||||||
|
for workspace_role in WORKSPACE_INVITED_USERS:
|
||||||
|
ws_role = Workspaces.create_member(user, workspace, workspace_role)
|
||||||
|
invitation = InvitationFactory.build(workspace_role=ws_role, status=workspace_role["status"])
|
||||||
|
db.session.add(invitation)
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
Projects.create(
|
Projects.create(
|
||||||
user,
|
user,
|
||||||
workspace=workspace,
|
workspace=workspace,
|
||||||
|
@ -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 send an email to invite the user to join this workspace."
|
||||||
|
)}}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -33,6 +33,17 @@
|
|||||||
) }}
|
) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if resent_invitation_to %}
|
||||||
|
{% set message -%}
|
||||||
|
<p>Successfully sent a new invitation to {{ resent_invitation_to }}.</p>
|
||||||
|
{%- endset %}
|
||||||
|
|
||||||
|
{{ Alert('Invitation resent',
|
||||||
|
message=message,
|
||||||
|
level='success'
|
||||||
|
) }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% set member_name = request.args.get("memberName") %}
|
{% set member_name = request.args.get("memberName") %}
|
||||||
{% set updated_role = request.args.get("updatedRole") %}
|
{% set updated_role = request.args.get("updatedRole") %}
|
||||||
{% if updated_role %}
|
{% if updated_role %}
|
||||||
|
@ -22,7 +22,7 @@ def test_create_invitation():
|
|||||||
workspace = WorkspaceFactory.create()
|
workspace = WorkspaceFactory.create()
|
||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
ws_role = WorkspaceRoleFactory.create(user=user, workspace=workspace)
|
ws_role = WorkspaceRoleFactory.create(user=user, workspace=workspace)
|
||||||
invite = Invitations.create(ws_role, workspace.owner, user)
|
invite = Invitations.create(workspace.owner, ws_role)
|
||||||
assert invite.user == user
|
assert invite.user == user
|
||||||
assert invite.workspace_role == ws_role
|
assert invite.workspace_role == ws_role
|
||||||
assert invite.inviter == workspace.owner
|
assert invite.inviter == workspace.owner
|
||||||
@ -34,7 +34,7 @@ def test_accept_invitation():
|
|||||||
workspace = WorkspaceFactory.create()
|
workspace = WorkspaceFactory.create()
|
||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
ws_role = WorkspaceRoleFactory.create(user=user, workspace=workspace)
|
ws_role = WorkspaceRoleFactory.create(user=user, workspace=workspace)
|
||||||
invite = Invitations.create(ws_role, workspace.owner, user)
|
invite = Invitations.create(workspace.owner, ws_role)
|
||||||
assert invite.is_pending
|
assert invite.is_pending
|
||||||
accepted_invite = Invitations.accept(user, invite.token)
|
accepted_invite = Invitations.accept(user, invite.token)
|
||||||
assert accepted_invite.is_accepted
|
assert accepted_invite.is_accepted
|
||||||
@ -89,7 +89,7 @@ def test_accept_invitation_twice():
|
|||||||
workspace = WorkspaceFactory.create()
|
workspace = WorkspaceFactory.create()
|
||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
ws_role = WorkspaceRoleFactory.create(user=user, workspace=workspace)
|
ws_role = WorkspaceRoleFactory.create(user=user, workspace=workspace)
|
||||||
invite = Invitations.create(ws_role, workspace.owner, user)
|
invite = Invitations.create(workspace.owner, ws_role)
|
||||||
Invitations.accept(user, invite.token)
|
Invitations.accept(user, invite.token)
|
||||||
with pytest.raises(InvitationError):
|
with pytest.raises(InvitationError):
|
||||||
Invitations.accept(user, invite.token)
|
Invitations.accept(user, invite.token)
|
||||||
@ -99,7 +99,17 @@ def test_revoke_invitation():
|
|||||||
workspace = WorkspaceFactory.create()
|
workspace = WorkspaceFactory.create()
|
||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
ws_role = WorkspaceRoleFactory.create(user=user, workspace=workspace)
|
ws_role = WorkspaceRoleFactory.create(user=user, workspace=workspace)
|
||||||
invite = Invitations.create(ws_role, workspace.owner, user)
|
invite = Invitations.create(workspace.owner, ws_role)
|
||||||
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
|
||||||
|
@ -21,7 +21,6 @@ from atst.domain.roles import Roles
|
|||||||
from atst.models.workspace_role import WorkspaceRole, Status as WorkspaceRoleStatus
|
from atst.models.workspace_role import WorkspaceRole, Status as WorkspaceRoleStatus
|
||||||
from atst.models.environment_role import EnvironmentRole
|
from atst.models.environment_role import EnvironmentRole
|
||||||
from atst.models.invitation import Invitation, Status as InvitationStatus
|
from atst.models.invitation import Invitation, Status as InvitationStatus
|
||||||
from atst.domain.workspaces import Workspaces
|
|
||||||
from atst.domain.invitations import Invitations
|
from atst.domain.invitations import Invitations
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -457,3 +457,24 @@ def test_revoke_invitation(client, user_session):
|
|||||||
|
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
assert invite.is_revoked
|
assert invite.is_revoked
|
||||||
|
|
||||||
|
|
||||||
|
def test_resend_invitation_sends_email(client, user_session, queue):
|
||||||
|
user = UserFactory.create()
|
||||||
|
workspace = WorkspaceFactory.create()
|
||||||
|
ws_role = WorkspaceRoleFactory.create(
|
||||||
|
user=user, workspace=workspace, status=WorkspaceRoleStatus.PENDING
|
||||||
|
)
|
||||||
|
invite = InvitationFactory.create(
|
||||||
|
user_id=user.id, workspace_role_id=ws_role.id, status=InvitationStatus.PENDING
|
||||||
|
)
|
||||||
|
user_session(workspace.owner)
|
||||||
|
client.post(
|
||||||
|
url_for(
|
||||||
|
"workspaces.resend_invitation",
|
||||||
|
workspace_id=workspace.id,
|
||||||
|
token=invite.token,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(queue.get_queue()) == 1
|
||||||
|
Loading…
x
Reference in New Issue
Block a user