intent/tests/test_org_views.py

114 lines
4.2 KiB
Python
Raw Normal View History

import re
from django.core import mail
from django.urls import reverse
from intent.orgs.models import InviteStatus, OrgInvite, Role
def members_url(org):
return reverse("orgs:members", kwargs={"org_slug": org.slug})
def test_org_page_is_public(client, org):
response = client.get(reverse("orgs:detail", kwargs={"org_slug": org.slug}))
assert response.status_code == 200
assert b"Catbriar" in response.content
def test_members_page_requires_membership(client, make_user, org):
assert client.get(members_url(org)).status_code == 403
client.force_login(make_user())
assert client.get(members_url(org)).status_code == 403
def test_collaborator_sees_members_but_cannot_invite(client, collaborator, org):
client.force_login(collaborator)
response = client.get(members_url(org))
assert response.status_code == 200
assert b"Invite someone" not in response.content
response = client.post(members_url(org), {"recipient": "x@example.com", "role": "owner"})
assert response.status_code == 403
def test_invite_by_username_then_accept_from_invitations_page(client, owner, make_user, org):
invitee = make_user("ivan")
client.force_login(owner)
response = client.post(members_url(org), {"recipient": "IVAN", "role": "collaborator"})
assert response.status_code == 302
invite = OrgInvite.objects.get(user=invitee)
assert mail.outbox == [] # in-app only; no notifications in V1
client.force_login(invitee)
assert b"Catbriar" in client.get(reverse("invites:list")).content
response = client.post(
reverse("invites:respond", kwargs={"invite_id": invite.pk}), {"action": "accept"}
)
assert response.status_code == 302
assert org.memberships.filter(user=invitee, role=Role.COLLABORATOR).exists()
def test_cannot_respond_to_someone_elses_invite(client, owner, make_user, org):
invite = OrgInvite.objects.create(org=org, user=make_user(), invited_by=owner, token_hash="x")
client.force_login(make_user())
response = client.post(
reverse("invites:respond", kwargs={"invite_id": invite.pk}), {"action": "accept"}
)
assert response.status_code == 403
def test_email_invite_link_flow(client, owner, make_user, org):
client.force_login(owner)
client.post(members_url(org), {"recipient": "new@example.com", "role": "collaborator"})
assert len(mail.outbox) == 1
path = re.search(r"https?://[^/]+(/invites/t/\S+/)", mail.outbox[0].body).group(1)
client.logout()
response = client.get(path)
assert response.status_code == 302
assert response["Location"].startswith(reverse("account_login"))
# Bearer link: any signed-in account can accept, whatever its email.
joiner = make_user("june", email="june@elsewhere.example")
client.force_login(joiner)
assert client.get(path).status_code == 200
client.post(path, {"action": "accept"})
assert org.memberships.filter(user=joiner).exists()
assert OrgInvite.objects.get(email="new@example.com").status == InviteStatus.ACCEPTED
def test_invalid_token_is_404(client, make_user):
client.force_login(make_user())
assert client.get(reverse("invites:by_token", kwargs={"token": "nope"})).status_code == 404
def test_owner_updates_role_and_grant(client, owner, collaborator, org):
membership = org.memberships.get(user=collaborator)
client.force_login(owner)
client.post(
reverse(
"orgs:member_update", kwargs={"org_slug": org.slug, "membership_id": membership.pk}
),
{"role": "collaborator", "can_create_projects": "on"},
)
membership.refresh_from_db()
assert membership.can_create_projects
def test_last_owner_leaving_shows_error(client, owner, org):
membership = org.memberships.get(user=owner)
client.force_login(owner)
response = client.post(
reverse(
"orgs:member_remove", kwargs={"org_slug": org.slug, "membership_id": membership.pk}
),
follow=True,
)
assert b"at least one owner" in response.content
assert org.memberships.filter(user=owner).exists()
def test_home_lists_orgs_and_invites(client, owner, make_user, org):
client.force_login(owner)
assert b"Catbriar" in client.get("/").content