From 578d604ab8419c7634cb1cf1213f4add9a1a9b61 Mon Sep 17 00:00:00 2001 From: Elliot Axel Noriega Date: Mon, 12 Aug 2024 11:06:14 -0600 Subject: [PATCH 1/5] Cambio de logica de navigate --- cosiap_frontend/src/components/users/Login/Login.jsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cosiap_frontend/src/components/users/Login/Login.jsx b/cosiap_frontend/src/components/users/Login/Login.jsx index a142106..2c90335 100644 --- a/cosiap_frontend/src/components/users/Login/Login.jsx +++ b/cosiap_frontend/src/components/users/Login/Login.jsx @@ -7,20 +7,19 @@ import { LoginForm } from './LoginForm'; export function Login( {setViewPageLoader} ) { const navigate = useNavigate(); - function navigateRegister(){ - navigate('register'); - } - return (

¿Haz olvidado tu contraseña?

+

navigate('reset_password')}> + Reestablecer contraseña +

¿Aun no tienes cuenta?

-

+

navigate('register')}> Registrate

-- GitLab From 7340d6221f8e423f3489646de0fc76c4793b07d1 Mon Sep 17 00:00:00 2001 From: Elliot Axel Noriega Date: Mon, 12 Aug 2024 11:07:38 -0600 Subject: [PATCH 2/5] Cambio de url de google icons --- cosiap_frontend/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cosiap_frontend/index.html b/cosiap_frontend/index.html index 5649738..51bac2d 100644 --- a/cosiap_frontend/index.html +++ b/cosiap_frontend/index.html @@ -5,7 +5,7 @@ - + Sistema de apoyos COZCyT -- GitLab From cc0c8356cf6fb98ba7c650fb342c87e747ea0d6a Mon Sep 17 00:00:00 2001 From: Elliot Axel Noriega Date: Mon, 12 Aug 2024 11:10:25 -0600 Subject: [PATCH 3/5] =?UTF-8?q?Primera=20parte=20de=20funcionalidad=20de?= =?UTF-8?q?=20reestablecer=20contrase=C3=B1a?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cosiap_api/users/views.py | 3 +- cosiap_frontend/src/App.jsx | 2 + cosiap_frontend/src/api.js | 4 +- .../src/components/FormsValidations.jsx | 11 +++ .../users/Password/NewPasswordForm.jsx | 92 +++++++++++++++++++ .../users/Password/ResetPassword.jsx | 78 ++++++++++++++++ .../users/Password/ResetPasswordForm.jsx | 79 ++++++++++++++++ 7 files changed, 266 insertions(+), 3 deletions(-) create mode 100644 cosiap_frontend/src/components/users/Password/NewPasswordForm.jsx create mode 100644 cosiap_frontend/src/components/users/Password/ResetPassword.jsx create mode 100644 cosiap_frontend/src/components/users/Password/ResetPasswordForm.jsx diff --git a/cosiap_api/users/views.py b/cosiap_api/users/views.py index 09a19f8..3167985 100644 --- a/cosiap_api/users/views.py +++ b/cosiap_api/users/views.py @@ -197,6 +197,7 @@ class NuevaPassword(APIView): response_data = {} try: uid = urlsafe_base64_decode(uidb64).decode() + print(uid) usuario = Usuario.objects.get(pk=uid) except (TypeError, ValueError, OverflowError, Usuario.DoesNotExist): usuario = None @@ -221,7 +222,7 @@ def enviar_correo_reset_password(email, uid, token): - token (token de restablecimiento de contraseña) """ subject = 'Restablecer contraseña' - message = f'Para restablecer tu contraseña, haz click en confirmar:\n\n{settings.BASE_URL}api/usuarios/nueva-password/{uid}/{token}/' + message = f'Para restablecer tu contraseña, haz click en el siguiente enlace:\n\nhttp://localhost:5173/authentication/reset_password?uid={uid}&token={token}' from_email = settings.EMAIL_HOST_USER recipient_list = [email] send_mail(subject, message, from_email, recipient_list) diff --git a/cosiap_frontend/src/App.jsx b/cosiap_frontend/src/App.jsx index aca4efd..c676329 100644 --- a/cosiap_frontend/src/App.jsx +++ b/cosiap_frontend/src/App.jsx @@ -6,6 +6,7 @@ import "./App.css"; import PageLoader from '@/components/common/ui/PageLoader'; import { Login } from './components/users/Login/Login'; import Register from './components/users/Register/Register'; +import ResetPassword from './components/users/Password/ResetPassword'; import Inicio from "./components/users/Inicio"; import { useState } from 'react'; @@ -31,6 +32,7 @@ function App() { } /> } /> } /> + } /> {/* Rutas protegidas */} }> diff --git a/cosiap_frontend/src/api.js b/cosiap_frontend/src/api.js index 7cd0b33..26b0c72 100644 --- a/cosiap_frontend/src/api.js +++ b/cosiap_frontend/src/api.js @@ -52,8 +52,8 @@ const api = { delete: (id) => ax.delete(`api/usuarios/${id}`), verificarCorreo: (uidb64, token) => ax.get(`api/usuarios/verificar-correo/${uidb64}/${token}`), - restablecerPassoword: (data) => ax.post(`api/usuarios/restablecer-password`, data), - nuevaPassword: (uidb64, token, data) => ax.get(`api/usuarios/nueva-password/${uidb64}/${token}`, data), + restablecerPassword: (data) => ax.post(`api/usuarios/restablecer-password/`, data), + nuevaPassword: (uidb64, token, data) => ax.post(`api/usuarios/nueva-password/${uidb64}/${token}/`, data), administradores: { get: () => ax.get('api/usuarios/administradores'), diff --git a/cosiap_frontend/src/components/FormsValidations.jsx b/cosiap_frontend/src/components/FormsValidations.jsx index 785a51a..076e4e8 100644 --- a/cosiap_frontend/src/components/FormsValidations.jsx +++ b/cosiap_frontend/src/components/FormsValidations.jsx @@ -44,3 +44,14 @@ export const RegisterValidationSchema = Yup.object({ password: PASSWORD_CREATION_VALIDATION, confirmar_password: CONFIRM_PASSWORD_VALIDATION }); + +export const ResetPasswordValidationSchema = Yup.object().shape({ + email: Yup.string() + .required("El correo electronico es requerido") + .email("El correo electronico no es válido") +}); + +export const NewPasswordValidationSchema = Yup.object().shape({ + password: PASSWORD_CREATION_VALIDATION, + confirmar_password: CONFIRM_PASSWORD_VALIDATION +}); diff --git a/cosiap_frontend/src/components/users/Password/NewPasswordForm.jsx b/cosiap_frontend/src/components/users/Password/NewPasswordForm.jsx new file mode 100644 index 0000000..9a8d8ca --- /dev/null +++ b/cosiap_frontend/src/components/users/Password/NewPasswordForm.jsx @@ -0,0 +1,92 @@ +import { useState } from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import { NewPasswordValidationSchema } from "@/components/FormsValidations"; +import { RegisterInputPassword } from "@/components/users/Register/RegisterInputPassword"; +import ErrorDisplay from "@/components/common/ui/ErrorDisplay"; +import api from "@/api"; + +export default function NewPasswordForm ({uid, token, setViewPageLoader}){ + // Para cambiar de componente si la creación de la nueva contraseña fue exitosa + const [successChangePassword, setSuccessChangePassword] = useState(false); + // Error de la creacion de contraseña desde back + const [errorNewPassword, setErrorNewPassword] = useState(''); + const { + register, + handleSubmit, + formState: { errors, isSubmitting }, + } = useForm({ + resolver: yupResolver(NewPasswordValidationSchema), + }); + + const handleFormSubmission = async (data) => { + setViewPageLoader(true); + try { + const response = await api.usuarios.nuevaPassword(uid, token, data) + console.log('Password change successful', response.data); + setSuccessChangePassword(true); + } catch (error) { + console.error('Password change failed', error); + setErrorNewPassword(error.response.data.messages.error); + } + setViewPageLoader(false); + } + + return ( + successChangePassword ? + ( + <> +
+
+

¡CAMBIO DE CONTRASEÑA REALIZADO CON EXITO!

+
+
+

SE HA REESTABLECIDO TU CONTRASEÑA, INICIA SESIÓN CON TUS CREDENCIALES

+
+
+ +
+
+ + ) + : + ( + <> + +
+
+ +
+
+ +
+
+ +
+
+ + + ) + ); +} \ No newline at end of file diff --git a/cosiap_frontend/src/components/users/Password/ResetPassword.jsx b/cosiap_frontend/src/components/users/Password/ResetPassword.jsx new file mode 100644 index 0000000..9069a02 --- /dev/null +++ b/cosiap_frontend/src/components/users/Password/ResetPassword.jsx @@ -0,0 +1,78 @@ +import LayoutBaseAuthenticator from "@/components/common/layouts/LayoutBaseAuthenticator"; +import ResetPasswordForm from "./ResetPasswordForm"; +import { useState, useEffect } from "react"; +import { useNavigate, useLocation } from "react-router-dom"; +import NewPasswordForm from "./NewPasswordForm"; + +export default function ResetPassword({ setViewPageLoader }){ + // false se mantiene en el formulario de envio de correo + // true se establece al formulario de creacion de nueva contraseña + const [viewChangePasswordForm, setChangePasswordForm] = useState(false); + // Definimos las variables necesarios en el componente de NewPassword + let uid = null; + let token = null; + // Para cambiar de url + const navigate = useNavigate(); + // Informacion de la url + const location = useLocation(); + + useEffect (() => { + //Parametros mandados de la url, con clave - valor + const queryParams = new URLSearchParams(location.search); + // isEmpty será true si queryParams no tiene ningún parámetro y false si tiene al menos uno. + const isEmpty = ![...queryParams].length; + + if (!isEmpty){ + if (queryParams.has('uid') && queryParams.has('token')) { // Si la url contiene esos dos parametros + handleParamsChangePassword(queryParams) + } + // Limpia los parámetros de la URL + // Redirige a la misma página sin parámetros + navigate(location.pathname, { replace: true }); + } + + },[location]); // Se ejecutara si location cambia + + // Funcion para procesar los parametros para cambiar la contraseña en la api + const handleParamsChangePassword = (queryParams) => { + // Obtenemos y establecemos los valores de los parametros + uid = queryParams.get('uid'); + token = queryParams.get('token'); + //Declaramos a true para confirmar que la url que se ingreso es para realizar un cambio de contraseña + setChangePasswordForm(true); + } + + return ( + +
+
+ { + viewChangePasswordForm ? ( + <> + + + ) : ( + <> +
+

+ Se le enviara un correo para restablecer la contraseña +

+
+ + + ) + } + +
+
+ +
+ ); + +} \ No newline at end of file diff --git a/cosiap_frontend/src/components/users/Password/ResetPasswordForm.jsx b/cosiap_frontend/src/components/users/Password/ResetPasswordForm.jsx new file mode 100644 index 0000000..cc3f253 --- /dev/null +++ b/cosiap_frontend/src/components/users/Password/ResetPasswordForm.jsx @@ -0,0 +1,79 @@ +import { useState } from "react"; +import { useForm } from "react-hook-form"; +import { ResetPasswordValidationSchema } from "@/components/FormsValidations"; +import { yupResolver } from "@hookform/resolvers/yup"; +import { RegisterInput } from "@/components/users/Register/RegisterInput"; +import { useNavigate } from "react-router-dom"; +import api from "@/api"; + +export default function ResetPasswordForm({ setViewPageLoader }){ + const navigate = useNavigate(); + + const [emailSent, setEmailSent] = useState(false); + const [formError, setFormError] = useState(''); + const { + register, + handleSubmit, + formState: { errors, isSubmitting }, + } = useForm({ + resolver: yupResolver(ResetPasswordValidationSchema), + }); + + const handleFormSubmission = async (data) => { + setViewPageLoader(true); + + try { + const response = await api.usuarios.restablecerPassword(data); + console.log('Password reset succesfuly: ', response.data); + setEmailSent(true); + } catch (error) { + console.error('Password reset failed: ', error); + console.log(error.response.data); + setFormError(error.response.data); + } + setViewPageLoader(false); + } + return ( + emailSent ? ( + <> +
+

+ ¡Correo enviado con exito!
Revisa tu bandeja para seguir con el proceso de restablecimiento +

+
+
+ +
+ + ) : ( + <> +
+
+ +
+
+ +
+
+

navigate('/authentication')}> + Iniciar sesión +

+ + ) + + ); +} \ No newline at end of file -- GitLab From 0dab57b84285a77b59cd28b78379050823be3adc Mon Sep 17 00:00:00 2001 From: Elliot Axel Noriega Date: Mon, 12 Aug 2024 13:18:32 -0600 Subject: [PATCH 4/5] =?UTF-8?q?Funcionalidad=20completada=20de=20reestable?= =?UTF-8?q?cer=20contrase=C3=B1a?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cosiap_api/users/views.py | 1 - .../src/components/users/Password/NewPasswordForm.jsx | 4 ++++ .../src/components/users/Password/ResetPassword.jsx | 10 ++++++---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/cosiap_api/users/views.py b/cosiap_api/users/views.py index 3167985..8d135e6 100644 --- a/cosiap_api/users/views.py +++ b/cosiap_api/users/views.py @@ -197,7 +197,6 @@ class NuevaPassword(APIView): response_data = {} try: uid = urlsafe_base64_decode(uidb64).decode() - print(uid) usuario = Usuario.objects.get(pk=uid) except (TypeError, ValueError, OverflowError, Usuario.DoesNotExist): usuario = None diff --git a/cosiap_frontend/src/components/users/Password/NewPasswordForm.jsx b/cosiap_frontend/src/components/users/Password/NewPasswordForm.jsx index 9a8d8ca..9a3b294 100644 --- a/cosiap_frontend/src/components/users/Password/NewPasswordForm.jsx +++ b/cosiap_frontend/src/components/users/Password/NewPasswordForm.jsx @@ -4,9 +4,13 @@ import { yupResolver } from "@hookform/resolvers/yup"; import { NewPasswordValidationSchema } from "@/components/FormsValidations"; import { RegisterInputPassword } from "@/components/users/Register/RegisterInputPassword"; import ErrorDisplay from "@/components/common/ui/ErrorDisplay"; +import { useNavigate } from "react-router-dom"; import api from "@/api"; export default function NewPasswordForm ({uid, token, setViewPageLoader}){ + // Para cambiar de url + const navigate = useNavigate(); + // Para cambiar de componente si la creación de la nueva contraseña fue exitosa const [successChangePassword, setSuccessChangePassword] = useState(false); // Error de la creacion de contraseña desde back diff --git a/cosiap_frontend/src/components/users/Password/ResetPassword.jsx b/cosiap_frontend/src/components/users/Password/ResetPassword.jsx index 9069a02..e997e77 100644 --- a/cosiap_frontend/src/components/users/Password/ResetPassword.jsx +++ b/cosiap_frontend/src/components/users/Password/ResetPassword.jsx @@ -9,13 +9,14 @@ export default function ResetPassword({ setViewPageLoader }){ // true se establece al formulario de creacion de nueva contraseña const [viewChangePasswordForm, setChangePasswordForm] = useState(false); // Definimos las variables necesarios en el componente de NewPassword - let uid = null; - let token = null; + const [uid, setUid] = useState(''); + const [token, setToken] = useState(''); // Para cambiar de url const navigate = useNavigate(); // Informacion de la url const location = useLocation(); + useEffect (() => { //Parametros mandados de la url, con clave - valor const queryParams = new URLSearchParams(location.search); @@ -36,8 +37,9 @@ export default function ResetPassword({ setViewPageLoader }){ // Funcion para procesar los parametros para cambiar la contraseña en la api const handleParamsChangePassword = (queryParams) => { // Obtenemos y establecemos los valores de los parametros - uid = queryParams.get('uid'); - token = queryParams.get('token'); + setUid(queryParams.get('uid')); + setToken(queryParams.get('token')); + //Declaramos a true para confirmar que la url que se ingreso es para realizar un cambio de contraseña setChangePasswordForm(true); } -- GitLab From e06397ef25c46af5bf487312b3697bad4950c195 Mon Sep 17 00:00:00 2001 From: Elliot Axel Noriega Date: Mon, 12 Aug 2024 18:26:56 -0600 Subject: [PATCH 5/5] Reajuste de estilos --- .../layouts/LayoutBaseAuthenticator.jsx | 4 +- .../users/Password/ResetPassword.jsx | 49 +++++++++---------- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/cosiap_frontend/src/components/common/layouts/LayoutBaseAuthenticator.jsx b/cosiap_frontend/src/components/common/layouts/LayoutBaseAuthenticator.jsx index 8523ff4..6ea0ecf 100644 --- a/cosiap_frontend/src/components/common/layouts/LayoutBaseAuthenticator.jsx +++ b/cosiap_frontend/src/components/common/layouts/LayoutBaseAuthenticator.jsx @@ -20,12 +20,12 @@ export default function LayoutBaseAuthenticator({title, children}) { {/* Contenido de authentication */}
-
+
-
-
- { - viewChangePasswordForm ? ( - <> - - - ) : ( - <> -
-

- Se le enviara un correo para restablecer la contraseña -

-
- - - ) - } - -
+
+ { + viewChangePasswordForm ? ( + <> + + + ) : ( + <> +
+

+ Se le enviara un correo para restablecer la contraseña +

+
+ + + ) + }
-- GitLab