forked from rapidpro/rapidpro
-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add new invitations list and delete views
- Loading branch information
1 parent
d5541a4
commit c8fa8c2
Showing
7 changed files
with
168 additions
and
70 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -118,13 +118,7 @@ def test_group_perms_wrapper(self): | |
|
||
class InvitationTest(TembaTest): | ||
def test_model(self): | ||
invitation = Invitation.objects.create( | ||
org=self.org, | ||
user_group="E", | ||
email="[email protected]", | ||
created_by=self.admin, | ||
modified_by=self.admin, | ||
) | ||
invitation = Invitation.create(self.org, self.admin, "[email protected]", OrgRole.EDITOR) | ||
|
||
self.assertEqual(OrgRole.EDITOR, invitation.role) | ||
|
||
|
@@ -1561,12 +1555,8 @@ def test_manage_accounts(self): | |
self.org.save(update_fields=("features",)) | ||
|
||
# create invitations | ||
invitation1 = Invitation.objects.create( | ||
org=self.org, email="[email protected]", user_group="A", created_by=self.admin, modified_by=self.admin | ||
) | ||
invitation2 = Invitation.objects.create( | ||
org=self.org, email="[email protected]", user_group="T", created_by=self.admin, modified_by=self.admin | ||
) | ||
invitation1 = Invitation.create(self.org, self.admin, "[email protected]", OrgRole.ADMINISTRATOR) | ||
invitation2 = Invitation.create(self.org, self.admin, "[email protected]", OrgRole.AGENT) | ||
|
||
# add a second editor to the org | ||
editor2 = self.create_user("[email protected]", first_name="Edwina") | ||
|
@@ -2001,13 +1991,7 @@ def test_join(self): | |
response = self.client.get(reverse("orgs.org_join", args=["invalid"])) | ||
self.assertRedirect(response, reverse("public.public_index")) | ||
|
||
invitation = Invitation.objects.create( | ||
org=self.org, | ||
user_group="E", | ||
email="[email protected]", | ||
created_by=self.admin, | ||
modified_by=self.admin, | ||
) | ||
invitation = Invitation.create(self.org, self.admin, "[email protected]", OrgRole.EDITOR) | ||
|
||
join_url = reverse("orgs.org_join", args=[invitation.secret]) | ||
join_signup_url = reverse("orgs.org_join_signup", args=[invitation.secret]) | ||
|
@@ -2034,13 +2018,7 @@ def test_join(self): | |
self.assertEqual(0, len(self.client.session.keys())) | ||
|
||
# invitation with mismatching case email | ||
invitation2 = Invitation.objects.create( | ||
org=self.org2, | ||
user_group="E", | ||
email="[email protected]", | ||
created_by=self.admin2, | ||
modified_by=self.admin2, | ||
) | ||
invitation2 = Invitation.create(self.org2, self.admin, "[email protected]", OrgRole.EDITOR) | ||
|
||
join_accept_url = reverse("orgs.org_join_accept", args=[invitation2.secret]) | ||
join_url = reverse("orgs.org_join", args=[invitation2.secret]) | ||
|
@@ -2062,13 +2040,7 @@ def test_join_signup(self): | |
response = self.client.get(reverse("orgs.org_join_signup", args=["invalid"])) | ||
self.assertRedirect(response, reverse("public.public_index")) | ||
|
||
invitation = Invitation.objects.create( | ||
org=self.org, | ||
user_group="A", | ||
email="[email protected]", | ||
created_by=self.admin, | ||
modified_by=self.admin, | ||
) | ||
invitation = Invitation.create(self.org, self.admin, "[email protected]", OrgRole.ADMINISTRATOR) | ||
|
||
join_signup_url = reverse("orgs.org_join_signup", args=[invitation.secret]) | ||
join_url = reverse("orgs.org_join", args=[invitation.secret]) | ||
|
@@ -2077,13 +2049,7 @@ def test_join_signup(self): | |
response = self.client.get(join_signup_url) | ||
self.assertRedirect(response, join_url) | ||
|
||
invitation = Invitation.objects.create( | ||
org=self.org, | ||
user_group="E", | ||
email="[email protected]", | ||
created_by=self.admin, | ||
modified_by=self.admin, | ||
) | ||
invitation = Invitation.create(self.org, self.admin, "[email protected]", OrgRole.EDITOR) | ||
|
||
join_signup_url = reverse("orgs.org_join_signup", args=[invitation.secret]) | ||
join_url = reverse("orgs.org_join", args=[invitation.secret]) | ||
|
@@ -2116,13 +2082,7 @@ def test_join_accept(self): | |
response = self.client.get(reverse("orgs.org_join_accept", args=["invalid"])) | ||
self.assertRedirect(response, reverse("public.public_index")) | ||
|
||
invitation = Invitation.objects.create( | ||
org=self.org, | ||
user_group="E", | ||
email="[email protected]", | ||
created_by=self.admin, | ||
modified_by=self.admin, | ||
) | ||
invitation = Invitation.create(self.org, self.admin, "[email protected]", OrgRole.EDITOR) | ||
|
||
join_accept_url = reverse("orgs.org_join_accept", args=[invitation.secret]) | ||
join_url = reverse("orgs.org_join", args=[invitation.secret]) | ||
|
@@ -3438,13 +3398,7 @@ def test_forget(self): | |
self.assertRedirect(response, forget_url, status_code=301) | ||
|
||
FailedLogin.objects.create(username="[email protected]") | ||
invitation = Invitation.objects.create( | ||
org=self.org, | ||
user_group="A", | ||
email="[email protected]", | ||
created_by=self.admin, | ||
modified_by=self.admin, | ||
) | ||
invitation = Invitation.create(self.org, self.admin, "[email protected]", OrgRole.ADMINISTRATOR) | ||
|
||
# no login required to access | ||
response = self.client.get(forget_url) | ||
|
@@ -4371,9 +4325,30 @@ def test_prevent_flow_type_changes(self): | |
|
||
|
||
class InvitationCRUDLTest(TembaTest, CRUDLTestMixin): | ||
def test_list(self): | ||
list_url = reverse("orgs.invitation_list") | ||
|
||
# nobody can access if users feature not enabled | ||
response = self.requestView(list_url, self.admin) | ||
self.assertRedirect(response, reverse("orgs.org_workspace")) | ||
|
||
self.org.features = [Org.FEATURE_USERS] | ||
self.org.save(update_fields=("features",)) | ||
|
||
self.assertRequestDisallowed(list_url, [None, self.user, self.editor, self.agent]) | ||
|
||
inv1 = Invitation.create(self.org, self.admin, "[email protected]", OrgRole.EDITOR) | ||
inv2 = Invitation.create(self.org, self.admin, "[email protected]", OrgRole.AGENT) | ||
|
||
self.assertListFetch(list_url, [self.admin], context_objects=[inv2, inv1]) | ||
|
||
def test_create(self): | ||
create_url = reverse("orgs.invitation_create") | ||
|
||
# nobody can access if users feature not enabled | ||
response = self.requestView(create_url, self.admin) | ||
self.assertRedirect(response, reverse("orgs.org_workspace")) | ||
|
||
self.org.features = [Org.FEATURE_CHILD_ORGS, Org.FEATURE_USERS] | ||
self.org.save(update_fields=("features",)) | ||
|
||
|
@@ -4443,6 +4418,31 @@ def test_create(self): | |
response = self.client.get(create_url + f"?org={self.org2.id}") | ||
self.assertEqual(404, response.status_code) | ||
|
||
def test_delete(self): | ||
inv1 = Invitation.create(self.org, self.admin, "[email protected]", OrgRole.EDITOR) | ||
inv2 = Invitation.create(self.org, self.admin, "[email protected]", OrgRole.AGENT) | ||
|
||
delete_url = reverse("orgs.invitation_delete", args=[inv1.id]) | ||
|
||
# nobody can access if users feature not enabled | ||
response = self.requestView(delete_url, self.admin) | ||
self.assertRedirect(response, reverse("orgs.org_workspace")) | ||
|
||
self.org.features = [Org.FEATURE_USERS] | ||
self.org.save(update_fields=("features",)) | ||
|
||
self.assertRequestDisallowed(delete_url, [None, self.user, self.editor, self.agent]) | ||
|
||
response = self.assertDeleteFetch(delete_url, [self.admin], as_modal=True) | ||
self.assertContains( | ||
response, "You are about to cancel the invitation sent to <b>[email protected]</b>. Are you sure?" | ||
) | ||
|
||
response = self.assertDeleteSubmit(delete_url, self.admin, object_deactivated=inv1) | ||
|
||
self.assertRedirect(response, reverse("orgs.invitation_list")) | ||
self.assertEqual({inv2}, set(self.org.invitations.filter(is_active=True))) | ||
|
||
|
||
class BackupTokenTest(TembaTest): | ||
def test_model(self): | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{% extends "includes/modax.html" %} | ||
{% load i18n %} | ||
|
||
{% block fields %} | ||
{% blocktrans trimmed with email=object.email %} | ||
You are about to cancel the invitation sent to <b>{{ email }}</b>. Are you sure? | ||
{% endblocktrans %} | ||
{% endblock fields %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
{% extends "smartmin/list.html" %} | ||
{% load smartmin temba i18n %} | ||
|
||
{% block content %} | ||
<div class="mb-4"> | ||
{% blocktrans trimmed with days=validity_days %} | ||
These are pending invitations to join your workspace. Invitations expire after {{ days }} days. | ||
{% endblocktrans %} | ||
</div> | ||
{% block pre-table %} | ||
<temba-modax header="{{ _("Cancel Invitation") |escapejs }}" id="delete-invitation"> | ||
</temba-modax> | ||
{% endblock pre-table %} | ||
<div class="mt-4 shadow rounded-lg rounded-bl-none rounded-br-none bg-white">{% include "includes/short_pagination.html" %}</div> | ||
<div class="flex-grow overflow-y-auto shadow"> | ||
<table class="list lined scrolled"> | ||
<thead> | ||
<tr> | ||
<th>{% trans "Email" %}</th> | ||
<th>{% trans "Role" %}</th> | ||
<th>{% trans "Sent On" %}</th> | ||
<th></th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{% for obj in object_list %} | ||
<tr> | ||
<td>{{ obj.email }}</td> | ||
<td>{{ obj.role.display }}</td> | ||
<td>{{ obj.created_on|day }}</td> | ||
<td class="w-10"> | ||
<div style="visibility:hidden" | ||
onclick="event.stopPropagation(); showDeleteInvitationModal({{ obj.id }});" | ||
class="pl-2 pt-1 delete-link linked text-gray-400"> | ||
<temba-icon name="delete_small"> | ||
</temba-icon> | ||
</div> | ||
</td> | ||
</tr> | ||
{% empty %} | ||
<tr class="empty_list"> | ||
<td colspan="99" class="text-center">{% trans "No invitations" %}</td> | ||
</tr> | ||
{% endfor %} | ||
</tbody> | ||
</table> | ||
</div> | ||
{% endblock content %} | ||
{% block extra-script %} | ||
{{ block.super }} | ||
<script> | ||
function showDeleteInvitationModal(id) { | ||
var modax = document.querySelector('#delete-invitation'); | ||
modax.endpoint = `/invitation/delete/${id}/`; | ||
modax.open = true; | ||
} | ||
</script> | ||
{% endblock extra-script %} | ||
{% block extra-style %} | ||
{{ block.super }} | ||
<style type="text/css"> | ||
tr:hover .delete-link { | ||
visibility: visible !important; | ||
} | ||
</style> | ||
{% endblock extra-style %} |