1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-07-30 18:29:37 +02:00

User profile settings API and remove old Dj-Rest-Auth code

This commit is contained in:
Sean Morley 2024-11-30 10:24:27 -05:00
parent c65fcc2558
commit 84566b8ec1
22 changed files with 514 additions and 791 deletions

View file

@ -1,27 +0,0 @@
# Preface
AdventureLog uses DjRestAuth, a Django REST Framework authentication backend for Django Rest Framework. DjRestAuth is licensed under the MIT License.
---
## The MIT License (MIT)
Copyright (c) 2014 iMerica https://github.com/iMerica/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,4 +0,0 @@
# AdventureLog Django Backend
A demo of a possible AdventureLog 2.0 version using Django as the backend with a REST API.
Based of django-rest-framework and dj-rest-auth.

View file

@ -11,7 +11,6 @@ https://docs.djangoproject.com/en/1.7/ref/settings/
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os import os
from dotenv import load_dotenv from dotenv import load_dotenv
from datetime import timedelta
from os import getenv from os import getenv
from pathlib import Path from pathlib import Path
# Load environment variables from .env file # Load environment variables from .env file
@ -35,8 +34,6 @@ DEBUG = getenv('DEBUG', 'True') == 'True'
# ] # ]
ALLOWED_HOSTS = ['*'] ALLOWED_HOSTS = ['*']
# Application definition
INSTALLED_APPS = ( INSTALLED_APPS = (
'django.contrib.admin', 'django.contrib.admin',
'django.contrib.auth', 'django.contrib.auth',
@ -50,7 +47,7 @@ INSTALLED_APPS = (
"allauth_ui", "allauth_ui",
'allauth', 'allauth',
'allauth.account', 'allauth.account',
'allauth.mfa', # 'allauth.mfa',
'allauth.headless', 'allauth.headless',
'allauth.socialaccount', 'allauth.socialaccount',
"widget_tweaks", "widget_tweaks",
@ -108,7 +105,7 @@ DATABASES = {
} }
} }
ACCOUNT_SIGNUP_FORM_CLASS = 'users.form_overrides.CustomSignupForm'
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/1.7/topics/i18n/ # https://docs.djangoproject.com/en/1.7/topics/i18n/
@ -123,8 +120,7 @@ USE_L10N = True
USE_TZ = True USE_TZ = True
ALLAUTH_UI_THEME = "dark"
SILENCED_SYSTEM_CHECKS = ["slippers.E001"]
# Static files (CSS, JavaScript, Images) # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.7/howto/static-files/ # https://docs.djangoproject.com/en/1.7/howto/static-files/
@ -138,6 +134,16 @@ MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media' MEDIA_ROOT = BASE_DIR / 'media'
STATICFILES_DIRS = [BASE_DIR / 'static'] STATICFILES_DIRS = [BASE_DIR / 'static']
STORAGES = {
"staticfiles": {
"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
},
"default": {
"BACKEND": "django.core.files.storage.FileSystemStorage",
}
}
TEMPLATES = [ TEMPLATES = [
{ {
'BACKEND': 'django.template.backends.django.DjangoTemplates', 'BACKEND': 'django.template.backends.django.DjangoTemplates',
@ -154,22 +160,22 @@ TEMPLATES = [
}, },
] ]
# Authentication settings
DISABLE_REGISTRATION = getenv('DISABLE_REGISTRATION', 'False') == 'True' DISABLE_REGISTRATION = getenv('DISABLE_REGISTRATION', 'False') == 'True'
DISABLE_REGISTRATION_MESSAGE = getenv('DISABLE_REGISTRATION_MESSAGE', 'Registration is disabled. Please contact the administrator if you need an account.') DISABLE_REGISTRATION_MESSAGE = getenv('DISABLE_REGISTRATION_MESSAGE', 'Registration is disabled. Please contact the administrator if you need an account.')
STORAGES = { ALLAUTH_UI_THEME = "dark"
"staticfiles": { SILENCED_SYSTEM_CHECKS = ["slippers.E001"]
"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
},
"default": {
"BACKEND": "django.core.files.storage.FileSystemStorage",
}
}
AUTH_USER_MODEL = 'users.CustomUser' AUTH_USER_MODEL = 'users.CustomUser'
ACCOUNT_ADAPTER = 'users.adapters.NoNewUsersAccountAdapter' ACCOUNT_ADAPTER = 'users.adapters.NoNewUsersAccountAdapter'
ACCOUNT_SIGNUP_FORM_CLASS = 'users.form_overrides.CustomSignupForm'
SESSION_SAVE_EVERY_REQUEST = True
FRONTEND_URL = getenv('FRONTEND_URL', 'http://localhost:3000') FRONTEND_URL = getenv('FRONTEND_URL', 'http://localhost:3000')
# HEADLESS_FRONTEND_URLS = { # HEADLESS_FRONTEND_URLS = {
@ -218,9 +224,6 @@ SWAGGER_SETTINGS = {
'LOGOUT_URL': 'logout', 'LOGOUT_URL': 'logout',
} }
from os import getenv
CORS_ALLOWED_ORIGINS = [origin.strip() for origin in getenv('CSRF_TRUSTED_ORIGINS', 'http://localhost').split(',') if origin.strip()] CORS_ALLOWED_ORIGINS = [origin.strip() for origin in getenv('CSRF_TRUSTED_ORIGINS', 'http://localhost').split(',') if origin.strip()]
@ -254,5 +257,3 @@ LOGGING = {
} }
# https://github.com/dr5hn/countries-states-cities-database/tags # https://github.com/dr5hn/countries-states-cities-database/tags
COUNTRY_REGION_JSON_VERSION = 'v2.4' COUNTRY_REGION_JSON_VERSION = 'v2.4'
SESSION_SAVE_EVERY_REQUEST = True

