1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-07-19 12:59:36 +02:00

Refactor user ID handling to use UUIDs; update related components and serializers for consistency

This commit is contained in:
Sean Morley 2024-11-17 16:34:46 -05:00
parent 129c76078e
commit 86d213bb8b
18 changed files with 78 additions and 46 deletions

View file

@ -2,8 +2,10 @@ from django.utils import timezone
import os
from .models import Adventure, AdventureImage, ChecklistItem, Collection, Note, Transportation, Checklist, Visit, Category
from rest_framework import serializers
from main.utils import CustomModelSerializer
class AdventureImageSerializer(serializers.ModelSerializer):
class AdventureImageSerializer(CustomModelSerializer):
class Meta:
model = AdventureImage
fields = ['id', 'image', 'adventure']
@ -19,11 +21,12 @@ class AdventureImageSerializer(serializers.ModelSerializer):
representation['image'] = f"{public_url}/media/{instance.image.name}"
return representation
class CategorySerializer(serializers.ModelSerializer):
class CategorySerializer(CustomModelSerializer):
num_adventures = serializers.SerializerMethodField()
class Meta:
model = Category
fields = ['id', 'name', 'display_name', 'icon', 'user_id']
read_only_fields = ['id', 'user_id']
fields = ['id', 'name', 'display_name', 'icon', 'user_id', 'num_adventures']
read_only_fields = ['id', 'user_id', 'num_adventures']
def validate_name(self, value):
if Category.objects.filter(name=value).exists():
@ -31,14 +34,17 @@ class CategorySerializer(serializers.ModelSerializer):
return value
class VisitSerializer(serializers.ModelSerializer):
def get_num_adventures(self, obj):
return Adventure.objects.filter(category=obj, user_id=obj.user_id).count()
class VisitSerializer(CustomModelSerializer):
class Meta:
model = Visit
fields = ['id', 'start_date', 'end_date', 'notes']
read_only_fields = ['id']
class AdventureSerializer(serializers.ModelSerializer):
class AdventureSerializer(CustomModelSerializer):
images = AdventureImageSerializer(many=True, read_only=True)
visits = VisitSerializer(many=True, read_only=False)
category = CategorySerializer(read_only=True)
@ -102,7 +108,7 @@ class AdventureSerializer(serializers.ModelSerializer):
return instance
class TransportationSerializer(serializers.ModelSerializer):
class TransportationSerializer(CustomModelSerializer):
class Meta:
model = Transportation
@ -113,7 +119,7 @@ class TransportationSerializer(serializers.ModelSerializer):
]
read_only_fields = ['id', 'created_at', 'updated_at', 'user_id']
class NoteSerializer(serializers.ModelSerializer):
class NoteSerializer(CustomModelSerializer):
class Meta:
model = Note
@ -123,7 +129,7 @@ class NoteSerializer(serializers.ModelSerializer):
]
read_only_fields = ['id', 'created_at', 'updated_at', 'user_id']
class ChecklistItemSerializer(serializers.ModelSerializer):
class ChecklistItemSerializer(CustomModelSerializer):
class Meta:
model = ChecklistItem
fields = [
@ -131,7 +137,7 @@ class ChecklistItemSerializer(serializers.ModelSerializer):
]
read_only_fields = ['id', 'created_at', 'updated_at', 'user_id', 'checklist']
class ChecklistSerializer(serializers.ModelSerializer):
class ChecklistSerializer(CustomModelSerializer):
items = ChecklistItemSerializer(many=True, source='checklistitem_set')
class Meta:
model = Checklist
@ -194,7 +200,7 @@ class ChecklistSerializer(serializers.ModelSerializer):
return data
class CollectionSerializer(serializers.ModelSerializer):
class CollectionSerializer(CustomModelSerializer):
adventures = AdventureSerializer(many=True, read_only=True, source='adventure_set')
transportations = TransportationSerializer(many=True, read_only=True, source='transportation_set')
notes = NoteSerializer(many=True, read_only=True, source='note_set')

View file

@ -0,0 +1,10 @@
from rest_framework import serializers
def get_user_uuid(user):
return str(user.uuid)
class CustomModelSerializer(serializers.ModelSerializer):
def to_representation(self, instance):
representation = super().to_representation(instance)
representation['user_id'] = get_user_uuid(instance.user_id)
return representation

View file

@ -196,6 +196,7 @@ class CustomUserDetailsSerializer(UserDetailsSerializer):
# remove any ' from the url
public_url = public_url.replace("'", "")
representation['profile_pic'] = f"{public_url}/media/{instance.profile_pic.name}"
del representation['pk'] # remove the pk field from the response
return representation
class MyPasswordResetSerializer(PasswordResetSerializer):

View file

