1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-08-02 19:55:18 +02:00

Merge pull request #158 from seanmorley15/development

Development
This commit is contained in:
Sean Morley 2024-08-04 18:09:19 -04:00 committed by GitHub
commit e066ed7be6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 217 additions and 49 deletions

View file

@ -54,17 +54,18 @@ Here is a summary of the configuration options available in the `docker-compose.
### Backend Container (server)
| Name | Required | Description | Default Value |
| ----------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
| `PGHOST` | Yes | Databse host. | db |
| `PGDATABASE` | Yes | Database. | database |
| `PGUSER` | Yes | Database user. | adventure |
| `PGPASSWORD` | Yes | Database password. | changeme123 |
| `DJANGO_ADMIN_USERNAME` | Yes | Default username. | admin |
| `DJANGO_ADMIN_PASSWORD` | Yes | Default password, change after inital login. | admin |
| `DJANGO_ADMIN_EMAIL` | Yes | Default user's email. | admin@example.com |
| `PUBLIC_URL` | Yes | This is the publically accessible url to the **nginx** container. You should be able to acess nginx from this url where you access your app. | http://127.0.0.1:81 |
| `CSRF_TRUSTED_ORIGINS` | Yes | Need to be changed to the orgins where you use your backend server and frontend. These values are comma seperated. | Needs to be changed. |
| Name | Required | Description | Default Value |
| ----------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| `PGHOST` | Yes | Databse host. | db |
| `PGDATABASE` | Yes | Database. | database |
| `PGUSER` | Yes | Database user. | adventure |
| `PGPASSWORD` | Yes | Database password. | changeme123 |
| `DJANGO_ADMIN_USERNAME` | Yes | Default username. | admin |
| `DJANGO_ADMIN_PASSWORD` | Yes | Default password, change after inital login. | admin |
| `DJANGO_ADMIN_EMAIL` | Yes | Default user's email. | admin@example.com |
| `PUBLIC_URL` | Yes | This is the publically accessible url to the **nginx** container. You should be able to acess nginx from this url where you access your app. | http://127.0.0.1:81 |
| `CSRF_TRUSTED_ORIGINS` | Yes | Need to be changed to the orgins where you use your backend server and frontend. These values are comma seperated. | Needs to be changed. |
| `FRONTEND_URL` | Yes | This is the publically accessible url to the **frontend** container. This link should be accessable for all users. Used for email generation. | http://localhost:3000 |
### Proxy Container (nginx) Configuration

View file

@ -7,4 +7,17 @@ SECRET_KEY='pleasechangethisbecauseifyoudontitwillbeverybadandyouwillgethackedin
PUBLIC_URL='http://127.0.0.1:8000'
DEBUG=True
DEBUG=True
FRONTEND_URL='http://localhost:3000'
EMAIL_BACKEND='console'
# EMAIL_BACKEND='email'
# EMAIL_HOST='smtp.gmail.com'
# EMAIL_USE_TLS=False
# EMAIL_PORT=587
# EMAIL_USE_SSL=True
# EMAIL_HOST_USER='user'
# EMAIL_HOST_PASSWORD='password'
# DEFAULT_FROM_EMAIL='user@example.com'

View file

@ -155,7 +155,7 @@ REST_AUTH = {
'JWT_AUTH_HTTPONLY': False,
'REGISTER_SERIALIZER': 'users.serializers.RegisterSerializer',
'USER_DETAILS_SERIALIZER': 'users.serializers.CustomUserDetailsSerializer',
'PASSWORD_RESET_SERIALIZER': 'users.serializers.MyPasswordResetSerializer'
}
STORAGES = {
@ -169,12 +169,26 @@ STORAGES = {
AUTH_USER_MODEL = 'users.CustomUser'
FRONTEND_URL = getenv('FRONTEND_URL', 'http://localhost:3000')
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
SITE_ID = 1
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_AUTHENTICATION_METHOD = 'username'
ACCOUNT_EMAIL_VERIFICATION = 'optional'
if getenv('EMAIL_BACKEND', 'console') == 'console':
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
else:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = getenv('EMAIL_HOST')
EMAIL_USE_TLS = getenv('EMAIL_USE_TLS', 'True') == 'True'
EMAIL_PORT = getenv('EMAIL_PORT', 587)
EMAIL_USE_SSL = getenv('EMAIL_USE_SSL', 'False') == 'True'
EMAIL_HOST_USER = getenv('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = getenv('EMAIL_HOST_PASSWORD')
DEFAULT_FROM_EMAIL = getenv('DEFAULT_FROM_EMAIL')
# EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# EMAIL_HOST = 'smtp.resend.com'
# EMAIL_USE_TLS = False

View file

@ -0,0 +1,13 @@
{% extends "account/email/base_message.txt" %}
{% load i18n %}
{% block content %}{% autoescape off %}{% blocktrans %}You're receiving this email because you or someone else has requested a password reset for your user account.
It can be safely ignored if you did not request a password reset. Click the link below to reset your password.{% endblocktrans %}
{{ frontend_url }}/settings/forgot-password/confirm?token={{ temp_key }}&uid={{ user_pk }}
{% if username %}
{% blocktrans %}In case you forgot, your username is {{ username }}.{% endblocktrans %}{% endif %}{% endautoescape %}{% endblock content %}

View file

@ -0,0 +1,50 @@
from allauth.account.utils import (filter_users_by_email, user_pk_to_url_str, user_username)
from allauth.utils import build_absolute_uri
from allauth.account.adapter import get_adapter
from allauth.account.forms import default_token_generator
from allauth.account import app_settings
from django.conf import settings
from allauth.account.forms import ResetPasswordForm as AllAuthPasswordResetForm
class CustomAllAuthPasswordResetForm(AllAuthPasswordResetForm):
def clean_email(self):
"""
Invalid email should not raise error, as this would leak users
for unit test: test_password_reset_with_invalid_email
"""
email = self.cleaned_data["email"]
email = get_adapter().clean_email(email)
self.users = filter_users_by_email(email, is_active=True)
return self.cleaned_data["email"]
def save(self, request, **kwargs):
email = self.cleaned_data['email']
token_generator = kwargs.get('token_generator', default_token_generator)
for user in self.users:
temp_key = token_generator.make_token(user)
path = f"custom_password_reset_url/{user_pk_to_url_str(user)}/{temp_key}/"
url = build_absolute_uri(request, path)
#Values which are passed to password_reset_key_message.txt
context = {
"frontend_url": settings.FRONTEND_URL,
"user": user,
"password_reset_url": url,
"request": request,
"path": path,
"temp_key": temp_key,
'user_pk': user_pk_to_url_str(user),
}
if app_settings.AUTHENTICATION_METHOD != app_settings.AuthenticationMethod.EMAIL:
context['username'] = user_username(user)
get_adapter(request).send_mail(
'account/email/password_reset_key', email, context
)
return self.cleaned_data['email']

View file

@ -2,6 +2,8 @@ from rest_framework import serializers
from django.contrib.auth import get_user_model
from adventures.models import Adventure
from users.forms import CustomAllAuthPasswordResetForm
from dj_rest_auth.serializers import PasswordResetSerializer
User = get_user_model()
@ -177,3 +179,13 @@ class CustomUserDetailsSerializer(UserDetailsSerializer):
public_url = public_url.replace("'", "")
representation['profile_pic'] = f"{public_url}/media/{instance.profile_pic.name}"
return representation
class MyPasswordResetSerializer(PasswordResetSerializer):
def validate_email(self, value):
# use the custom reset form
self.reset_form = CustomAllAuthPasswordResetForm(data=self.initial_data)
if not self.reset_form.is_valid():
raise serializers.ValidationError(self.reset_form.errors)
return value

View file

@ -38,6 +38,7 @@ services:
- PUBLIC_URL='http://localhost:81'
- CSRF_TRUSTED_ORIGINS=https://api.adventurelog.app,https://adventurelog.app
- DEBUG=False
- FRONTEND_URL='http://localhost:8080'
ports:
- "8000:8000"
depends_on:

View file

@ -35,17 +35,18 @@ Here is a summary of the configuration options available in the `docker-compose.
### Backend Container (server)
| Name | Required | Description | Default Value |
| ----------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
| `PGHOST` | Yes | Databse host. | db |
| `PGDATABASE` | Yes | Database. | database |
| `PGUSER` | Yes | Database user. | adventure |
| `PGPASSWORD` | Yes | Database password. | changeme123 |
| `DJANGO_ADMIN_USERNAME` | Yes | Default username. | admin |
| `DJANGO_ADMIN_PASSWORD` | Yes | Default password, change after inital login. | admin |
| `DJANGO_ADMIN_EMAIL` | Yes | Default user's email. | admin@example.com |
| `PUBLIC_URL` | Yes | This is the publically accessible url to the **nginx** container. You should be able to acess nginx from this url where you access your app. | http://127.0.0.1:81 |
| `CSRF_TRUSTED_ORIGINS` | Yes | Need to be changed to the orgins where you use your backend server and frontend. These values are comma seperated. | Needs to be changed. |
| Name | Required | Description | Default Value |
| ----------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| `PGHOST` | Yes | Databse host. | db |
| `PGDATABASE` | Yes | Database. | database |
| `PGUSER` | Yes | Database user. | adventure |
| `PGPASSWORD` | Yes | Database password. | changeme123 |
| `DJANGO_ADMIN_USERNAME` | Yes | Default username. | admin |
| `DJANGO_ADMIN_PASSWORD` | Yes | Default password, change after inital login. | admin |
| `DJANGO_ADMIN_EMAIL` | Yes | Default user's email. | admin@example.com |
| `PUBLIC_URL` | Yes | This is the publically accessible url to the **nginx** container. You should be able to acess nginx from this url where you access your app. | http://127.0.0.1:81 |
| `CSRF_TRUSTED_ORIGINS` | Yes | Need to be changed to the orgins where you use your backend server and frontend. These values are comma seperated. | Needs to be changed. |
| `FRONTEND_URL` | Yes | This is the publically accessible url to the **frontend** container. This link should be accessable for all users. Used for email generation. | http://localhost:3000 |
### Proxy Container (nginx) Configuration