View file

@ -3,8 +3,7 @@ from django.contrib import admin
from django.views.generic import RedirectView, TemplateView from django.views.generic import RedirectView, TemplateView
from django.conf import settings from django.conf import settings
from django.conf.urls.static import static from django.conf.urls.static import static
from adventures import urls as adventures from users.views import IsRegistrationDisabled, PublicUserListView, PublicUserDetailView, UserMetadataView, UpdateUserMetadataView
from users.views import ChangeEmailView, IsRegistrationDisabled, PublicUserListView, PublicUserDetailView, UserMetadataView
from .views import get_csrf_token from .views import get_csrf_token
from drf_yasg.views import get_schema_view from drf_yasg.views import get_schema_view
@ -19,56 +18,19 @@ schema_view = get_schema_view(
urlpatterns = [ urlpatterns = [
path('api/', include('adventures.urls')), path('api/', include('adventures.urls')),
path('api/', include('worldtravel.urls')), path('api/', include('worldtravel.urls')),
path("_allauth/", include("allauth.headless.urls")),
path('auth/change-email/', ChangeEmailView.as_view(), name='change_email'),
path('auth/is-registration-disabled/', IsRegistrationDisabled.as_view(), name='is_registration_disabled'), path('auth/is-registration-disabled/', IsRegistrationDisabled.as_view(), name='is_registration_disabled'),
path('auth/users/', PublicUserListView.as_view(), name='public-user-list'), path('auth/users/', PublicUserListView.as_view(), name='public-user-list'),
path('auth/user/<uuid:user_id>/', PublicUserDetailView.as_view(), name='public-user-detail'), path('auth/user/<uuid:user_id>/', PublicUserDetailView.as_view(), name='public-user-detail'),
path('auth/update-user/', UpdateUserMetadataView.as_view(), name='update-user-metadata'),
path('auth/user-metadata/', UserMetadataView.as_view(), name='user-metadata'), path('auth/user-metadata/', UserMetadataView.as_view(), name='user-metadata'),
path('csrf/', get_csrf_token, name='get_csrf_token'), path('csrf/', get_csrf_token, name='get_csrf_token'),
re_path(r'^$', TemplateView.as_view(
template_name="home.html"), name='home'),
re_path(r'^signup/$', TemplateView.as_view(template_name="signup.html"),
name='signup'),
re_path(r'^email-verification/$',
TemplateView.as_view(template_name="email_verification.html"),
name='email-verification'),
re_path(r'^login/$', TemplateView.as_view(template_name="login.html"),
name='login'),
re_path(r'^logout/$', TemplateView.as_view(template_name="logout.html"),
name='logout'),
re_path(r'^password-reset/$',
TemplateView.as_view(template_name="password_reset.html"),
name='password-reset'),
re_path(r'^password-reset/confirm/$',
TemplateView.as_view(template_name="password_reset_confirm.html"),
name='password-reset-confirm'),
re_path(r'^user-details/$', path('', TemplateView.as_view(template_name='home.html')),
TemplateView.as_view(template_name="user_details.html"),
name='user-details'),
re_path(r'^password-change/$',
TemplateView.as_view(template_name="password_change.html"),
name='password-change'),
re_path(r'^resend-email-verification/$',
TemplateView.as_view(
template_name="resend_email_verification.html"),
name='resend-email-verification'),
# this url is used to generate email content
re_path(r'^password-reset/confirm/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,32})/$',
TemplateView.as_view(template_name="password_reset_confirm.html"),
name='password_reset_confirm'),
re_path(r'^auth/', include('dj_rest_auth.urls')),
re_path(r'^auth/registration/',
include('dj_rest_auth.registration.urls')),
# re_path(r'^account/', include('allauth.urls')),
re_path(r'^admin/', admin.site.urls), re_path(r'^admin/', admin.site.urls),
re_path(r'^accounts/profile/$', RedirectView.as_view(url='/', re_path(r'^accounts/profile/$', RedirectView.as_view(url='/',
permanent=True), name='profile-redirect'), permanent=True), name='profile-redirect'),
@ -78,5 +40,5 @@ urlpatterns = [
path("accounts/", include("allauth.urls")), path("accounts/", include("allauth.urls")),
# Include the API endpoints: # Include the API endpoints:
path("_allauth/", include("allauth.headless.urls")),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View file

@ -1,7 +1,5 @@
Django==5.0.8 Django==5.0.8
dj-rest-auth @ git+https://github.com/iMerica/dj-rest-auth.git@master
djangorestframework>=3.15.2 djangorestframework>=3.15.2
djangorestframework-simplejwt==5.3.1
django-allauth==0.63.3 django-allauth==0.63.3
drf-yasg==1.21.4 drf-yasg==1.21.4
django-cors-headers==4.4.0 django-cors-headers==4.4.0

View file

@ -4,8 +4,8 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Django-dj-rest-auth demo" /> <meta name="description" content="AdventureLog Server" />
<meta name="author" content="iMerica, Inc." /> <meta name="author" content="Sean Morley" />
<title>AdventureLog API Server</title> <title>AdventureLog API Server</title>
@ -31,39 +31,6 @@
<body role="document"> <body role="document">
<div class="navbar navbar-inverse" role="navigation"> <div class="navbar navbar-inverse" role="navigation">
<div class="container"> <div class="container">
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
>API endpoints <span class="caret"></span
></a>
<ul class="dropdown-menu" role="menu">
<!-- these pages don't require user token -->
<li><a href="{% url 'signup' %}">Signup</a></li>
<li>
<a href="{% url 'email-verification' %}">E-mail verification</a>
</li>
<li>
<a href="{% url 'resend-email-verification' %}"
>Resend E-mail verification</a
>
</li>
<li><a href="{% url 'login' %}">Login</a></li>
<li><a href="{% url 'password-reset' %}">Password Reset</a></li>
<li>
<a href="{% url 'password-reset-confirm' %}"
>Password Reset Confirm</a
>
</li>
<li class="divider"></li>
<!-- these pages require user token -->
<li><a href="{% url 'user-details' %}">User details</a></li>
<li><a href="{% url 'logout' %}">Logout</a></li>
<li><a href="{% url 'password-change' %}">Password change</a></li>
</ul>
</li>
</ul>
<div class="navbar-header"> <div class="navbar-header">
<button <button
type="button" type="button"
@ -80,20 +47,19 @@
</div> </div>
<div class="collapse navbar-collapse"> <div class="collapse navbar-collapse">
<ul class="nav navbar-nav"> <ul class="nav navbar-nav">
<li class="active"><a href="/">Demo</a></li> <li class="active"><a href="/">Server Home</a></li>
<li> <li>
<a <a target="_blank" href="http://adventurelog.app"
target="_blank"
href="http://dj-rest-auth.readthedocs.org/en/latest/"
>Documentation</a >Documentation</a
> >
</li> </li>
<li> <li>
<a target="_blank" href="https://github.com/iMerica/dj-rest-auth" <a
>Source code</a target="_blank"
href="https://github.com/seanmorley15/AdventureLog"
>Source Code</a
> >
</li> </li>
<li><a target="_blank" href="{% url 'api_docs' %}">API Docs</a></li>
</ul> </ul>
</div> </div>
<!--/.nav-collapse --> <!--/.nav-collapse -->

View file

@ -1,8 +0,0 @@
{% extends "base.html" %}
{% block content %}
<div class="row">
<h3>E-mail verification</h3><hr/>
{% include "fragments/email_verification_form.html" %}
</div>
{% endblock %}

View file

@ -4,7 +4,12 @@
<h1>AdventureLog API Server</h1> <h1>AdventureLog API Server</h1>
<p> <p>
<a class="btn btn-primary btn-lg" href="/admin" role="button">Admin Site</a> <a class="btn btn-primary btn-lg" href="/admin" role="button">Admin Site</a>
<a class="btn btn-secondary btn-lg" href="/docs" role="button">API Docs</a> <a
class="btn btn-secondary btn-lg"
href="/accounts/password/change"
role="button"
>Account Managment</a
>
</p> </p>
</div> </div>
{% endblock %} {% endblock %}

View file

@ -1,8 +0,0 @@
{% extends "base.html" %}
{% block content %}
<div class="row">
<h3>Login</h3><hr/>
{% include "fragments/login_form.html" %}
</div>
{% endblock %}

View file

@ -1,8 +0,0 @@
{% extends "base.html" %}
{% block content %}
<div class="row">
<h3>Logout</h3><hr/>
{% include "fragments/logout_form.html" %}
</div>
{% endblock %}

View file

@ -1,39 +0,0 @@
{% extends "base.html" %}
{% block content %}
<div class="row">
<div class="form-group">
<label for="token" class="col-sm-2 control-label">User Token</label>
<div class="col-sm-4">
<input name="token" type="text" class="form-control" id="token" placeholder="Token">
<p class="help-block">Token received after login</p>
</div>
</div>
</div>
<div class="row">
<h3>Update User Details</h3><hr/>
{% include "fragments/password_change_form.html" %}
</div>
{% endblock %}
{% block script %}
<script type="text/javascript">
$().ready(function(){
$('form button[type=submit]').click(function(){
var token = $('input[name=token]').val();
var form = $('form');
$.ajax({
url: form.attr('action'),
data: $('form').serialize(),
type: "POST",
beforeSend: function(xhr){xhr.setRequestHeader('Authorization', 'Token '+token);}
}).fail(function(data){error_response(data);})
.done(function(data){susccess_response(data);});
return false;
});
});
</script>
{% endblock %}

View file

@ -1,8 +0,0 @@
{% extends "base.html" %}
{% block content %}
<div class="row">
<h3>Password reset</h3><hr/>
{% include "fragments/password_reset_form.html" %}
</div>
{% endblock %}

View file

@ -1,26 +0,0 @@
{% extends "base.html" %}
{% block content %}
<div class="row">
<h3>Password reset confirmation</h3><hr/>
{% include "fragments/password_reset_confirm_form.html" %}
</div>
{% endblock %}
{% block script %}
<script type="text/javascript">
var url_elements = window.location.pathname.split('/');
if (url_elements.length == 6){
var uid = url_elements[url_elements.length - 3];
if (uid !== undefined){
$('input[name=uid]').val(uid);
}
var token = url_elements[url_elements.length - 2];
if (token !== undefined){
$('input[name=token]').val(token);
}
}
</script>
{% endblock %}

View file

@ -1,8 +0,0 @@
{% extends "base.html" %}
{% block content %}
<div class="row">
<h3>Resend E-mail verification</h3><hr/>
{% include "fragments/resend_email_verification_form.html" %}
</div>
{% endblock %}

View file

@ -1,8 +0,0 @@
{% extends "base.html" %}
{% block content %}
<div class="row">
<h3>Signup</h3><hr/>
{% include "fragments/signup_form.html" %}
</div>
{% endblock %}

View file

@ -1,58 +0,0 @@
{% extends "base.html" %}
{% block content %}
<div class="row">
<h3>Retrieve User Details</h3><hr/>
<div class="form-group">
<label for="token" class="col-sm-2 control-label">User Token</label>
<div class="col-sm-4">
<input name="token" type="text" class="form-control" id="token" placeholder="Token">
<p class="help-block">Token received after login</p>
</div>
<button id="get-user-details" class="btn btn-primary">GET user details</button>
</div>
</div>
<div class="row">
<h3>Update User Details</h3><hr/>
{% include "fragments/user_details_form.html" %}
</div>
{% endblock %}
{% block script %}
<script type="text/javascript">
$().ready(function(){
$('#get-user-details').click(function(){
var token = $('input[name=token]').val();
$.ajax({
url: "{% url 'rest_user_details' %}",
beforeSend: function(xhr){xhr.setRequestHeader('Authorization', 'Token '+token);},
type: "GET",
success: function(data) {
$('input[name=username]').val(data.username);
$('input[name=email]').val(data.email);
$('input[name=first_name]').val(data.first_name);
$('input[name=last_name]').val(data.last_name);
}
});
return false;
});
$('form button[type=submit]').click(function(){
var token = $('input[name=token]').val();
var form = $('form');
$.ajax({
url: form.attr('action'),
data: $('form').serialize(),
type: "PUT",
beforeSend: function(xhr){xhr.setRequestHeader('Authorization', 'Token '+token);}
}).fail(function(data){error_response(data);})
.done(function(data){susccess_response(data);});
return false;
});
});
</script>
{% endblock %}

View file

@ -106,6 +106,7 @@ class CustomUserDetailsSerializer(UserDetailsSerializer):
class Meta(UserDetailsSerializer.Meta): class Meta(UserDetailsSerializer.Meta):
model = CustomUser model = CustomUser
fields = UserDetailsSerializer.Meta.fields + ('profile_pic', 'uuid', 'public_profile') fields = UserDetailsSerializer.Meta.fields + ('profile_pic', 'uuid', 'public_profile')
read_only_fields = UserDetailsSerializer.Meta.read_only_fields + ('uuid',)
def to_representation(self, instance): def to_representation(self, instance):
representation = super().to_representation(instance) representation = super().to_representation(instance)

View file

@ -98,3 +98,26 @@ class UserMetadataView(APIView):
user = request.user user = request.user
serializer = PublicUserSerializer(user) serializer = PublicUserSerializer(user)
return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.data, status=status.HTTP_200_OK)
class UpdateUserMetadataView(APIView):
"""
Update user metadata using fields from the PublicUserSerializer.
Using patch opposed to put allows for partial updates, covers the case where it checks the username and says it's already taken. Duplicate uesrname values should not be included in the request to avoid this.
"""
permission_classes = [IsAuthenticated]
@swagger_auto_schema(
request_body=PublicUserSerializer,
responses={
200: openapi.Response('User metadata updated'),
400: 'Bad Request'
},
operation_description="Update user metadata."
)
def patch(self, request):
user = request.user
serializer = PublicUserSerializer(user, data=request.data, partial=True, context={'request': request})
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

View file

@ -1,38 +0,0 @@
# create-svelte
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).
## Creating a project
If you're seeing this, you've probably already done this step. Congrats!
```bash
# create a new project in the current directory
npm create svelte@latest
# create a new project in my-app
npm create svelte@latest my-app
```
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
## Building
To create a production version of your app:
```bash
npm run build
```
You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.

View file

@ -291,7 +291,9 @@
"about_this_background": "About this background", "about_this_background": "About this background",
"photo_by": "Photo by", "photo_by": "Photo by",
"join_discord": "Join the Discord", "join_discord": "Join the Discord",
"join_discord_desc": "to share your own photos. Post them in the #travel-share channel." "join_discord_desc": "to share your own photos. Post them in the #travel-share channel.",
"current_password": "Current Password",
"change_password_error": "Unable to change password. Invalid current password or invalid new password."
}, },
"collection": { "collection": {
"collection_created": "Collection created successfully!", "collection_created": "Collection created successfully!",

View file

@ -13,7 +13,7 @@ export const load: PageServerLoad = async (event) => {
if (!sessionId) { if (!sessionId) {
return redirect(302, '/'); return redirect(302, '/');
} }
let res = await fetch(`${endpoint}/auth/user/`, { let res = await fetch(`${endpoint}/auth/user-metadata/`, {
headers: { headers: {
Cookie: `sessionid=${sessionId}` Cookie: `sessionid=${sessionId}`
} }
@ -50,7 +50,7 @@ export const actions: Actions = {
let profile_pic = formData.get('profile_pic') as File | null | undefined; let profile_pic = formData.get('profile_pic') as File | null | undefined;
let public_profile = formData.get('public_profile') as string | null | undefined | boolean; let public_profile = formData.get('public_profile') as string | null | undefined | boolean;
const resCurrent = await fetch(`${endpoint}/auth/user/`, { const resCurrent = await fetch(`${endpoint}/auth/user-metadata/`, {
headers: { headers: {
Cookie: `sessionid=${sessionId}` Cookie: `sessionid=${sessionId}`
} }
@ -60,12 +60,12 @@ export const actions: Actions = {
return fail(resCurrent.status, await resCurrent.json()); return fail(resCurrent.status, await resCurrent.json());
} }
// Gets the boolean value of the public_profile input
if (public_profile === 'on') { if (public_profile === 'on') {
public_profile = true; public_profile = true;
} else { } else {
public_profile = false; public_profile = false;
} }
console.log(public_profile);
let currentUser = (await resCurrent.json()) as User; let currentUser = (await resCurrent.json()) as User;
@ -83,6 +83,7 @@ export const actions: Actions = {
} }
let formDataToSend = new FormData(); let formDataToSend = new FormData();
if (username) { if (username) {
formDataToSend.append('username', username); formDataToSend.append('username', username);
} }
@ -99,7 +100,7 @@ export const actions: Actions = {
let csrfToken = await fetchCSRFToken(); let csrfToken = await fetchCSRFToken();
let res = await fetch(`${endpoint}/auth/user/`, { let res = await fetch(`${endpoint}/auth/update-user/`, {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
Cookie: `sessionid=${sessionId}; csrftoken=${csrfToken}`, Cookie: `sessionid=${sessionId}; csrftoken=${csrfToken}`,
@ -111,8 +112,6 @@ export const actions: Actions = {
let response = await res.json(); let response = await res.json();
if (!res.ok) { if (!res.ok) {
// change the first key in the response to 'message' for the fail function
response = { message: Object.values(response)[0] };
return fail(res.status, response); return fail(res.status, response);
} }
@ -130,19 +129,23 @@ export const actions: Actions = {
if (!sessionId) { if (!sessionId) {
return redirect(302, '/'); return redirect(302, '/');
} }
console.log('changePassword');
const formData = await event.request.formData(); const formData = await event.request.formData();
const password1 = formData.get('password1') as string | null | undefined; const password1 = formData.get('password1') as string | null | undefined;
const password2 = formData.get('password2') as string | null | undefined; const password2 = formData.get('password2') as string | null | undefined;
const current_password = formData.get('current_password') as string | null | undefined;
if (password1 !== password2) { if (password1 !== password2) {
return fail(400, { message: 'Passwords do not match' }); return fail(400, { message: 'Passwords do not match' });
} }
if (!current_password) {
return fail(400, { message: 'Current password is required' });
}
let csrfToken = await fetchCSRFToken(); let csrfToken = await fetchCSRFToken();
let res = await fetch(`${endpoint}/auth/password/change/`, { let res = await fetch(`${endpoint}/_allauth/browser/v1/account/password/change`, {
method: 'POST', method: 'POST',
headers: { headers: {
Cookie: `sessionid=${sessionId}; csrftoken=${csrfToken}`, Cookie: `sessionid=${sessionId}; csrftoken=${csrfToken}`,
@ -150,12 +153,18 @@ export const actions: Actions = {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
body: JSON.stringify({ body: JSON.stringify({
new_password1: password1, current_password,
new_password2: password2 new_password: password1
}) })
}); });
if (!res.ok) { if (!res.ok) {
return fail(res.status, await res.json()); let error_message = await res.text();
if (res.status === 400) {
// get the message key of the object
// {"status": 400, "errors": [{"message": "Please type your current password.", "code": "enter_current_password", "param": "current_password"}]}
error_message = JSON.parse(error_message).errors[0].message;
}
return fail(res.status, { message: error_message });
} }
return { success: true }; return { success: true };
}, },

View file

@ -34,16 +34,6 @@
} }
} }
// async function exportAdventures() {
// const url = await exportData();
// const a = document.createElement('a');
// a.href = url;
// a.download = 'adventure-log-export.json';
// a.click();
// URL.revokeObjectURL(url);
// }
async function checkVisitedRegions() { async function checkVisitedRegions() {
let res = await fetch('/api/reverse-geocode/mark_visited_region/', { let res = await fetch('/api/reverse-geocode/mark_visited_region/', {
method: 'POST', method: 'POST',
@ -137,7 +127,15 @@
<h1 class="text-center font-extrabold text-xl mt-4 mb-2">{$t('settings.password_change')}</h1> <h1 class="text-center font-extrabold text-xl mt-4 mb-2">{$t('settings.password_change')}</h1>
<div class="flex justify-center"> <div class="flex justify-center">
<form action="?/changePassword" method="post" class="w-full max-w-xs"> <form action="?/changePassword" method="post" class="w-full max-w-xs" use:enhance>
<input
type="password"
name="current_password"
placeholder={$t('settings.current_password')}
id="current_password"
class="block mb-2 input input-bordered w-full max-w-xs"
/>
<br />
<input <input
type="password" type="password"
name="password1" name="password1"
@ -202,9 +200,7 @@
</div> --> </div> -->
<small class="text-center" <small class="text-center"
><b>For Debug Use:</b> Server PK={user.pk} | Date Joined: {user.date_joined ><b>For Debug Use:</b> UUID={user.uuid} | Staff user: {user.is_staff}</small
? new Date(user.date_joined).toDateString()
: ''} | Staff user: {user.is_staff}</small
> >
<svelte:head> <svelte:head>