diff --git a/classquiz/cache.py b/classquiz/cache.py index 21680cf..ba085ef 100644 --- a/classquiz/cache.py +++ b/classquiz/cache.py @@ -12,14 +12,14 @@ async def cache_account(criteria: str, content: str) -> Union[User, None]: if criteria == "email": try: - res = await User.objects.get(email=content) + res = await User.objects.get(email=content, verified=True) except ormar.exceptions.NoMatch: return None await insert_into_redis(res, content) return res elif criteria == "username": try: - res = await User.objects.get(username=content) + res = await User.objects.get(username=content, verified=True) except ormar.exceptions.NoMatch: return None await insert_into_redis(res, content) @@ -27,7 +27,7 @@ async def cache_account(criteria: str, content: str) -> Union[User, None]: elif criteria == "id": try: - res = await User.objects.get(id=uuid.UUID(content)) + res = await User.objects.get(id=uuid.UUID(content), verified=True) except ormar.exceptions.NoMatch: return None await insert_into_redis(res, content) diff --git a/classquiz/emails/__init__.py b/classquiz/emails/__init__.py index 32cf08d..35af7a7 100644 --- a/classquiz/emails/__init__.py +++ b/classquiz/emails/__init__.py @@ -1,4 +1,40 @@ +from jinja2 import Environment, PackageLoader, select_autoescape +from classquiz.db.models import User + +from email.mime.multipart import MIMEMultipart +from classquiz.config import settings +from email.mime.text import MIMEText +import smtplib +import ssl + +jinja = Environment( + loader=PackageLoader('classquiz.emails', 'templates'), + autoescape=select_autoescape(['html', 'xml']), + enable_async=True) + + +def _sendMail(template: str, to: str, subject: str): + msg = MIMEMultipart('alternative') + msg['Subject'] = subject + msg['From'] = settings.mail_address + msg['To'] = to + msg.attach(MIMEText(template, 'html')) + context = ssl.SSLContext(ssl.PROTOCOL_TLS) + server = smtplib.SMTP(host=settings.mail_server, port=settings.mail_port) + server.ehlo() + server.starttls(context=context) + server.ehlo() + server.login(settings.mail_username, settings.mail_password) + server.sendmail(settings.mail_address, to, msg.as_string()) async def send_mail(email: str): - pass \ No newline at end of file + user = await User.objects.get_or_none(email=email, verified=False) + if user is None: + raise ValueError('User not found') + template = jinja.get_template('register.jinja2') + template = await template.render_async( + base_url=settings.root_address, + token=user.verify_key + ) + _sendMail(template=template, to=email, subject='Verify your email') diff --git a/classquiz/emails/templates/footer.jinja2 b/classquiz/emails/templates/footer.jinja2 new file mode 100644 index 0000000..732e987 --- /dev/null +++ b/classquiz/emails/templates/footer.jinja2 @@ -0,0 +1,24 @@ + +
+ + + + + + +
+

+ 💌 Send with love by Mawoka +

+
\ No newline at end of file diff --git a/classquiz/emails/templates/register.html b/classquiz/emails/templates/register.jinja2 similarity index 73% rename from classquiz/emails/templates/register.html rename to classquiz/emails/templates/register.jinja2 index 3d4387b..cda74a1 100644 --- a/classquiz/emails/templates/register.html +++ b/classquiz/emails/templates/register.jinja2 @@ -1,18 +1,3 @@ - -
Let's confirm your email address.
@@ -63,7 +48,7 @@ Confirm Email Address @@ -83,20 +68,6 @@
-
- - - - - - -
-

- 💌 Send with love by Mawoka -

-
+ {% include 'footer.jinja2' %} +
\ No newline at end of file diff --git a/classquiz/routers/users.py b/classquiz/routers/users.py index d5b3f99..91ca01f 100644 --- a/classquiz/routers/users.py +++ b/classquiz/routers/users.py @@ -6,7 +6,7 @@ from classquiz.auth import * from fastapi.background import BackgroundTasks from classquiz.emails import send_mail from classquiz.config import redis -from fastapi.responses import JSONResponse +from fastapi.responses import JSONResponse, RedirectResponse from classquiz.db.models import * @@ -96,3 +96,14 @@ async def logout(request: Request, response: Response): @router.get("/check") async def check_token(user: User = Depends(get_current_user)): return {"email": user.email} + + +@router.get("/verify/{verify_key}") +async def verify_user(verify_key: str): + user = await User.objects.filter(verify_key=verify_key).get_or_none() + if user is None: + raise HTTPException(status_code=404, detail="User not found") + user.verified = True + user.verify_key = None + await user.update() + return RedirectResponse(url="/account/login?verified=true") diff --git a/frontend/src/routes/account/login.svelte b/frontend/src/routes/account/login.svelte index 57d50d3..23116a6 100644 --- a/frontend/src/routes/account/login.svelte +++ b/frontend/src/routes/account/login.svelte @@ -53,7 +53,7 @@ isSubmitting = true; if (res.status === 200) { responseData.data = loginData.password === '' ? 'magic' : 'password'; - } else if (res.status === 404) { + } else if (res.status === 401) { responseData.data = '404'; } else { responseData.data = 'error';