mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-08-10 07:35:17 +02:00
feat: add measurement system field to CustomUser model and update related serializers, migrations, and UI components
This commit is contained in:
parent
2af78e0a53
commit
31630de4fd
9 changed files with 76 additions and 21 deletions
|
@ -82,11 +82,11 @@ from users.models import CustomUser
|
||||||
|
|
||||||
class CustomUserAdmin(UserAdmin):
|
class CustomUserAdmin(UserAdmin):
|
||||||
model = CustomUser
|
model = CustomUser
|
||||||
list_display = ['username', 'is_staff', 'is_active', 'image_display']
|
list_display = ['username', 'is_staff', 'is_active', 'image_display', 'measurement_system']
|
||||||
readonly_fields = ('uuid',)
|
readonly_fields = ('uuid',)
|
||||||
search_fields = ('username',)
|
search_fields = ('username',)
|
||||||
fieldsets = UserAdmin.fieldsets + (
|
fieldsets = UserAdmin.fieldsets + (
|
||||||
(None, {'fields': ('profile_pic', 'uuid', 'public_profile', 'disable_password')}),
|
(None, {'fields': ('profile_pic', 'uuid', 'public_profile', 'disable_password', 'measurement_system')}),
|
||||||
)
|
)
|
||||||
def image_display(self, obj):
|
def image_display(self, obj):
|
||||||
if obj.profile_pic:
|
if obj.profile_pic:
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 5.2.2 on 2025-08-05 15:45
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('users', '0004_customuser_disable_password'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='customuser',
|
||||||
|
name='measurement_system',
|
||||||
|
field=models.CharField(choices=[('metric', 'Metric'), ('imperial', 'Imperial')], default='metric', max_length=10),
|
||||||
|
),
|
||||||
|
]
|
|
@ -9,6 +9,7 @@ class CustomUser(AbstractUser):
|
||||||
uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
|
uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
|
||||||
public_profile = models.BooleanField(default=False)
|
public_profile = models.BooleanField(default=False)
|
||||||
disable_password = models.BooleanField(default=False)
|
disable_password = models.BooleanField(default=False)
|
||||||
|
measurement_system = models.CharField(max_length=10, choices=[('metric', 'Metric'), ('imperial', 'Imperial')], default='metric')
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.username
|
return self.username
|
|
@ -50,7 +50,7 @@ class UserDetailsSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CustomUser
|
model = CustomUser
|
||||||
extra_fields = ['profile_pic', 'uuid', 'public_profile']
|
extra_fields = ['profile_pic', 'uuid', 'public_profile', 'measurement_system']
|
||||||
|
|
||||||
if hasattr(UserModel, 'USERNAME_FIELD'):
|
if hasattr(UserModel, 'USERNAME_FIELD'):
|
||||||
extra_fields.append(UserModel.USERNAME_FIELD)
|
extra_fields.append(UserModel.USERNAME_FIELD)
|
||||||
|
@ -66,6 +66,8 @@ class UserDetailsSerializer(serializers.ModelSerializer):
|
||||||
extra_fields.append('is_staff')
|
extra_fields.append('is_staff')
|
||||||
if hasattr(UserModel, 'disable_password'):
|
if hasattr(UserModel, 'disable_password'):
|
||||||
extra_fields.append('disable_password')
|
extra_fields.append('disable_password')
|
||||||
|
if hasattr(UserModel, 'measurement_system'):
|
||||||
|
extra_fields.append('measurement_system')
|
||||||
|
|
||||||
fields = ['pk', *extra_fields]
|
fields = ['pk', *extra_fields]
|
||||||
read_only_fields = ('email', 'date_joined', 'is_staff', 'is_superuser', 'is_active', 'pk', 'disable_password')
|
read_only_fields = ('email', 'date_joined', 'is_staff', 'is_superuser', 'is_active', 'pk', 'disable_password')
|
||||||
|
@ -96,7 +98,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', 'has_password', 'disable_password']
|
fields = UserDetailsSerializer.Meta.fields + ['profile_pic', 'uuid', 'public_profile', 'has_password', 'disable_password', 'measurement_system']
|
||||||
read_only_fields = UserDetailsSerializer.Meta.read_only_fields + ('uuid', 'has_password', 'disable_password')
|
read_only_fields = UserDetailsSerializer.Meta.read_only_fields + ('uuid', 'has_password', 'disable_password')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
1
frontend/src/app.d.ts
vendored
1
frontend/src/app.d.ts
vendored
|
@ -17,6 +17,7 @@ declare global {
|
||||||
public_profile: boolean;
|
public_profile: boolean;
|
||||||
has_password: boolean;
|
has_password: boolean;
|
||||||
disable_password: boolean;
|
disable_password: boolean;
|
||||||
|
measurement_system: 'metric' | 'imperial';
|
||||||
} | null;
|
} | null;
|
||||||
locale: string;
|
locale: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ export type User = {
|
||||||
public_profile: boolean;
|
public_profile: boolean;
|
||||||
has_password: boolean;
|
has_password: boolean;
|
||||||
disable_password: boolean;
|
disable_password: boolean;
|
||||||
|
measurement_system: 'metric' | 'imperial';
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ContentImage = {
|
export type ContentImage = {
|
||||||
|
|
|
@ -542,7 +542,9 @@
|
||||||
"data_override_warning_desc": "Restoring data will completely replace all existing data (that is included \t\t\t\t\t\t\t\t\t\t\t\tin the backup) in your account. This action cannot be undone.",
|
"data_override_warning_desc": "Restoring data will completely replace all existing data (that is included \t\t\t\t\t\t\t\t\t\t\t\tin the backup) in your account. This action cannot be undone.",
|
||||||
"select_backup_file": "Select backup file",
|
"select_backup_file": "Select backup file",
|
||||||
"data_override_acknowledge": "I acknowledge that this will override all my existing data",
|
"data_override_acknowledge": "I acknowledge that this will override all my existing data",
|
||||||
"data_override_acknowledge_desc": "This action is irreversible and will replace all locations, collections, \t\t\t\t\t\t\t\t\t\t\t\t\t\tand visits in your account."
|
"data_override_acknowledge_desc": "This action is irreversible and will replace all locations, collections, \t\t\t\t\t\t\t\t\t\t\t\t\t\tand visits in your account.",
|
||||||
|
"use_imperial": "Use Imperial Units",
|
||||||
|
"use_imperial_desc": "Use imperial units (feet, inches, pounds) instead of metric units"
|
||||||
},
|
},
|
||||||
"collection": {
|
"collection": {
|
||||||
"collection_created": "Collection created successfully!",
|
"collection_created": "Collection created successfully!",
|
||||||
|
|
|
@ -129,6 +129,7 @@ export const actions: Actions = {
|
||||||
let last_name = formData.get('last_name') as string | null | undefined;
|
let last_name = formData.get('last_name') as string | null | undefined;
|
||||||
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;
|
||||||
|
let measurement_system = formData.get('measurement_system') as string | null | undefined;
|
||||||
|
|
||||||
const resCurrent = await fetch(`${endpoint}/auth/user-metadata/`, {
|
const resCurrent = await fetch(`${endpoint}/auth/user-metadata/`, {
|
||||||
headers: {
|
headers: {
|
||||||
|
@ -148,6 +149,13 @@ export const actions: Actions = {
|
||||||
public_profile = false;
|
public_profile = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gets the boolean value of the measurement_system input checked means imperial
|
||||||
|
if (measurement_system === 'on') {
|
||||||
|
measurement_system = 'imperial';
|
||||||
|
} else {
|
||||||
|
measurement_system = 'metric';
|
||||||
|
}
|
||||||
|
|
||||||
let currentUser = (await resCurrent.json()) as User;
|
let currentUser = (await resCurrent.json()) as User;
|
||||||
|
|
||||||
if (username === currentUser.username || !username) {
|
if (username === currentUser.username || !username) {
|
||||||
|
@ -178,6 +186,7 @@ export const actions: Actions = {
|
||||||
formDataToSend.append('profile_pic', profile_pic);
|
formDataToSend.append('profile_pic', profile_pic);
|
||||||
}
|
}
|
||||||
formDataToSend.append('public_profile', public_profile.toString());
|
formDataToSend.append('public_profile', public_profile.toString());
|
||||||
|
formDataToSend.append('measurement_system', measurement_system.toString());
|
||||||
|
|
||||||
let csrfToken = await fetchCSRFToken();
|
let csrfToken = await fetchCSRFToken();
|
||||||
|
|
||||||
|
|
|
@ -515,23 +515,44 @@
|
||||||
accept="image/*"
|
accept="image/*"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<label class="label cursor-pointer justify-start gap-4">
|
<label class="label cursor-pointer justify-start gap-4">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
bind:checked={user.public_profile}
|
bind:checked={user.public_profile}
|
||||||
name="public_profile"
|
name="public_profile"
|
||||||
class="toggle toggle-primary"
|
class="toggle toggle-primary"
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<span class="label-text font-medium">{$t('auth.public_profile')}</span>
|
<span class="label-text font-medium">{$t('auth.public_profile')}</span>
|
||||||
<p class="text-sm text-base-content/60">
|
<p class="text-sm text-base-content/60">
|
||||||
{$t('settings.public_profile_desc')}
|
{$t('settings.public_profile_desc')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- metric or imperal toggle -->
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label cursor-pointer justify-start gap-4">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={user.measurement_system === 'imperial'}
|
||||||
|
name="measurement_system"
|
||||||
|
class="toggle toggle-primary"
|
||||||
|
on:change={() =>
|
||||||
|
(user.measurement_system =
|
||||||
|
user.measurement_system === 'metric' ? 'imperial' : 'metric')}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<span class="label-text font-medium">{$t('settings.use_imperial')}</span>
|
||||||
|
<p class="text-sm text-base-content/60">
|
||||||
|
{$t('settings.use_imperial_desc')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="btn btn-primary btn-wide">
|
<button class="btn btn-primary btn-wide">
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue