Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invite email multi site #579

Merged
merged 7 commits into from
Feb 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions rdmo/projects/tests/test_view_membership_multisite.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import pytest

from django.contrib.auth import get_user_model
from django.contrib.sites.models import Site
from django.core import mail
from django.urls import reverse

from ..models import Invite, Project
from ..utils import get_invite_email_project_path
users = (
('owner', 'owner'),
('manager', 'manager'),
('author', 'author'),
('guest', 'guest'),
('user', 'user'),
('site', 'site'),
('anonymous', None),
)

add_membership_permission_map = {
'owner': [1, 2, 3, 4, 5],
'api': [1, 2, 3, 4, 5],
'site': [1, 2, 3, 4, 5]
}

projects = [1, 2, 3, 4, 5]
memberships = [1, 2, 3, 4]

membership_roles = ('owner', 'manager', 'author', 'guest')

sites_domains = ('example.com', 'foo.com', 'bar.com')

@pytest.fixture()
def multisite_setting(settings):
settings.MULTISITE = True

@pytest.mark.parametrize('username,password', users)
@pytest.mark.parametrize('project_id', projects)
@pytest.mark.parametrize('membership_role', membership_roles)
@pytest.mark.parametrize('site_domain', sites_domains)
def test_get_invite_email_project_path_function(db, client, username, password, project_id, membership_role, site_domain, multisite_setting):
client.login(username=username, password=password)

current_site = Site.objects.get_current()
foo_site, _created = Site.objects.get_or_create(domain=site_domain, name=site_domain)
foo_username = f'{site_domain}-test-user'
foo_email = f'{foo_username}@{site_domain}'
foo_user, _created = get_user_model().objects.get_or_create(username=foo_username, email=foo_email, password=foo_username)
foo_user.role.member.set([foo_site])
project = Project.objects.get(pk=project_id)

invite = Invite(project=project, user=foo_user, role=membership_role)
invite.make_token()
invite.save()

invite_email_project_path = get_invite_email_project_path(invite)
if current_site.domain == site_domain:
assert invite_email_project_path.startswith('/projects')
else:
assert invite_email_project_path.startswith('http://' + site_domain + '/projects')

@pytest.mark.parametrize('username,password', users)
@pytest.mark.parametrize('project_id', projects)
@pytest.mark.parametrize('membership_role', membership_roles)
@pytest.mark.parametrize('site_domain', sites_domains)
def test_invite_email_project_path_email_body(db, client, username, password, project_id, membership_role, site_domain, multisite_setting):
client.login(username=username, password=password)

current_site = Site.objects.get_current()
foo_site, _created = Site.objects.get_or_create(domain=site_domain, name=site_domain)
foo_username = f'{site_domain}-user'
foo_email = f'{foo_username}@{site_domain}'
foo_user, _created = get_user_model().objects.get_or_create(username=f'{site_domain}-user', email=foo_email, password=foo_username)
foo_user.role.member.set([foo_site])
project = Project.objects.get(pk=project_id)

url = reverse('membership_create', args=[project_id])
data = {
'username_or_email': foo_email,
'role': membership_role
}
response = client.post(url, data)

invite = Invite(project=project, user=foo_user, role=membership_role)
invite.make_token()
invite.save()

if project_id in add_membership_permission_map.get(username, []):
if current_site.domain == site_domain:
assert 'http://testserver/' in mail.outbox[0].body
else:
assert f'http://{foo_site.domain}/' in mail.outbox[0].body

assert response.status_code == 302
assert len(mail.outbox) == 1
else:
if password:
assert response.status_code == 403
else:
assert response.status_code == 302
assert len(mail.outbox) == 0
17 changes: 17 additions & 0 deletions rdmo/projects/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import logging
from pathlib import Path

from django.conf import settings
from django.contrib.sites.models import Site
from django.urls import reverse

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -128,3 +132,16 @@ def save_import_tasks(project, tasks):
def save_import_views(project, views):
for view in views:
project.views.add(view)


def get_invite_email_project_path(invite) -> str:
project_invite_path = reverse('project_join', args=[invite.token])
# check if the invited user exists and the multisite environment is enabled
if invite.user is not None and settings.MULTISITE:
# do nothing if user is a member of the current site
current_site = Site.objects.get_current()
if not invite.user.role.member.filter(id=current_site.id).exists():
# else take first site
invited_user_member_domain = invite.user.role.member.first().domain
project_invite_path = 'http://' + invited_user_member_domain + project_invite_path
return project_invite_path
6 changes: 4 additions & 2 deletions rdmo/projects/views/membership.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

from ..forms import MembershipCreateForm
from ..models import Membership, Project
from ..utils import is_last_owner
from ..utils import is_last_owner, get_invite_email_project_path

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -48,8 +48,10 @@ def get_success_url(self):
def form_valid(self, form):
invite = form.save()
if invite is not None:

project_invite_path = get_invite_email_project_path(invite)
context = {
'invite_url': self.request.build_absolute_uri(reverse('project_join', args=[invite.token])),
'invite_url': self.request.build_absolute_uri(project_invite_path),
'invite_user': invite.user,
'project': invite.project,
'user': self.request.user,
Expand Down