Skip to content

Commit

Permalink
Merge branch 'develop' into bugfix/mixcript-priority
Browse files Browse the repository at this point in the history
  • Loading branch information
AntonioRodriguezRuiz committed Dec 19, 2023
2 parents af42645 + acf94f2 commit 7ac945c
Show file tree
Hide file tree
Showing 11 changed files with 286 additions and 11 deletions.
2 changes: 2 additions & 0 deletions decide/authentication/templates/authentication/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@
Continuar con GitHub
</a>
</div>

<a href="/password_reset">Recuperar Contraseña</a>
</section>

{% endblock %}
46 changes: 46 additions & 0 deletions decide/authentication/templates/authentication/password_reset.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{% extends "base.html" %}
{% load i18n static %}

{% block title %}Restore password{% endblock %}

{% block extrahead %}
<link rel="stylesheet" href="{% static "auth/style.css" %}">
{% endblock %}

{% block content %}
<section class="card form-card">
<section class="form-title"></section>
<section class="form-msg">
<h3>
Recuperar Contraseña
</h3>
{% if form.email.errors %}
<div class="form-errors">
<p>
{{ form.email.errors.0 }}
</p>
</div>
{% endif %}
{% if messages %}
<div class="form-errors">
{% for message in messages %}
<p>{{ message }}</p>
{% endfor %}
</div>
{% endif %}
</section>
<form method="post">
{% csrf_token %}
<section class="form-content">
<div class="input-group">
<label for="id_email">Email:</label>
{{ form.email }}
</div>
</section>
<section class="form-confirmation">
<button type="submit" class="btn btn-primary" style="width: 200px; align-self: center;">Recuperar Contraseña</button>
</section>
</form>
</section>

{% endblock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{% extends "base.html" %}
{% load i18n static %}

{% block title %}Restore password{% endblock %}

{% block extrahead %}
<link rel="stylesheet" href="{% static "auth/style.css" %}">
{% endblock %}

{% block content %}
<section class="card form-card">
<section class="form-title"></section>
<section class="form-msg">
<h3>
Recuperar Contraseña
</h3>
</section>
<section class="form-content">
<p>Contraseña restarurada. Ahora puedes hacer acceder con tu nueva contraseña.</p>
</section>
</section>

{% endblock %}

Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{% extends "base.html" %}
{% load i18n static %}

{% block title %}Restore password{% endblock %}

{% block extrahead %}
<link rel="stylesheet" href="{% static "auth/style.css" %}">
{% endblock %}

{% block content %}
{% if validlink %}
<section class="card form-card">
<section class="form-title"></section>
<section class="form-msg">
<h3 style="align-self: center;">
Recuperar Contraseña
</h3>
{% if form.new_password1.errors %}
<div class="form-errors">
<p>
{{ form.new_password1.errors.0 }}
</p>
</div>
{% endif %}
{% if form.new_password2.errors %}
<div class="form-errors">
<p>
{{ form.new_password2.errors.0 }}
</p>
</div>
{% endif %}
</section>
<form method="post">
{% csrf_token %}
<section class="form-content">
<div class="input-group">
<label for="id_new_password1">Nueva contraseña:</label>
{{ form.new_password1 }}
</div>
<div class="input-group">
<label for="id_new_password2">Confirme contraseña:</label>
{{ form.new_password2 }}
</div>
</section>
<section class="form-confirmation">
<button type="submit" class="btn btn-primary" style="width: 200px; align-self: center;">Cambiar Contraseña</button>
</section>
</form>
</section>

{% else %}
<section class="card form-card">
<section class="form-content">
<p>
El link ya no está disponible, probablemete porque ya ha sido utilizado o ha expirado.
</p>
</section>
</section>
{% endif %}

{% endblock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{% extends "base.html" %}
{% load i18n static %}

{% block title %}Restore password{% endblock %}

{% block extrahead %}
<link rel="stylesheet" href="{% static "auth/style.css" %}">
{% endblock %}

{% block content %}
<section class="card form-card">
<section class="form-title"></section>
<section class="form-msg">
<h3>
Recuperar Contraseña
</h3>
</section>
<section class="form-content">
<p>Se ha enviado un correo a tu email para resetear la contraseña. Revisa tu correo y sigue las instrucciones.</p>
</section>
</section>

{% endblock %}
38 changes: 33 additions & 5 deletions decide/authentication/test-selenium.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ def setUp(self):
options.headless = True
options.add_argument("--no-sandbox")
self.driver = webdriver.Chrome(options=options)
self.user = User.objects.create_user(username="testuser", password="testpass")
self.user = User.objects.create_user(
username="testuser", password="testpass", email="test@email.com"
)
super().setUp()

app = SocialApp.objects.create(
Expand All @@ -68,6 +70,36 @@ def tearDown(self):

self.base.tearDown()

def test_password_reset(self):
self.driver.get(f"{self.live_server_url}/signin")

self.driver.find_element(By.LINK_TEXT, "Recuperar Contraseña").click()

self.assertEqual(
self.driver.current_url,
f"{self.live_server_url}/password_reset/",
)
self.driver.find_element(By.ID, "id_email").send_keys("test@email.com")
self.driver.find_element(By.CSS_SELECTOR, ".btn").click()

self.assertEqual(
self.driver.current_url,
f"{self.live_server_url}/authentication/password_reset_done/",
)

def test_password_reset_unknown_email(self):
self.driver.get(f"{self.live_server_url}/signin")

self.driver.find_element(By.LINK_TEXT, "Recuperar Contraseña").click()

self.driver.find_element(By.ID, "id_email").send_keys("unknown@email.com")
self.driver.find_element(By.CSS_SELECTOR, ".btn").click()

self.assertEqual(
self.driver.current_url,
f"{self.live_server_url}/password_reset/",
)

def test_sucessful_login(self):
self.driver.get(f"{self.live_server_url}/signin")

Expand Down Expand Up @@ -147,10 +179,6 @@ def test_sucessful_login(self):
self.driver.get(f"{self.live_server_url}/signin")

self.driver.find_element(By.CSS_SELECTOR, ".google-button").click()
self.assertEqual(
self.driver.current_url,
f"{self.live_server_url}/authentication/accounts/google/login/",
)


class LoginGithubTestCase(StaticLiveServerTestCase):
Expand Down
31 changes: 31 additions & 0 deletions decide/authentication/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from django.urls import reverse
from unittest import mock
from rest_framework.test import APIClient, APITestCase
from django.contrib.messages import get_messages

from .forms import TestLoginForm, TestRegisterForm

Expand Down Expand Up @@ -269,3 +270,33 @@ def test_change_password_view_failure(self):
)
self.user.refresh_from_db()
self.assertTrue(self.user.check_password("testpass"))


class ResetPasswordViewTestCase(TestCase):
def setUp(self):
self.user = User.objects.create_user(
username="passuser", password="testpass", email="test@example.com"
)
self.url = reverse("password_reset")

# Disable recaptcha
os.environ["DISABLE_RECAPTCHA"] = "1"

def test_form_valid_with_existing_email(self):
email = self.user.email
data = {"email": email}

response = self.client.post(self.url, data)
self.assertEqual(response.status_code, 302)
self.assertRedirects(response, reverse("password_reset_done"))

def test_form_valid_with_non_existing_email(self):
data = {"email": "nonexisting@example.com"}

response = self.client.post(self.url, data)

self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "authentication/password_reset.html")
messages = list(get_messages(response.wsgi_request))
self.assertEqual(len(messages), 1)
self.assertEqual(str(messages[0]), "Este email no esta registrado")
33 changes: 33 additions & 0 deletions decide/authentication/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,16 @@
LogoutView,
RegisterView,
ChangePasswordView,
ResetPasswordView,
EmailView,
)

