mirror of https://github.com/doccano/doccano.git
25 changed files with 0 additions and 480 deletions
Split View
Diff Options
-
0backend/authentification/__init__.py
-
0backend/authentification/admin.py
-
12backend/authentification/forms.py
-
0backend/authentification/models.py
-
5backend/authentification/templates/acc_active_email.html
-
11backend/authentification/templates/base_auth.html
-
12backend/authentification/templates/email_not_set.html
-
9backend/authentification/templates/password_reset_complete.html
-
25backend/authentification/templates/password_reset_confirm.html
-
14backend/authentification/templates/password_reset_done.html
-
12backend/authentification/templates/password_reset_email.html
-
19backend/authentification/templates/password_reset_form.html
-
1backend/authentification/templates/password_reset_subject.txt
-
45backend/authentification/templates/signup.html
-
14backend/authentification/templates/validate_mail_address_complete.html
-
9backend/authentification/templates/validate_mail_address_invalid.html
-
11backend/authentification/templatetags/utils_templating.py
-
0backend/authentification/tests/__init__.py
-
40backend/authentification/tests/test_activate.py
-
49backend/authentification/tests/test_signup.py
-
85backend/authentification/tests/test_template.py
-
13backend/authentification/tokens.py
-
18backend/authentification/urls.py
-
24backend/authentification/utils.py
-
52backend/authentification/views.py
@ -1,12 +0,0 @@ |
|||
from django import forms |
|||
from django.contrib.auth import get_user_model |
|||
from django.contrib.auth.forms import UserCreationForm |
|||
|
|||
User = get_user_model() |
|||
|
|||
class SignupForm(UserCreationForm): |
|||
email = forms.EmailField(max_length=200, help_text='Required') |
|||
|
|||
class Meta: |
|||
model = User |
|||
fields = ('username', 'email', 'password1', 'password2') |
@ -1,5 +0,0 @@ |
|||
{% autoescape off %} |
|||
Hi {{ user.username }}, |
|||
Please click on the link to confirm your email and activate your Doccano account: |
|||
{{ scheme }}://{{ domain }}{% url 'activate' uidb64=uid token=token %} |
|||
{% endautoescape %} |
@ -1,11 +0,0 @@ |
|||
{% extends 'base.html' %} |
|||
|
|||
{% block content %} |
|||
<div class="hero-body"> |
|||
<div class="container"> |
|||
<div class="card is-shady column is-4 is-offset-4"> |
|||
{% block content_auth %}{% endblock %} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
{% endblock %} |
@ -1,12 +0,0 @@ |
|||
{% extends "base_auth.html" %} |
|||
|
|||
{% block content_auth %} |
|||
<div class="card-content"> |
|||
<p> |
|||
The webmaster <span>has not set up any emails</span> yet, so we can't send you any link confirmation |
|||
</p> |
|||
<p> |
|||
Please contact the admin to learn more |
|||
</p> |
|||
</div> |
|||
{% endblock %} |
@ -1,9 +0,0 @@ |
|||
{% extends "base_auth.html" %} |
|||
|
|||
{% block content_auth %} |
|||
<div class="card-content"> |
|||
<p> |
|||
Your password has been set. You may go ahead and <a href="{% url 'login' %}">sign in</a> now. |
|||
</p> |
|||
</div> |
|||
{% endblock %} |
@ -1,25 +0,0 @@ |
|||
{% extends "base_auth.html" %} |
|||
|
|||
{% block content_auth %} |
|||
{% if validlink %} |
|||
<div class="card-content"> |
|||
<div style="text-align:center;font-size:1.5em"> |
|||
<h2>Change password</h2> |
|||
</div> |
|||
|
|||
<form method="post"> |
|||
{% csrf_token %} |
|||
{{ form.as_p }} |
|||
<div style="text-align:center"> |
|||
<button type="submit" class="button is-link">Change password</button> |
|||
</div> |
|||
</form> |
|||
|
|||
</div> |
|||
{% else %} |
|||
<div class="card-content"> |
|||
The password reset link was invalid, possibly because it has already been used. |
|||
Please request a new password reset. |
|||
</div> |
|||
{% endif %} |
|||
{% endblock %} |
@ -1,14 +0,0 @@ |
|||
{% extends "base_auth.html" %} |
|||
|
|||
{% block content_auth %} |
|||
<div class="card-content"> |
|||
<p> |
|||
We've emailed you instructions for re-setting your password, if an account exists with the email you entered. |
|||
You should receive them shortly. |
|||
</p> |
|||
<p> |
|||
If you don't receive an email, please make sure you've entered the address you registered with, |
|||
and check your spam folder. |
|||
</p> |
|||
</div> |
|||
{% endblock %} |
@ -1,12 +0,0 @@ |
|||
{% autoescape off %} |
|||
To initiate the password reset process for your {{ user.get_username }} Doccano Account, |
|||
click the link below: |
|||
|
|||
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %} |
|||
|
|||
If clicking the link above doesn't work, please copy and paste the URL in a new browser |
|||
window instead. |
|||
|
|||
Sincerely, |
|||
The Doccano Team |
|||
{% endautoescape %} |
@ -1,19 +0,0 @@ |
|||
{% extends "base_auth.html" %} |
|||
|
|||
{% load widget_tweaks %} |
|||
{% block content_auth %} |
|||
<div class="card-content"> |
|||
<div style="text-align:center;font-size:1.5em"> |
|||
<h2>Forgot password</h2> |
|||
</div> |
|||
|
|||
<form method="post"> |
|||
{% csrf_token %} |
|||
{{ form.as_p }} |
|||
<div style="text-align:center"> |
|||
<button type="submit" class="button is-link">Submit</button> |
|||
</div> |
|||
</form> |
|||
|
|||
</div> |
|||
{% endblock %} |
@ -1 +0,0 @@ |
|||
Password reset |
@ -1,45 +0,0 @@ |
|||
{% extends "base_auth.html" %} |
|||
|
|||
{% load utils_templating %} |
|||
{% block content_auth %} |
|||
{% if allow_signup %} |
|||
<div class="card-content"> |
|||
<!-- <div style="text-align:center;font-size:1.5em"> |
|||
<h2>Sign up</h2> |
|||
</div> --> |
|||
<form method="post"> |
|||
{% csrf_token %} |
|||
{% for field in form %} |
|||
<div class="field"> |
|||
<label class="label">{{ field.label_tag }}</label> |
|||
<div class="control"> |
|||
{{ field|addcss:'input' }} |
|||
{% if field.help_text %} |
|||
<small style="display: none">{{ field.help_text }}</small> |
|||
{% endif %} |
|||
{% for error in field.errors %} |
|||
<p style="color: red">{{ error }}</p> |
|||
{% endfor %} |
|||
</div> |
|||
</div> |
|||
|
|||
{% endfor %} |
|||
<div style="text-align:center"> |
|||
<button type="submit" class="button is-block is-primary is-fullwidth is-middle">Sign up</button> |
|||
</div> |
|||
<div class="field"> |
|||
<span class="checkbox" style="margin-top:30px"> |
|||
Already registered ? <a href="{% url 'login' %}"> login </a> |
|||
</span> |
|||
</div> |
|||
</form> |
|||
</div> |
|||
|
|||
{% else %} |
|||
<div class="card-content"> |
|||
<div> |
|||
You can't signup yourself, please contact the admin in order to get your username and your password! |
|||
</div> |
|||
</div> |
|||
{% endif %} |
|||
{% endblock %} |
@ -1,14 +0,0 @@ |
|||
{% extends "base_auth.html" %} |
|||
|
|||
{% block content_auth %} |
|||
<div class="card-content"> |
|||
<p> |
|||
We've <span>emailed you instructions to activate your account</span>. |
|||
You should receive them shortly. |
|||
</p> |
|||
<p> |
|||
If you don't receive an email, please make sure you've entered the address you registered with, |
|||
and check your spam folder. |
|||
</p> |
|||
</div> |
|||
{% endblock %} |
@ -1,9 +0,0 @@ |
|||
{% extends "base_auth.html" %} |
|||
|
|||
{% block content_auth %} |
|||
<div class="card-content" style="color:white;background-color:red;"> |
|||
<p> |
|||
Activation link is invalid! |
|||
</p> |
|||
</div> |
|||
{% endblock %} |
@ -1,11 +0,0 @@ |
|||
from django import template |
|||
|
|||
register = template.Library() |
|||
|
|||
|
|||
@register.filter(name='addcss') |
|||
def addcss(value, arg): |
|||
css_classes = value.field.widget.attrs.get('class', '').split(' ') |
|||
if css_classes and arg not in css_classes: |
|||
css_classes = '%s %s' % (*css_classes, arg) |
|||
return value.as_widget(attrs={'class': css_classes}) |
@ -1,40 +0,0 @@ |
|||
from django.test import RequestFactory, TestCase, override_settings |
|||
from django.utils.http import urlsafe_base64_encode |
|||
from django.utils.encoding import force_bytes |
|||
from django.urls import reverse |
|||
from rest_framework import status |
|||
from ..forms import SignupForm |
|||
from ..tokens import account_activation_token |
|||
import re |
|||
|
|||
|
|||
@override_settings(STATICFILES_STORAGE='django.contrib.staticfiles.storage.StaticFilesStorage') |
|||
class TestActivate(TestCase): |
|||
def setUp(self): |
|||
# Every test needs access to the request factory. |
|||
self.factory = RequestFactory() |
|||
|
|||
request_POST = {'username': 'username5648', |
|||
'email': 'email@example.com', |
|||
'password1': 'pwd0000Y00$$', |
|||
'password2': 'pwd0000Y00$$'} |
|||
user = SignupForm(request_POST).save(commit=False) |
|||
user.save() |
|||
self.token = account_activation_token.make_token(user) |
|||
self.uid = urlsafe_base64_encode(force_bytes(user.pk)).decode() |
|||
|
|||
def test_activate_invalid(self): |
|||
response = self.client.get(reverse('activate', args=['wrong_uid', 'wrong_token'])) |
|||
self.assertEqual(response.status_code, 200) |
|||
needle = '<p>Activation link is invalid!</p>' |
|||
m = re.search(needle, str(response.content)) |
|||
self.assertTrue(m is None) |
|||
|
|||
def test_activate_valid(self): |
|||
"""we make sure code is for the /projects redirection""" |
|||
response = self.client.get(reverse('activate', args=[self.uid, self.token])) |
|||
# For some reason this get rejected by Travis CI |
|||
# File "/usr/local/lib/python3.6/site-packages/webpack_loader/loader.py", line 26, in _load_assets with open(self.config['STATS_FILE'], encoding="utf-8") as f: |
|||
# FileNotFoundError: [Errno 2] No such file or directory: '/doccano/app/server/static/webpack-stats.json' |
|||
# self.assertRedirects(response, '/projects/') |
|||
self.assertEqual(response.status_code, status.HTTP_302_FOUND) |
@ -1,49 +0,0 @@ |
|||
from django.test import TestCase |
|||
from ..forms import SignupForm |
|||
from ..tokens import account_activation_token |
|||
|
|||
|
|||
class TestSignUp(TestCase): |
|||
form_class = SignupForm |
|||
|
|||
def test_signup(self): |
|||
|
|||
form = self.form_class({ |
|||
'username': 'i_am_a_test_username', |
|||
'email': 'i_am_a_test@email.com', |
|||
'password1': 'fdsfdsfdssd232323&', |
|||
'password2': 'fdsfdsfdssd232323&' |
|||
}) |
|||
self.assertTrue(form.is_valid()) |
|||
user_saved = form.save() |
|||
self.assertEqual(user_saved.username, 'i_am_a_test_username') |
|||
self.assertEqual(user_saved.email, 'i_am_a_test@email.com') |
|||
|
|||
# I guess this is impossible to test password because it gets removed |
|||
# after the form.save() execution |
|||
# self.assertEqual(user_saved.password1, "fdsfdsfdssd232323&") |
|||
# self.assertEqual(user_saved.password2, "fdsfdsfdssd232323&") |
|||
|
|||
def test_blank_signup(self): |
|||
form = self.form_class({}) |
|||
self.assertFalse(form.is_valid()) |
|||
|
|||
self.assertEqual(form.errors, { |
|||
'username': ['This field is required.'], |
|||
'email': ['This field is required.'], |
|||
'password1': ['This field is required.'], |
|||
'password2': ['This field is required.'] |
|||
}) |
|||
|
|||
|
|||
class TestToken(TestCase): |
|||
"""test for token""" |
|||
|
|||
def test_valid_token(self): |
|||
request_POST = {'username': 'username5645', |
|||
'email': 'email@example.com', |
|||
'password1': 'pwd000000', |
|||
'password2': 'pwd000000'} |
|||
user = SignupForm(request_POST).save(commit=False) |
|||
token = account_activation_token.make_token(user) |
|||
self.assertTrue(isinstance(token, str)) |
@ -1,85 +0,0 @@ |
|||
from django.test import SimpleTestCase, TestCase, RequestFactory, override_settings |
|||
from django.http import HttpRequest |
|||
from ..views import SignupView |
|||
from django.conf import settings |
|||
from api.tests.test_config import setenv |
|||
|
|||
@override_settings(STATICFILES_STORAGE='django.contrib.staticfiles.storage.StaticFilesStorage') |
|||
class AddCSSTemplateTagTest(SimpleTestCase): |
|||
|
|||
def test_rendered(self): |
|||
with setenv('ALLOW_SIGNUP', 'True'): |
|||
request = HttpRequest() |
|||
request.method = 'GET' |
|||
needle = '<input type="password" name="password1" class=" input" required id="id_password1">' |
|||
self.assertInHTML(needle, str(SignupView.as_view()(request, as_string=True).content)) |
|||
|
|||
|
|||
@override_settings(STATICFILES_STORAGE='django.contrib.staticfiles.storage.StaticFilesStorage') |
|||
class ViewsTest(SimpleTestCase): |
|||
"""Class for testing views""" |
|||
|
|||
def test_mail_not_set_up(self): |
|||
with setenv('ALLOW_SIGNUP', 'True'): |
|||
if hasattr(settings, 'EMAIL_HOST'): |
|||
has_EMAIL_HOST = True |
|||
EMAIL_HOST = settings.EMAIL_HOST |
|||
delattr(settings, 'EMAIL_HOST') |
|||
else: |
|||
has_EMAIL_HOST = False |
|||
|
|||
if hasattr(settings, 'EMAIL_BACKEND'): |
|||
has_EMAIL_BACKEND = True |
|||
EMAIL_BACKEND = settings.EMAIL_BACKEND |
|||
delattr(settings, 'EMAIL_BACKEND') |
|||
else: |
|||
has_EMAIL_BACKEND = False |
|||
|
|||
request = HttpRequest() |
|||
request.method = 'POST' |
|||
response = SignupView.as_view()(request, as_string=True) |
|||
|
|||
if has_EMAIL_HOST: |
|||
settings.EMAIL_HOST = EMAIL_HOST |
|||
if has_EMAIL_BACKEND: |
|||
settings.EMAIL_BACKEND = EMAIL_BACKEND |
|||
needle = "<span>has not set up any emails</span>" |
|||
self.assertInHTML(needle, str(response.content)) |
|||
|
|||
def test_signup_not_allowed(self): |
|||
with setenv('ALLOW_SIGNUP', 'True'): |
|||
ALLOW_SIGNUP = settings.ALLOW_SIGNUP |
|||
settings.ALLOW_SIGNUP = False |
|||
request = HttpRequest() |
|||
request.method = 'POST' |
|||
response = SignupView.as_view()(request, as_string=True) |
|||
settings.ALLOW_SIGNUP = ALLOW_SIGNUP |
|||
self.assertEqual(response.status_code, 302) |
|||
|
|||
|
|||
@override_settings(STATICFILES_STORAGE='django.contrib.staticfiles.storage.StaticFilesStorage') |
|||
class ViewsDBTest(TestCase): |
|||
"""Class for testing views with DB queries""" |
|||
|
|||
def test_form_submission(self): |
|||
with setenv('ALLOW_SIGNUP', 'True'): |
|||
self.factory = RequestFactory() |
|||
if hasattr(settings, 'EMAIL_BACKEND'): |
|||
EMAIL_BACKEND = settings.EMAIL_BACKEND |
|||
else: |
|||
EMAIL_BACKEND = False |
|||
|
|||
settings.EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' |
|||
request = self.factory.post('/signup') |
|||
request.POST = {'username': 'username5648', |
|||
'email': 'email@example.com', |
|||
'password1': 'pwd0000Y00$$', |
|||
'password2': 'pwd0000Y00$$' |
|||
} |
|||
response = SignupView.as_view()(request) |
|||
needle = '<span>emailed you instructions to activate your account</span>' |
|||
if not EMAIL_BACKEND: |
|||
delattr(settings, 'EMAIL_BACKEND') |
|||
else: |
|||
settings.EMAIL_BACKEND = EMAIL_BACKEND |
|||
self.assertInHTML(needle, str(response.content)) |
@ -1,13 +0,0 @@ |
|||
from django.contrib.auth.tokens import PasswordResetTokenGenerator |
|||
from django.utils import six |
|||
|
|||
|
|||
class TokenGenerator(PasswordResetTokenGenerator): |
|||
def _make_hash_value(self, user, timestamp): |
|||
return ( |
|||
six.text_type(user.pk) + six.text_type(timestamp) + |
|||
six.text_type(user.is_active) |
|||
) |
|||
|
|||
|
|||
account_activation_token = TokenGenerator() |
@ -1,18 +0,0 @@ |
|||
from django.contrib.auth.views import (PasswordResetCompleteView, |
|||
PasswordResetConfirmView, |
|||
PasswordResetDoneView) |
|||
from django.urls import path |
|||
|
|||
from .utils import activate |
|||
from .views import SignupView |
|||
|
|||
urlpatterns = [ |
|||
path('password_reset/done/', PasswordResetDoneView.as_view(), |
|||
name='password_reset_done'), |
|||
path('reset/done/', PasswordResetCompleteView.as_view(), |
|||
name='password_reset_complete'), |
|||
path('reset/<uidb64>/<token>/', PasswordResetConfirmView.as_view(), |
|||
name='password_reset_confirm'), |
|||
path('signup/', SignupView.as_view(), name='signup'), |
|||
path('activate/<str:uidb64>/<str:token>', activate, name='activate'), |
|||
] |
@ -1,24 +0,0 @@ |
|||
from django.contrib.auth import get_user_model, login |
|||
from django.shortcuts import redirect, render |
|||
from django.utils.encoding import force_text |
|||
from django.utils.http import urlsafe_base64_decode |
|||
|
|||
from .tokens import account_activation_token |
|||
|
|||
User = get_user_model() |
|||
|
|||
|
|||
def activate(request, uidb64, token): |
|||
try: |
|||
uid = force_text(urlsafe_base64_decode(uidb64)) |
|||
user = User.objects.get(pk=uid) |
|||
except(TypeError, ValueError, OverflowError, User.DoesNotExist): |
|||
user = None |
|||
if user is not None and account_activation_token.check_token(user, token): |
|||
user.is_active = True |
|||
user.save() |
|||
user.backend = 'django.contrib.auth.backends.ModelBackend' |
|||
login(request=request, user=user,) |
|||
return redirect('projects') |
|||
else: |
|||
return render(request, 'validate_mail_address_invalid.html') |
@ -1,52 +0,0 @@ |
|||
from django.conf import settings |
|||
from django.contrib.sites.shortcuts import get_current_site |
|||
from django.core.mail import EmailMessage |
|||
from django.shortcuts import redirect, render |
|||
from django.template.loader import render_to_string |
|||
from django.utils.encoding import force_bytes |
|||
from django.utils.http import urlsafe_base64_encode |
|||
from django.views.generic import TemplateView |
|||
|
|||
from .forms import SignupForm |
|||
from .tokens import account_activation_token |
|||
|
|||
|
|||
class SignupView(TemplateView): |
|||
template_name = 'signup.html' |
|||
form_class = SignupForm |
|||
|
|||
def get(self, request, *args, **kwargs): |
|||
form = self.form_class() |
|||
return render(request, self.template_name, {'form': form, 'allow_signup': bool(settings.ALLOW_SIGNUP)}) |
|||
|
|||
def post(self, request, *args, **kwargs): |
|||
form = self.form_class(request.POST) |
|||
|
|||
# here we make sure that a post request won't trigger a subscription in case allow_signup is False |
|||
if not bool(settings.ALLOW_SIGNUP): |
|||
return redirect('signup') |
|||
|
|||
if not hasattr(settings, "EMAIL_BACKEND") and not hasattr(settings, "EMAIL_HOST"): |
|||
return render(request, 'email_not_set.html') |
|||
|
|||
if form.is_valid(): |
|||
user = form.save(commit=False) |
|||
user.is_active = False |
|||
user.save() |
|||
current_site = get_current_site(request) |
|||
mail_subject = 'Activate your account.' |
|||
message = render_to_string('acc_active_email.html', { |
|||
'user': user, |
|||
'domain': current_site.domain, |
|||
'scheme': request.scheme, |
|||
'uid': urlsafe_base64_encode(force_bytes(user.pk)).decode(), |
|||
'token': account_activation_token.make_token(user), |
|||
}) |
|||
to_email = form.cleaned_data.get('email') |
|||
email = EmailMessage( |
|||
mail_subject, message, to=[to_email] |
|||
) |
|||
email.send() |
|||
return render(request, 'validate_mail_address_complete.html') |
|||
else: |
|||
return render(request, self.template_name, {'form': form, 'allow_signup': bool(settings.ALLOW_SIGNUP)}) |
Write
Preview
Loading…
Cancel
Save