diff --git a/atst/models/invitation.py b/atst/models/invitation.py
index 6097361a..a6a2964d 100644
--- a/atst/models/invitation.py
+++ b/atst/models/invitation.py
@@ -87,3 +87,7 @@ class Invitation(Base, TimestampsMixin, AuditableMixin):
@property
def user_name(self):
return self.workspace_role.user.full_name
+
+ @property
+ def is_revokable(self):
+ return self.is_pending and not self.is_expired
diff --git a/templates/workspaces/members/edit.html b/templates/workspaces/members/edit.html
index 0b609e5b..f83149d3 100644
--- a/templates/workspaces/members/edit.html
+++ b/templates/workspaces/members/edit.html
@@ -40,7 +40,7 @@
edit account details
{% endif %}
- {% if member.latest_invitation.is_pending %}
+ {% if member.latest_invitation.is_revokable %}
{{ ConfirmationButton(
"Revoke Invitation",
url_for("workspaces.revoke_invitation", workspace_id=workspace.id, token=member.latest_invitation.token),
diff --git a/tests/models/test_invitation.py b/tests/models/test_invitation.py
new file mode 100644
index 00000000..44fb30fb
--- /dev/null
+++ b/tests/models/test_invitation.py
@@ -0,0 +1,23 @@
+import pytest
+import datetime
+
+from atst.models.invitation import Invitation, Status
+
+from tests.factories import InvitationFactory
+
+
+def test_expired_invite_is_not_revokable():
+ invite = InvitationFactory.create(
+ expiration_time=datetime.datetime.now() - datetime.timedelta(minutes=60)
+ )
+ assert not invite.is_revokable
+
+
+def test_unexpired_invite_is_revokable():
+ invite = InvitationFactory.create()
+ assert invite.is_revokable
+
+
+def test_invite_is_not_revokable_if_invite_is_not_pending():
+ invite = InvitationFactory.create(status=Status.ACCEPTED)
+ assert not invite.is_revokable