from django.contrib.auth.views import (
PasswordResetDoneView,
PasswordResetCompleteView,
PasswordResetConfirmView,
)

urlpatterns = [
path("login/", obtain_auth_token),
path("signin/", LoginView.as_view(), name="signin"),
Expand All @@ -19,5 +26,31 @@
path("register/", RegisterView.as_view(), name="register"),
path("verificar/<str:user_encode>/", EmailView.emailCheck),
path("change-password/", ChangePasswordView.as_view(), name="change-password"),
path(
"password_reset/",
ResetPasswordView.as_view(template_name="authentication/password_reset.html"),
name="password_reset",
),
path(
"password_reset_done/",
PasswordResetDoneView.as_view(
template_name="authentication/password_reset_done.html"
),
name="password_reset_done",
),
path(
"password_reset_confirm/<uidb64>/<token>/",
PasswordResetConfirmView.as_view(
template_name="authentication/password_reset_confirm.html"
),
name="password_reset_confirm",
),
path(
"password_reset_complete/",
PasswordResetCompleteView.as_view(
template_name="authentication/password_reset_complete.html"
),
name="password_reset_complete",
),
path("social-auth/", include("social_django.urls", namespace="social_auth")),
]
20 changes: 20 additions & 0 deletions decide/authentication/views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import os
import base64
import socket
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.views import PasswordChangeView
Expand All @@ -20,6 +22,12 @@

import os

from django.contrib.auth.models import User
from django.contrib.auth.views import (
PasswordResetView,
)
from django.contrib import messages


# Non-api view
class LoginView(TemplateView):
Expand Down Expand Up @@ -141,3 +149,15 @@ def emailCheck(request, **kwargs):
class ChangePasswordView(PasswordChangeView):
template_name = "authentication/change_password.html"
success_url = "/"


class ResetPasswordView(PasswordResetView):
def form_valid(self, form):
email = form.cleaned_data.get("email")
if User.objects.filter(email=email).exists():
return super().form_valid(form)
else:
messages.error(self.request, "Este email no esta registrado")
return render(
self.request, "authentication/password_reset.html", {"form": form}
)
16 changes: 11 additions & 5 deletions decide/decide/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
"allauth.socialaccount",
"allauth.socialaccount.providers.google",
"social_django",
"django_rest_passwordreset",
"django_recaptcha",
]

Expand Down Expand Up @@ -209,18 +210,23 @@

STATIC_URL = "/static/"

STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
]


# number of bits for the key, all auths should use the same number of bits
KEYBITS = 256

# Versioning
ALLOWED_VERSIONS = ["v1", "v2"]
DEFAULT_VERSION = "v1"


# Restore password
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "smtp.gmail.com"
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = os.getenv("EMAIL_HOST_USER", "")
EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD", "")


try:
from local_settings import *
except ImportError:
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ whitenoise==6.5.0
gunicorn==21.2.0
social-auth-app-django
locust==2.20.0
sendgrid
sendgrid
django-rest-passwordreset==1.3.0

0 comments on commit 7ac945c

Please sign in to comment.