Skip to content

Commit c19d6bc

Browse files
committed
fix: Fixes and refactors SignUp, Reset and Mail Services. Closes #62
1 parent 72f6694 commit c19d6bc

File tree

23 files changed

+293
-94
lines changed

23 files changed

+293
-94
lines changed

.env.docker.example

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ FLASK_APP_NAME="UVLHUB.IO(dev)"
22
FLASK_ENV=development
33
FLASK_APP=app
44
SECRET_KEY=dev_test_key_1234567890abcdefghijklmnopqrstu
5-
DOMAIN=localhost
5+
SERVER_NAME=localhost
66
MARIADB_HOSTNAME=db
77
MARIADB_PORT=3306
88
MARIADB_DATABASE=uvlhubdb
@@ -13,3 +13,12 @@ MARIADB_ROOT_PASSWORD=uvlhubdb_root_password
1313
WORKING_DIR=/app/
1414
REDIS_URL=redis://redis:6379
1515
REDIS_WORKER_TIMEOUT=180
16+
MAIL_SERVER="mailhog"
17+
MAIL_PORT=1025
18+
MAIL_USE_TLS=False
19+
MAIL_USE_SSL=False
20+
MAIL_DEBUG=True
21+
MAIL_USERNAME=""
22+
MAIL_PASSWORD=""
23+
MAIL_DEFAULT_SENDER="dev@mailhog"
24+
ZENODO_ACCESS_TOKEN=<CHANGE_THIS>

.env.docker.production.example

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ FLASK_APP_NAME="UVLHUB.IO"
22
FLASK_ENV=production
33
FLASK_APP=app
44
SECRET_KEY=<CHANGE_THIS>
5-
DOMAIN=<CHANGE_THIS>
5+
SERVER_NAME=<CHANGE_THIS>
66
MARIADB_HOSTNAME=db
77
MARIADB_PORT=3306
88
MARIADB_DATABASE=uvlhubdb
@@ -12,4 +12,12 @@ MARIADB_ROOT_PASSWORD=<CHANGE_THIS>
1212
WEBHOOK_TOKEN=<CHANGE_THIS>
1313
WORKING_DIR=/app/
1414
REDIS_URL=redis://redis:6379
15-
REDIS_WORKER_TIMEOUT=180
15+
REDIS_WORKER_TIMEOUT=180
16+
MAIL_SERVER=<CHANGE_THIS>
17+
MAIL_PORT=<CHANGE_THIS>
18+
MAIL_USE_TLS=False
19+
MAIL_USE_SSL=False
20+
MAIL_USERNAME=<CHANGE_THIS>
21+
MAIL_PASSWORD=<CHANGE_THIS>
22+
MAIL_DEFAULT_SENDER=<CHANGE_THIS>
23+
ZENODO_ACCESS_TOKEN=<CHANGE_THIS>

.env.docker.production.webhook.example

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ FLASK_APP_NAME="UVLHUB.IO"
22
FLASK_ENV=production
33
FLASK_APP=app
44
SECRET_KEY=<CHANGE_THIS>
5-
DOMAIN=<CHANGE_THIS>
5+
SERVER_NAME=<CHANGE_THIS>
66
MARIADB_HOSTNAME=db
77
MARIADB_PORT=3306
88
MARIADB_DATABASE=uvlhubdb
@@ -13,4 +13,12 @@ WEBHOOK_TOKEN=<CHANGE_THIS>
1313
WORKING_DIR=/app/
1414
REDIS_URL=redis://redis:6379
1515
REDIS_WORKER_TIMEOUT=180
16+
MAIL_SERVER=<CHANGE_THIS>
17+
MAIL_PORT=<CHANGE_THIS>
18+
MAIL_USE_TLS=False
19+
MAIL_USE_SSL=False
20+
MAIL_USERNAME=<CHANGE_THIS>
21+
MAIL_PASSWORD=<CHANGE_THIS>
22+
MAIL_DEFAULT_SENDER=<CHANGE_THIS>
23+
ZENODO_ACCESS_TOKEN=<CHANGE_THIS>
1624
WEBHOOK_TOKEN=<CHANGE_THIS>