@ -1,6 +1,8 @@
import os
from .models import Country, Region, VisitedRegion
from rest_framework import serializers
from main.utils import CustomModelSerializer
class CountrySerializer(serializers.ModelSerializer):
def get_public_url(self, obj):
@ -36,7 +38,7 @@ class RegionSerializer(serializers.ModelSerializer):
fields = '__all__'
read_only_fields = ['id', 'name', 'country', 'longitude', 'latitude']
class VisitedRegionSerializer(serializers.ModelSerializer):
class VisitedRegionSerializer(CustomModelSerializer):
longitude = serializers.DecimalField(source='region.longitude', max_digits=9, decimal_places=6, read_only=True)
latitude = serializers.DecimalField(source='region.latitude', max_digits=9, decimal_places=6, read_only=True)
name = serializers.CharField(source='region.name', read_only=True)

View file

@ -167,7 +167,7 @@
<div class="card-actions justify-end mt-2">
<!-- action options dropdown -->
{#if type != 'link'}
{#if adventure.user_id == user?.pk || (collection && user && collection.shared_with.includes(user.uuid))}
{#if adventure.user_id == user?.uuid || (collection && user && collection.shared_with.includes(user.uuid))}
<div class="dropdown dropdown-end">
<div tabindex="0" role="button" class="btn btn-neutral-200">
<DotsHorizontal class="w-6 h-6" />
@ -188,7 +188,7 @@
</button>
<!-- remove from collection -->
{#if adventure.collection && user?.pk == adventure.user_id}
{#if adventure.collection && user?.uuid == adventure.user_id}
<button class="btn btn-neutral mb-2" on:click={removeFromCollection}
><LinkVariantRemove class="w-6 h-6" />{$t(
'adventures.remove_from_collection'

View file

@ -52,7 +52,14 @@
location: null,
images: [],
user_id: null,
collection: collection?.id || null
collection: collection?.id || null,
category: {
id: '',
name: '',
display_name: '',
icon: '',
user_id: ''
}
};
export let adventureToEdit: Adventure | null = null;
@ -73,7 +80,14 @@
user_id: adventureToEdit?.user_id || null,
collection: adventureToEdit?.collection || collection?.id || null,
visits: adventureToEdit?.visits || [],
is_visited: adventureToEdit?.is_visited || false
is_visited: adventureToEdit?.is_visited || false,
category: adventureToEdit?.category || {
id: '',
name: '',
display_name: '',
icon: '',
user_id: ''
}
};
let markers: Point[] = [];

View file

@ -53,7 +53,7 @@
on:change={() => toggleSelect(type.name)}
checked={types.indexOf(type.name) > -1}
/>
<span>{type.display_name + ' ' + type.icon}</span>
<span>{type.display_name + ' ' + type.icon + ` (${type.num_adventures})`}</span>
</label>
</li>
{/each}

View file

@ -56,7 +56,7 @@
<button class="btn btn-neutral-200 mb-2" on:click={editChecklist}>
<Launch class="w-6 h-6" />{$t('notes.open')}
</button>
{#if checklist.user_id == user?.pk || (collection && user && collection.shared_with.includes(user.uuid))}
{#if checklist.user_id == user?.uuid || (collection && user && collection.shared_with.includes(user.uuid))}
<button
id="delete_adventure"
data-umami-event="Delete Checklist"

View file

@ -34,7 +34,7 @@
name: newItem,
is_checked: newStatus,
id: '',
user_id: 0,
user_id: '',
checklist: 0,
created_at: '',
updated_at: ''
@ -135,7 +135,7 @@
<p class="font-semibold text-md mb-2">{$t('checklist.editing_checklist')} {initialName}</p>
{/if}
{#if (checklist && user?.pk == checklist?.user_id) || (user && collection && collection.shared_with.includes(user.uuid)) || !checklist}
{#if (checklist && user?.uuid == checklist?.user_id) || (user && collection && collection.shared_with.includes(user.uuid)) || !checklist}
<form on:submit|preventDefault>
<div class="form-control mb-2">
<label for="name">{$t('adventures.name')}</label>

View file

@ -8,7 +8,7 @@
import Calendar from '~icons/mdi/calendar';
let newCollection: Collection = {
user_id: NaN,
user_id: '',
id: '',
name: '',
description: '',

View file

@ -59,7 +59,7 @@
<button class="btn btn-neutral-200 mb-2" on:click={editNote}>
<Launch class="w-6 h-6" />{$t('notes.open')}
</button>
{#if note.user_id == user?.pk || (collection && user && collection.shared_with.includes(user.uuid))}
{#if note.user_id == user?.uuid || (collection && user && collection.shared_with.includes(user.uuid))}
<button
id="delete_adventure"
data-umami-event="Delete Adventure"

View file

@ -113,7 +113,7 @@
<p class="font-semibold text-md mb-2">{$t('notes.editing_note')} {initialName}</p>
{/if}
{#if (note && user?.pk == note?.user_id) || (collection && user && collection.shared_with.includes(user.uuid)) || !note}
{#if (note && user?.uuid == note?.user_id) || (collection && user && collection.shared_with.includes(user.uuid)) || !note}
<form on:submit|preventDefault>
<div class="form-control mb-2">
<label for="name">{$t('adventures.name')}</label>

View file

@ -59,7 +59,7 @@
{/if}
</div>
{#if transportation.user_id == user?.pk || (collection && user && collection.shared_with.includes(user.uuid))}
{#if transportation.user_id == user?.uuid || (collection && user && collection.shared_with.includes(user.uuid))}
<div class="card-actions justify-end">
<button on:click={deleteTransportation} class="btn btn-secondary"
><TrashCanOutline class="w-5 h-5 mr-1" /></button

View file

@ -13,7 +13,7 @@ export type User = {
export type Adventure = {
id: string;
user_id: number | null;
user_id: string | null;
type: string;
name: string;
location?: string | null;
@ -43,7 +43,7 @@ export type Adventure = {
name: string;
display_name: string;
icon: string;
user_id: number;
user_id: string;
};
};
@ -69,7 +69,7 @@ export type Region = {
export type VisitedRegion = {
id: number;
region: number;
user_id: number;
user_id: string;
longitude: number;
latitude: number;
name: string;
@ -87,7 +87,7 @@ export type Point = {
export type Collection = {
id: string;
user_id: number;
user_id: string;
name: string;
description: string;
is_public: boolean;
@ -122,7 +122,7 @@ export type OpenStreetMapPlace = {
export type Transportation = {
id: string;
user_id: number;
user_id: string;
type: string;
name: string;
description: string | null;
@ -141,7 +141,7 @@ export type Transportation = {
export type Note = {
id: string;
user_id: number;
user_id: string;
name: string;
content: string | null;
links: string[] | null;
@ -154,7 +154,7 @@ export type Note = {
export type Checklist = {
id: string;
user_id: number;
user_id: string;
name: string;
items: ChecklistItem[];
date: string | null; // ISO 8601 date string
@ -166,7 +166,7 @@ export type Checklist = {
export type ChecklistItem = {
id: string;
user_id: number;
user_id: string;
name: string;
is_checked: boolean;
checklist: number;
@ -193,5 +193,6 @@ export type Category = {
name: string;
display_name: string;
icon: string;
user_id: number;
user_id: string;
num_adventures: number;
};

View file

@ -15,7 +15,6 @@
console.log(data);
let adventures: Adventure[] = data.props.adventures || [];
let categories: Category[] = data.props.categories || [];
let currentSort = {
order_by: '',
@ -36,14 +35,13 @@
let typeString: string = '';
$: {
console.log(typeString);
if (typeof window !== 'undefined' && typeString) {
if (typeof window !== 'undefined') {
let url = new URL(window.location.href);
if (typeString) {
url.searchParams.set('types', typeString);
goto(url.toString(), { invalidateAll: true, replaceState: true });
} else if (typeof window !== 'undefined' && !typeString) {
let url = new URL(window.location.href);
url.searchParams.set('types', 'all');
} else {
url.searchParams.delete('types');
}
goto(url.toString(), { invalidateAll: true, replaceState: true });
}
}

View file

@ -82,7 +82,7 @@
{/if}
{#if adventure}
{#if data.user && data.user.pk == adventure.user_id}
{#if data.user && data.user.uuid == adventure.user_id}
<div class="fixed bottom-4 right-4 z-[999]">
<button class="btn m-1 size-16 btn-primary" on:click={() => (isEditModalOpen = true)}
><ClipboardList class="w-8 h-8" /></button

View file

@ -263,7 +263,7 @@
</div>
{/if}
{#if collection}
{#if data.user && !collection.is_archived}
{#if data.user && data.user.uuid && (data.user.uuid == collection.user_id || collection.shared_with.includes(data.user.uuid)) && !collection.is_archived}
<div class="fixed bottom-4 right-4 z-[999]">
<div class="flex flex-row items-center justify-center gap-4">
<div class="dropdown dropdown-top dropdown-end">
@ -275,7 +275,7 @@
tabindex="0"
class="dropdown-content z-[1] menu p-4 shadow bg-base-300 text-base-content rounded-box w-52 gap-4"
>
{#if collection.user_id === data.user.pk}
{#if collection.user_id === data.user.uuid}
<p class="text-center font-bold text-lg">{$t('adventures.link_new')}</p>
<button
class="btn btn-primary"

View file

@ -41,13 +41,13 @@
publicAdventures = data.props.adventures;
if (data.user?.pk != null) {
myAdventures = myAdventures.filter((adventure) => adventure.user_id === data.user?.pk);
myAdventures = myAdventures.filter((adventure) => adventure.user_id === data.user?.uuid);
} else {
myAdventures = [];
}
publicAdventures = publicAdventures.filter(
(adventure) => adventure.user_id !== data.user?.pk
(adventure) => adventure.user_id !== data.user?.uuid
);
if (data.props.osmData) {