Merge pull request #453 from taigaio/filter-by-email-domain-on-register
Add filter by email domain on registerremotes/origin/issue/4795/notification_even_they_are_disabled
commit
bc3025f065
|
@ -22,6 +22,7 @@
|
|||
- Import/Export:
|
||||
- Gzip export/import support.
|
||||
- Export performance improvements.
|
||||
- Add filter by email domain registration and invitation by setting.
|
||||
|
||||
### Misc
|
||||
- [API] Improve performance of some calls over list.
|
||||
|
|
|
@ -441,6 +441,8 @@ APP_EXTRA_EXPOSE_HEADERS = [
|
|||
|
||||
DEFAULT_PROJECT_TEMPLATE = "scrum"
|
||||
PUBLIC_REGISTER_ENABLED = False
|
||||
# None or [] values in USER_EMAIL_ALLOWED_DOMAINS means allow any domain
|
||||
USER_EMAIL_ALLOWED_DOMAINS = None
|
||||
|
||||
SEARCHES_MAX_RESULTS = 150
|
||||
|
||||
|
|
|
@ -105,3 +105,7 @@ DATABASES = {
|
|||
# To use celery in memory
|
||||
#CELERY_ENABLED = True
|
||||
#CELERY_ALWAYS_EAGER = True
|
||||
|
||||
# LIMIT ALLOWED DOMAINS FOR REGISTER AND INVITE
|
||||
# None or [] values in USER_EMAIL_ALLOWED_DOMAINS means allow any domain
|
||||
# USER_EMAIL_ALLOWED_DOMAINS = None
|
||||
|
|
|
@ -612,6 +612,14 @@ class ChoiceField(WritableField):
|
|||
return value
|
||||
|
||||
|
||||
def validate_user_email_allowed_domains(value):
|
||||
domain_name = value.split("@")[1]
|
||||
print("EMAIL VALIDATE DOMAIN")
|
||||
|
||||
if settings.USER_EMAIL_ALLOWED_DOMAINS and domain_name not in settings.USER_EMAIL_ALLOWED_DOMAINS:
|
||||
raise ValidationError(_("You email domain is not allowed"))
|
||||
|
||||
|
||||
class EmailField(CharField):
|
||||
type_name = "EmailField"
|
||||
type_label = "email"
|
||||
|
@ -620,7 +628,7 @@ class EmailField(CharField):
|
|||
default_error_messages = {
|
||||
"invalid": _("Enter a valid email address."),
|
||||
}
|
||||
default_validators = [validators.validate_email]
|
||||
default_validators = [validators.validate_email, validate_user_email_allowed_domains]
|
||||
|
||||
def from_native(self, value):
|
||||
ret = super(EmailField, self).from_native(value)
|
||||
|
|
|
@ -33,6 +33,7 @@ from taiga.base.decorators import list_route
|
|||
from taiga.base.decorators import detail_route
|
||||
from taiga.base.api import ModelCrudViewSet
|
||||
from taiga.base.api.mixins import BlockedByProjectMixin
|
||||
from taiga.base.api.fields import validate_user_email_allowed_domains
|
||||
from taiga.base.api.utils import get_object_or_404
|
||||
from taiga.base.filters import MembersFilterBackend
|
||||
from taiga.base.mails import mail_builder
|
||||
|
@ -112,6 +113,7 @@ class UsersViewSet(ModelCrudViewSet):
|
|||
|
||||
try:
|
||||
validate_email(new_email)
|
||||
validate_user_email_allowed_domains(new_email)
|
||||
except ValidationError:
|
||||
valid_new_email = False
|
||||
|
||||
|
|
|
@ -48,6 +48,20 @@ def test_respond_400_when_public_registration_is_disabled(client, register_form,
|
|||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_respond_400_when_the_email_domain_isnt_in_allowed_domains(client, register_form, settings):
|
||||
settings.PUBLIC_REGISTER_ENABLED = True
|
||||
settings.USER_EMAIL_ALLOWED_DOMAINS = ['other-domain.com']
|
||||
response = client.post(reverse("auth-register"), register_form)
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_respond_201_when_the_email_domain_is_in_allowed_domains(client, settings, register_form):
|
||||
settings.PUBLIC_REGISTER_ENABLED = True
|
||||
settings.USER_EMAIL_ALLOWED_DOMAINS = ['email.com']
|
||||
response = client.post(reverse("auth-register"), register_form)
|
||||
assert response.status_code == 201
|
||||
|
||||
|
||||
def test_respond_201_with_invitation_without_public_registration(client, register_form, settings):
|
||||
settings.PUBLIC_REGISTER_ENABLED = False
|
||||
user = factories.UserFactory()
|
||||
|
|
|
@ -72,6 +72,79 @@ def test_api_create_bulk_members(client):
|
|||
assert response.data[1]["email"] == joseph.email
|
||||
|
||||
|
||||
def test_api_create_bulk_members_with_allowed_domain(client):
|
||||
project = f.ProjectFactory()
|
||||
john = f.UserFactory.create()
|
||||
joseph = f.UserFactory.create()
|
||||
tester = f.RoleFactory(project=project, name="Tester")
|
||||
gamer = f.RoleFactory(project=project, name="Gamer")
|
||||
f.MembershipFactory(project=project, user=project.owner, is_admin=True)
|
||||
|
||||
url = reverse("memberships-bulk-create")
|
||||
|
||||
data = {
|
||||
"project_id": project.id,
|
||||
"bulk_memberships": [
|
||||
{"role_id": tester.pk, "email": "test1@email.com"},
|
||||
{"role_id": gamer.pk, "email": "test2@email.com"},
|
||||
]
|
||||
}
|
||||
client.login(project.owner)
|
||||
response = client.json.post(url, json.dumps(data))
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.data[0]["email"] == "test1@email.com"
|
||||
assert response.data[1]["email"] == "test2@email.com"
|
||||
|
||||
|
||||
def test_api_create_bulk_members_with_allowed_and_unallowed_domain(client, settings):
|
||||
project = f.ProjectFactory()
|
||||
settings.USER_EMAIL_ALLOWED_DOMAINS = ['email.com']
|
||||
tester = f.RoleFactory(project=project, name="Tester")
|
||||
gamer = f.RoleFactory(project=project, name="Gamer")
|
||||
f.MembershipFactory(project=project, user=project.owner, is_admin=True)
|
||||
|
||||
url = reverse("memberships-bulk-create")
|
||||
|
||||
data = {
|
||||
"project_id": project.id,
|
||||
"bulk_memberships": [
|
||||
{"role_id": tester.pk, "email": "test@invalid-domain.com"},
|
||||
{"role_id": gamer.pk, "email": "test@email.com"},
|
||||
]
|
||||
}
|
||||
client.login(project.owner)
|
||||
response = client.json.post(url, json.dumps(data))
|
||||
|
||||
assert response.status_code == 400
|
||||
assert "email" in response.data["bulk_memberships"][0]
|
||||
assert "email" not in response.data["bulk_memberships"][1]
|
||||
|
||||
|
||||
def test_api_create_bulk_members_with_unallowed_domains(client, settings):
|
||||
project = f.ProjectFactory()
|
||||
settings.USER_EMAIL_ALLOWED_DOMAINS = ['email.com']
|
||||
tester = f.RoleFactory(project=project, name="Tester")
|
||||
gamer = f.RoleFactory(project=project, name="Gamer")
|
||||
f.MembershipFactory(project=project, user=project.owner, is_admin=True)
|
||||
|
||||
url = reverse("memberships-bulk-create")
|
||||
|
||||
data = {
|
||||
"project_id": project.id,
|
||||
"bulk_memberships": [
|
||||
{"role_id": tester.pk, "email": "test1@invalid-domain.com"},
|
||||
{"role_id": gamer.pk, "email": "test2@invalid-domain.com"},
|
||||
]
|
||||
}
|
||||
client.login(project.owner)
|
||||
response = client.json.post(url, json.dumps(data))
|
||||
|
||||
assert response.status_code == 400
|
||||
assert "email" in response.data["bulk_memberships"][0]
|
||||
assert "email" in response.data["bulk_memberships"][1]
|
||||
|
||||
|
||||
def test_api_create_bulk_members_without_enough_memberships_private_project_slots_one_project(client):
|
||||
user = f.UserFactory.create(max_memberships_private_projects=3)
|
||||
project = f.ProjectFactory(owner=user, is_private=True)
|
||||
|
@ -314,6 +387,36 @@ def test_api_create_membership(client):
|
|||
assert response.data["user_email"] == user.email
|
||||
|
||||
|
||||
def test_api_create_membership_with_unallowed_domain(client, settings):
|
||||
settings.USER_EMAIL_ALLOWED_DOMAINS = ['email.com']
|
||||
|
||||
membership = f.MembershipFactory(is_admin=True)
|
||||
role = f.RoleFactory.create(project=membership.project)
|
||||
|
||||
client.login(membership.user)
|
||||
url = reverse("memberships-list")
|
||||
data = {"role": role.pk, "project": role.project.pk, "email": "test@invalid-email.com"}
|
||||
response = client.json.post(url, json.dumps(data))
|
||||
|
||||
assert response.status_code == 400
|
||||
assert "email" in response.data
|
||||
|
||||
|
||||
def test_api_create_membership_with_allowed_domain(client, settings):
|
||||
settings.USER_EMAIL_ALLOWED_DOMAINS = ['email.com']
|
||||
|
||||
membership = f.MembershipFactory(is_admin=True)
|
||||
role = f.RoleFactory.create(project=membership.project)
|
||||
|
||||
client.login(membership.user)
|
||||
url = reverse("memberships-list")
|
||||
data = {"role": role.pk, "project": role.project.pk, "email": "test@email.com"}
|
||||
response = client.json.post(url, json.dumps(data))
|
||||
|
||||
assert response.status_code == 201
|
||||
assert response.data["email"] == "test@email.com"
|
||||
|
||||
|
||||
def test_api_create_membership_without_enough_memberships_private_project_slots_one_projects(client):
|
||||
user = f.UserFactory.create(max_memberships_private_projects=1)
|
||||
project = f.ProjectFactory(owner=user, is_private=True)
|
||||
|
|
|
@ -99,6 +99,35 @@ def test_update_user_with_invalid_email(client):
|
|||
assert response.data['_error_message'] == 'Not valid email'
|
||||
|
||||
|
||||
def test_update_user_with_unallowed_domain_email(client, settings):
|
||||
settings.USER_EMAIL_ALLOWED_DOMAINS = ['email.com']
|
||||
user = f.UserFactory.create(email="my@email.com")
|
||||
url = reverse('users-detail', kwargs={"pk": user.pk})
|
||||
data = {"email": "my@invalid-email.com"}
|
||||
|
||||
client.login(user)
|
||||
response = client.patch(url, json.dumps(data), content_type="application/json")
|
||||
|
||||
assert response.status_code == 400
|
||||
assert response.data['_error_message'] == 'Not valid email'
|
||||
|
||||
|
||||
def test_update_user_with_allowed_domain_email(client, settings):
|
||||
settings.USER_EMAIL_ALLOWED_DOMAINS = ['email.com']
|
||||
|
||||
user = f.UserFactory.create(email="old@email.com")
|
||||
url = reverse('users-detail', kwargs={"pk": user.pk})
|
||||
data = {"email": "new@email.com"}
|
||||
|
||||
client.login(user)
|
||||
response = client.patch(url, json.dumps(data), content_type="application/json")
|
||||
|
||||
assert response.status_code == 200
|
||||
user = models.User.objects.get(pk=user.id)
|
||||
assert user.email_token is not None
|
||||
assert user.new_email == "new@email.com"
|
||||
|
||||
|
||||
def test_update_user_with_valid_email(client):
|
||||
user = f.UserFactory.create(email="old@email.com")
|
||||
url = reverse('users-detail', kwargs={"pk": user.pk})
|
||||
|
|
Loading…
Reference in New Issue