.env.local.example

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ FLASK_APP_NAME="UVLHUB.IO(dev)"
22
FLASK_ENV=development
33
FLASK_APP=app
44
SECRET_KEY=dev_test_key_1234567890abcdefghijklmnopqrstu
5-
DOMAIN=localhost:5000
5+
SERVER_NAME=localhost:5000
66
MARIADB_HOSTNAME=localhost
77
MARIADB_PORT=3306
88
MARIADB_DATABASE=uvlhubdb
@@ -12,4 +12,12 @@ MARIADB_PASSWORD=uvlhubdb_password
1212
MARIADB_ROOT_PASSWORD=uvlhubdb_root_password
1313
WORKING_DIR=""
1414
REDIS_URL=redis://localhost:6379
15-
REDIS_WORKER_TIMEOUT=180
15+
REDIS_WORKER_TIMEOUT=180
16+
MAIL_SERVER=<CHANGE_THIS>
17+
MAIL_PORT=<CHANGE_THIS>
18+
MAIL_USE_TLS=False
19+
MAIL_USE_SSL=False
20+
MAIL_USERNAME=<CHANGE_THIS>
21+
MAIL_PASSWORD=<CHANGE_THIS>
22+
MAIL_DEFAULT_SENDER=<CHANGE_THIS>
23+
ZENODO_ACCESS_TOKEN=<CHANGE_THIS>

app/__init__.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,6 @@ def inject_vars_into_jinja():
9393
# Add the application version manually
9494
env_vars["APP_VERSION"] = get_app_version()
9595

96-
# Ensure DOMAIN variable has a default value if not set
97-
env_vars["DOMAIN"] = os.getenv("DOMAIN", "localhost")
98-
9996
# Set Boolean variables for the environment
10097
flask_env = os.getenv("FLASK_ENV")
10198
env_vars["DEVELOPMENT"] = flask_env == "development"

app/modules/auth/forms.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
from flask_wtf import FlaskForm
22
from wtforms import BooleanField, PasswordField, StringField, SubmitField
3-
from wtforms.validators import DataRequired, Email, Length
3+
from wtforms.validators import DataRequired, Email, EqualTo, Length
44

55

66
class SignupForm(FlaskForm):
77
name = StringField("Name", validators=[DataRequired(), Length(max=100)])
88
surname = StringField("Surname", validators=[DataRequired(), Length(max=100)])
9-
password = PasswordField("Password", validators=[DataRequired()])
109
email = StringField("Email", validators=[DataRequired(), Email()])
10+
password = PasswordField("Password", validators=[DataRequired(), Length(min=6)])
11+
confirm_password = PasswordField(
12+
"Confirm Password",
13+
validators=[
14+
DataRequired(),
15+
EqualTo("password", message="Passwords must match."),
16+
],
17+
)
1118
submit = SubmitField("Submit")
1219

1320

app/modules/auth/repositories.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,9 @@ def create(self, commit: bool = True, **kwargs):
1717
self.session.flush()
1818
return instance
1919

20-
def get_by_email(self, email: str, active: bool = True):
21-
return self.model.query.filter_by(email=email, active=active).first()
20+
def get_by_email(self, email: str, active: bool | None = None):
21+
normalized_email = email.strip().lower()
22+
query = self.model.query.filter_by(email=normalized_email)
23+
if active is not None:
24+
query = query.filter_by(active=active)
25+
return query.first()

app/modules/auth/routes.py

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from flask import flash, redirect, render_template, request, url_for
2-
from flask_login import current_user, logout_user
2+
from flask_login import current_user, login_user, logout_user
33
from pymysql import IntegrityError
44

55
from app import db
@@ -10,6 +10,7 @@
1010
from app.modules.captcha.services import CaptchaService
1111
from app.modules.confirmemail.services import ConfirmemailService
1212
from app.modules.profile.services import UserProfileService
13+
from core.managers.task_queue_manager import TaskQueueManager
1314

1415
authentication_service = AuthenticationService()
1516
user_profile_service = UserProfileService()
@@ -23,30 +24,34 @@ def signup():
2324
return redirect(url_for("public.index"))
2425