View file

@ -113,7 +113,7 @@
<p class="font-semibold text-md mb-2">Editing note {initialName}</p>
{/if}
{#if user?.pk == note?.user_id}
{#if (note && user?.pk == note?.user_id) || !note}
<form on:submit|preventDefault>
<div class="form-control mb-2">
<label for="name">Name</label>

View file

@ -22,8 +22,13 @@ export const actions: Actions = {
email
})
});
if (!res.ok) {
return fail(res.status, { message: await res.json() });
let message = await res.json();
const key = Object.keys(message)[0];
return fail(res.status, { message: message[key] });
}
return { success: true };
}

View file

@ -6,7 +6,7 @@
<h1 class="text-center font-extrabold text-4xl mb-6">Reset Password</h1>
<div class="flex justify-center">
<form method="post" action="?/forgotPassword" class="w-full max-w-xs">
<form method="post" action="?/forgotPassword" class="w-full max-w-xs" use:enhance>
<label for="email">Email</label>
<input
name="email"

View file

@ -1,4 +1,4 @@
import { fail, redirect } from '@sveltejs/kit';
import { fail, redirect, type Actions } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
const PUBLIC_SERVER_URL = process.env['PUBLIC_SERVER_URL'];
const serverEndpoint = PUBLIC_SERVER_URL || 'http://localhost:8000';
@ -6,26 +6,54 @@ const serverEndpoint = PUBLIC_SERVER_URL || 'http://localhost:8000';
export const load = (async (event) => {
const token = event.url.searchParams.get('token');
const uid = event.url.searchParams.get('uid');
console.log('token', token);
if (!token) {
return redirect(302, '/settings/forgot-password');
} else {
let response = await fetch(`${serverEndpoint}/auth/password/reset/confirm/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
token: token,
uid: uid,
new_password1: 'password',
new_password2: 'password'
})
});
let data = await response.json();
console.log('data', data);
}
return {};
return {
props: {
token,
uid
}
};
}) satisfies PageServerLoad;
export const actions: Actions = {
reset: async (event) => {
const formData = await event.request.formData();
const new_password1 = formData.get('new_password1') as string;
const new_password2 = formData.get('new_password2') as string;
const token = formData.get('token') as string;
const uid = formData.get('uid') as string;
if (!new_password1 || !new_password2) {
return fail(400, { message: 'Password is required' });
}
if (new_password1 !== new_password2) {
return fail(400, { message: 'Passwords do not match' });
}
if (!token || !uid) {
return redirect(302, '/settings/forgot-password');
} else {
let response = await fetch(`${serverEndpoint}/auth/password/reset/confirm/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
token: token,
uid: uid,
new_password1,
new_password2
})
});
if (!response.ok) {
let responseJson = await response.json();
const key = Object.keys(responseJson)[0];
return fail(response.status, { message: responseJson[key] });
} else {
return redirect(302, '/login');
}
}
}
};

View file

@ -1,5 +1,35 @@
<script lang="ts">
import { enhance } from '$app/forms';
import { page } from '$app/stores';
import type { PageData } from './$types';
export let data: PageData;
</script>
<h1 class="text-center font-bold text-4xl mb-4">Change Password</h1>
<form action="?/reset" method="post" use:enhance>
<input type="hidden" name="uid" value={data.props.uid} />
<input type="hidden" name="token" value={data.props.token} />
<div class="flex items-center justify-center gap-4">
<input
type="password"
class="input input-bordered w-full max-w-xs"
id="new_password1"
name="new_password1"
placeholder="New Password"
/>
<input
type="password"
class="input input-bordered w-full max-w-xs"
id="new_password2"
name="new_password2"
placeholder="Confirm Password"
/>
<button type="submit" class="btn btn-primary"> Submit </button>
{#if $page.form?.message}
<div class="text-center text-error mt-4">
{$page.form?.message}
</div>
{/if}
</div>
</form>