2526
form = SignupForm()
26-
if form.validate_on_submit():
27-
user_input = request.form["captcha"]
28-
if not captcha_service.validate_captcha(user_input):
29-
flash("Please complete the reCAPTCHA", "danger")
30-
return render_template("auth/signup_form.html", form=form)
3127

32-
email = form.email.data
28+
if request.method == "POST" and form.validate_on_submit():
29+
email = form.email.data.strip().lower()
30+
3331
if not authentication_service.is_email_available(email):
34-
flash(f"Email {email} is already in use", "danger")
32+
flash(f"The email '{email}' is already registered.", "danger")
33+
return render_template("auth/signup_form.html", form=form)
34+
35+
user_input = request.form.get("captcha", "")
36+
if not captcha_service.validate_captcha(user_input):
37+
flash("Please complete the CAPTCHA correctly.", "danger")
3538
return render_template("auth/signup_form.html", form=form)
3639

3740
try:
38-
# We try to create the user
3941
user = authentication_service.create_with_profile(**form.data)
40-
confirmemail_service.send_confirmation_email(user.email)
41-
except IntegrityError as exc:
42-
db.session.rollback()
43-
if "Duplicate entry" in str(exc):
44-
flash(f"Email {email} is already in use", "danger")
45-
else:
46-
flash(f"Error creating user: {exc}", "danger")
47-
return render_template("auth/signup_form.html", form=form)
42+
login_user(user, remember=True)
43+
flash("Account created successfully. Welcome!", "success")
4844

49-
return redirect(url_for("public.index"))
45+
print(">>> SIGNUP reached end: before enqueuing email", flush=True)
46+
47+
task_manager = TaskQueueManager()
48+
task_manager.enqueue_task("app.modules.auth.tasks.send_confirmation_email", email=user.email, timeout=10)
49+
50+
return redirect(url_for("public.index"))
51+
52+
except IntegrityError:
53+
db.session.rollback()
54+
flash("An error occurred while creating your account.", "danger")
5055

5156
return render_template("auth/signup_form.html", form=form)
5257

app/modules/auth/services.py

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,25 +43,20 @@ def create_with_profile(self, **kwargs):
4343
if not surname:
4444
raise ValueError("Surname is required.")
4545

46-
# 🚨 Validación clave
4746
if not self.is_email_available(email):
4847
raise ValueError("This email is already registered. Try logging in or using ORCID.")
4948

50-
user_data = {
51-
"email": email,
52-
"password": password,
53-
"active": False,
54-
}
49+
# Crear usuario
50+
user = User(email=email, active=True)
51+
user.set_password(password)
52+
self.repository.session.add(user)
53+
self.repository.session.flush() # garantiza que user.id esté disponible
5554

56-
profile_data = {
57-
"name": name,
58-
"surname": surname,
59-
}
60-
61-
user = self.create(commit=False, **user_data)
62-
profile_data["user_id"] = user.id
63-
self.user_profile_repository.create(**profile_data)
55+
# Crear perfil
56+
profile = UserProfile(user_id=user.id, name=name, surname=surname)
57+
self.repository.session.add(profile)
6458
self.repository.session.commit()
59+
6560
return user
6661

6762
except Exception as exc:

app/modules/auth/tasks.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import logging
2+
3+
from app import create_app
4+
from app.modules.confirmemail.services import ConfirmemailService
5+
6+
confirmemail_service = ConfirmemailService()
7+
8+
logger = logging.getLogger(__name__)
9+
app = create_app()
10+
11+
12+
def send_confirmation_email(email: str):
13+
"""Tarea asíncrona para enviar el correo de confirmación."""
14+
logger.info(f"[EMAIL] Enviando correo de confirmación a {email}")
15+
16+
with app.app_context():
17+
try:
18+
confirmemail_service.send_confirmation_email(email)
19+
logger.info(f"[EMAIL] ✅ Correo de confirmación enviado a {email}")
20+
except Exception as e:
21+
logger.exception(f"[EMAIL] ❌ Error enviando correo a {email}: {e}")

0 commit comments

Comments
 (0)