mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-07-21 22:09:36 +02:00
Remove AUTHORS and MANIFEST.in files; add ReverseGeocodeViewSet and localization updates
This commit is contained in:
parent
05076a6732
commit
83d06fc0a4
13 changed files with 109 additions and 42 deletions
|
@ -1 +0,0 @@
|
||||||
http://github.com/iMerica/dj-rest-auth/contributors
|
|
|
@ -1,4 +1,10 @@
|
||||||
The MIT License (MIT)
|
# 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/
|
Copyright (c) 2014 iMerica https://github.com/iMerica/
|
||||||
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
include AUTHORS
|
|
||||||
include LICENSE
|
|
||||||
include MANIFEST.in
|
|
||||||
include README.md
|
|
||||||
graft dj_rest_auth
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
from rest_framework.routers import DefaultRouter
|
from rest_framework.routers import DefaultRouter
|
||||||
from .views import AdventureViewSet, ChecklistViewSet, CollectionViewSet, NoteViewSet, StatsViewSet, GenerateDescription, ActivityTypesView, TransportationViewSet, AdventureImageViewSet
|
from .views import AdventureViewSet, ChecklistViewSet, CollectionViewSet, NoteViewSet, StatsViewSet, GenerateDescription, ActivityTypesView, TransportationViewSet, AdventureImageViewSet, ReverseGeocodeViewSet
|
||||||
|
|
||||||
router = DefaultRouter()
|
router = DefaultRouter()
|
||||||
router.register(r'adventures', AdventureViewSet, basename='adventures')
|
router.register(r'adventures', AdventureViewSet, basename='adventures')
|
||||||
|
@ -12,6 +12,7 @@ router.register(r'transportations', TransportationViewSet, basename='transportat
|
||||||
router.register(r'notes', NoteViewSet, basename='notes')
|
router.register(r'notes', NoteViewSet, basename='notes')
|
||||||
router.register(r'checklists', ChecklistViewSet, basename='checklists')
|
router.register(r'checklists', ChecklistViewSet, basename='checklists')
|
||||||
router.register(r'images', AdventureImageViewSet, basename='images')
|
router.register(r'images', AdventureImageViewSet, basename='images')
|
||||||
|
router.register(r'reverse-geocode', ReverseGeocodeViewSet, basename='reverse-geocode')
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
import requests
|
import requests
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
@ -1053,3 +1054,42 @@ class AdventureImageViewSet(viewsets.ModelViewSet):
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
def perform_create(self, serializer):
|
||||||
serializer.save(user_id=self.request.user)
|
serializer.save(user_id=self.request.user)
|
||||||
|
|
||||||
|
class ReverseGeocodeViewSet(viewsets.ViewSet):
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
def extractIsoCode(self, data):
|
||||||
|
"""
|
||||||
|
Extract the ISO code from the response data.
|
||||||
|
Returns a dictionary containing the region name, country name, and ISO code if found.
|
||||||
|
"""
|
||||||
|
iso_code = None
|
||||||
|
if 'address' in data.keys():
|
||||||
|
keys = data['address'].keys()
|
||||||
|
for key in keys:
|
||||||
|
if key.find("ISO") != -1:
|
||||||
|
iso_code = data['address'][key]
|
||||||
|
print(iso_code)
|
||||||
|
region = Region.objects.filter(id=iso_code).first()
|
||||||
|
visited_region = VisitedRegion.objects.filter(region=region).first()
|
||||||
|
is_visited = False
|
||||||
|
if visited_region:
|
||||||
|
is_visited = True
|
||||||
|
if region:
|
||||||
|
return {"id": iso_code, "region": region.name, "country": region.country.name, "is_visited": is_visited}
|
||||||
|
return {"error": "No region found"}
|
||||||
|
|
||||||
|
@action(detail=False, methods=['get'])
|
||||||
|
def reverse_geocode(self, request):
|
||||||
|
lat = request.query_params.get('lat', '')
|
||||||
|
lon = request.query_params.get('lon', '')
|
||||||
|
print(lat, lon)
|
||||||
|
url = f"https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat={lat}&lon={lon}"
|
||||||
|
headers = {'User-Agent': 'AdventureLog Server'}
|
||||||
|
response = requests.get(url, headers=headers)
|
||||||
|
try:
|
||||||
|
data = response.json()
|
||||||
|
except requests.exceptions.JSONDecodeError:
|
||||||
|
return Response({"error": "Invalid response from geocoding service"}, status=400)
|
||||||
|
return Response(self.extractIsoCode(data))
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import type { Adventure, User } from '$lib/types';
|
import type { Adventure, User } from '$lib/types';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
import type { ActionResult } from '@sveltejs/kit';
|
import { t } from 'svelte-i18n';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import AdventureCard from './AdventureCard.svelte';
|
import AdventureCard from './AdventureCard.svelte';
|
||||||
let modal: HTMLDialogElement;
|
let modal: HTMLDialogElement;
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
||||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||||
<div class="modal-box w-11/12 max-w-5xl" role="dialog" on:keydown={handleKeydown} tabindex="0">
|
<div class="modal-box w-11/12 max-w-5xl" role="dialog" on:keydown={handleKeydown} tabindex="0">
|
||||||
<h1 class="text-center font-bold text-4xl mb-6">My Adventures</h1>
|
<h1 class="text-center font-bold text-4xl mb-6">{$t('adventures.my_adventures')}</h1>
|
||||||
{#if isLoading}
|
{#if isLoading}
|
||||||
<div class="flex justify-center items-center w-full mt-16">
|
<div class="flex justify-center items-center w-full mt-16">
|
||||||
<span class="loading loading-spinner w-24 h-24"></span>
|
<span class="loading loading-spinner w-24 h-24"></span>
|
||||||
|
@ -63,10 +63,10 @@
|
||||||
{/each}
|
{/each}
|
||||||
{#if adventures.length === 0 && !isLoading}
|
{#if adventures.length === 0 && !isLoading}
|
||||||
<p class="text-center text-lg">
|
<p class="text-center text-lg">
|
||||||
No adventures found that can be linked to this collection.
|
{$t('adventures.no_linkable_adventures')}
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-primary" on:click={close}>Close</button>
|
<button class="btn btn-primary" on:click={close}>{$t('about.close')}</button>
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import type { Adventure, Collection, OpenStreetMapPlace, Point } from '$lib/types';
|
import type {
|
||||||
|
Adventure,
|
||||||
|
Collection,
|
||||||
|
OpenStreetMapPlace,
|
||||||
|
Point,
|
||||||
|
ReverseGeocode
|
||||||
|
} from '$lib/types';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { enhance } from '$app/forms';
|
import { enhance } from '$app/forms';
|
||||||
import { addToast } from '$lib/toasts';
|
import { addToast } from '$lib/toasts';
|
||||||
|
@ -27,6 +33,8 @@
|
||||||
|
|
||||||
let noPlaces: boolean = false;
|
let noPlaces: boolean = false;
|
||||||
|
|
||||||
|
let reverseGeocodePlace: ReverseGeocode | null = null;
|
||||||
|
|
||||||
let adventure: Adventure = {
|
let adventure: Adventure = {
|
||||||
id: '',
|
id: '',
|
||||||
name: '',
|
name: '',
|
||||||
|
@ -136,6 +144,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: {
|
||||||
|
if (adventure.longitude && adventure.latitude) {
|
||||||
|
reverseGeocode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function fetchImage() {
|
async function fetchImage() {
|
||||||
let res = await fetch(url);
|
let res = await fetch(url);
|
||||||
let data = await res.blob();
|
let data = await res.blob();
|
||||||
|
@ -249,29 +263,15 @@
|
||||||
|
|
||||||
async function reverseGeocode() {
|
async function reverseGeocode() {
|
||||||
let res = await fetch(
|
let res = await fetch(
|
||||||
`https://nominatim.openstreetmap.org/search?q=${adventure.latitude},${adventure.longitude}&format=jsonv2`,
|
`/api/reverse-geocode/reverse_geocode/?lat=${adventure.latitude}&lon=${adventure.longitude}`
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
'User-Agent': `AdventureLog / ${appVersion} `
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
let data = (await res.json()) as OpenStreetMapPlace[];
|
let data = await res.json();
|
||||||
if (data.length > 0) {
|
if (data.error) {
|
||||||
adventure.name = data[0]?.name || '';
|
console.log(data.error);
|
||||||
adventure.activity_types?.push(data[0]?.type || '');
|
reverseGeocodePlace = null;
|
||||||
adventure.location = data[0]?.display_name || '';
|
return;
|
||||||
if (longitude && latitude) {
|
|
||||||
markers = [
|
|
||||||
{
|
|
||||||
lngLat: { lng: longitude, lat: latitude },
|
|
||||||
location: data[0]?.display_name || '',
|
|
||||||
name: data[0]?.name || '',
|
|
||||||
activity_type: data[0]?.type || ''
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
reverseGeocodePlace = data;
|
||||||
console.log(data);
|
console.log(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -610,6 +610,13 @@ it would also work to just use on:click on the MapLibre component itself. -->
|
||||||
<DefaultMarker lngLat={marker.lngLat} />
|
<DefaultMarker lngLat={marker.lngLat} />
|
||||||
{/each}
|
{/each}
|
||||||
</MapLibre>
|
</MapLibre>
|
||||||
|
{#if reverseGeocodePlace}
|
||||||
|
<div class="mt-2">
|
||||||
|
<p>{reverseGeocodePlace.id}</p>
|
||||||
|
<p>{reverseGeocodePlace.region}, {reverseGeocodePlace.country}</p>
|
||||||
|
<p>{reverseGeocodePlace.is_visited ? 'Visited' : 'Not Visited'}</p>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import CollectionCard from './CollectionCard.svelte';
|
import CollectionCard from './CollectionCard.svelte';
|
||||||
let modal: HTMLDialogElement;
|
let modal: HTMLDialogElement;
|
||||||
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
let collections: Collection[] = [];
|
let collections: Collection[] = [];
|
||||||
|
|
||||||
|
@ -44,15 +45,15 @@
|
||||||
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
||||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||||
<div class="modal-box w-11/12 max-w-5xl" role="dialog" on:keydown={handleKeydown} tabindex="0">
|
<div class="modal-box w-11/12 max-w-5xl" role="dialog" on:keydown={handleKeydown} tabindex="0">
|
||||||
<h1 class="text-center font-bold text-4xl mb-6">My Collections</h1>
|
<h1 class="text-center font-bold text-4xl mb-6">{$t('adventures.my_collections')}</h1>
|
||||||
<div class="flex flex-wrap gap-4 mr-4 justify-center content-center">
|
<div class="flex flex-wrap gap-4 mr-4 justify-center content-center">
|
||||||
{#each collections as collection}
|
{#each collections as collection}
|
||||||
<CollectionCard {collection} type="link" on:link={link} />
|
<CollectionCard {collection} type="link" on:link={link} />
|
||||||
{/each}
|
{/each}
|
||||||
{#if collections.length === 0}
|
{#if collections.length === 0}
|
||||||
<p class="text-center text-lg">No collections found to add this adventure to.</p>
|
<p class="text-center text-lg">{$t('adventures.no_collections_found')}</p>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-primary" on:click={close}>Close</button>
|
<button class="btn btn-primary" on:click={close}>{$t('about.close')}</button>
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Lost from '$lib/assets/undraw_lost.svg';
|
import Lost from '$lib/assets/undraw_lost.svg';
|
||||||
export let error: string | undefined;
|
export let error: string | undefined;
|
||||||
|
import { t } from 'svelte-i18n';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
@ -11,12 +12,11 @@
|
||||||
<img src={Lost} alt="Lost" class="w-1/2" />
|
<img src={Lost} alt="Lost" class="w-1/2" />
|
||||||
</div>
|
</div>
|
||||||
<h1 class="mt-4 text-3xl font-bold tracking-tight text-foreground sm:text-4xl">
|
<h1 class="mt-4 text-3xl font-bold tracking-tight text-foreground sm:text-4xl">
|
||||||
No adventures found
|
{$t('adventures.no_adventures_found')}
|
||||||
</h1>
|
</h1>
|
||||||
{#if !error}
|
{#if !error}
|
||||||
<p class="mt-4 text-muted-foreground">
|
<p class="mt-4 text-muted-foreground">
|
||||||
There are no adventures to display. Add some using the plus button at the bottom right or
|
{$t('adventures.adventure_not_found')}
|
||||||
try changing filters!
|
|
||||||
</p>
|
</p>
|
||||||
{:else}
|
{:else}
|
||||||
<p class="text-error mt-2">{error}</p>
|
<p class="text-error mt-2">{error}</p>
|
||||||
|
|
|
@ -168,3 +168,10 @@ export type Background = {
|
||||||
author?: string;
|
author?: string;
|
||||||
location?: string;
|
location?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ReverseGeocode = {
|
||||||
|
id: string;
|
||||||
|
region: string;
|
||||||
|
country: string;
|
||||||
|
is_visited: boolean;
|
||||||
|
};
|
||||||
|
|
|
@ -101,6 +101,8 @@
|
||||||
"wikipedia": "Wikipedia",
|
"wikipedia": "Wikipedia",
|
||||||
"add_notes": "Add notes",
|
"add_notes": "Add notes",
|
||||||
"warning": "Warning",
|
"warning": "Warning",
|
||||||
|
"my_adventures": "My Adventures",
|
||||||
|
"no_linkable_adventures": "No adventures found that can be linked to this collection.",
|
||||||
"add": "Add",
|
"add": "Add",
|
||||||
"save_next": "Save & Next",
|
"save_next": "Save & Next",
|
||||||
"end_date": "End Date",
|
"end_date": "End Date",
|
||||||
|
@ -136,6 +138,7 @@
|
||||||
"edit_collection": "Edit Collection",
|
"edit_collection": "Edit Collection",
|
||||||
"unarchive": "Unarchive",
|
"unarchive": "Unarchive",
|
||||||
"archive": "Archive",
|
"archive": "Archive",
|
||||||
|
"no_collections_found": "No collections found to add this adventure to.",
|
||||||
"archived_collection_message": "Collection archived successfully!",
|
"archived_collection_message": "Collection archived successfully!",
|
||||||
"unarchived_collection_message": "Collection unarchived successfully!",
|
"unarchived_collection_message": "Collection unarchived successfully!",
|
||||||
"delete_collection_success": "Collection deleted successfully!",
|
"delete_collection_success": "Collection deleted successfully!",
|
||||||
|
@ -168,6 +171,8 @@
|
||||||
"adventure_update_error": "Failed to update adventure",
|
"adventure_update_error": "Failed to update adventure",
|
||||||
"new_adventure": "New Adventure",
|
"new_adventure": "New Adventure",
|
||||||
"basic_information": "Basic Information",
|
"basic_information": "Basic Information",
|
||||||
|
"adventure_not_found": "There are no adventures to display. Add some using the plus button at the bottom right or try changing filters!",
|
||||||
|
"no_adventures_found": "No adventures found",
|
||||||
"activities": {
|
"activities": {
|
||||||
"general": "General 🌍",
|
"general": "General 🌍",
|
||||||
"outdoor": "Outdoor 🏞️",
|
"outdoor": "Outdoor 🏞️",
|
||||||
|
|
|
@ -191,7 +191,12 @@
|
||||||
"warning": "Advertencia",
|
"warning": "Advertencia",
|
||||||
"wiki_desc": "Extrae un extracto de un artículo de Wikipedia que coincide con el nombre de la aventura.",
|
"wiki_desc": "Extrae un extracto de un artículo de Wikipedia que coincide con el nombre de la aventura.",
|
||||||
"wikipedia": "Wikipedia",
|
"wikipedia": "Wikipedia",
|
||||||
"add_an_activity": "Agregar una actividad"
|
"add_an_activity": "Agregar una actividad",
|
||||||
|
"adventure_not_found": "No hay aventuras que mostrar. \n¡Agregue algunos usando el botón más en la parte inferior derecha o intente cambiar los filtros!",
|
||||||
|
"no_adventures_found": "No se encontraron aventuras",
|
||||||
|
"no_collections_found": "No se encontraron colecciones para agregar esta aventura.",
|
||||||
|
"my_adventures": "mis aventuras",
|
||||||
|
"no_linkable_adventures": "No se encontraron aventuras que puedan vincularse a esta colección."
|
||||||
},
|
},
|
||||||
"worldtravel": {
|
"worldtravel": {
|
||||||
"all": "Todo",
|
"all": "Todo",
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import CollectionCard from '$lib/components/CollectionCard.svelte';
|
import CollectionCard from '$lib/components/CollectionCard.svelte';
|
||||||
import NotFound from '$lib/components/NotFound.svelte';
|
import NotFound from '$lib/components/NotFound.svelte';
|
||||||
import type { Collection } from '$lib/types';
|
import type { Collection } from '$lib/types';
|
||||||
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
export let data: any;
|
export let data: any;
|
||||||
console.log(data);
|
console.log(data);
|
||||||
|
@ -16,7 +17,7 @@
|
||||||
<div class="drawer lg:drawer-open">
|
<div class="drawer lg:drawer-open">
|
||||||
<div class="drawer-content">
|
<div class="drawer-content">
|
||||||
<!-- Page content -->
|
<!-- Page content -->
|
||||||
<h1 class="text-center font-bold text-4xl mb-6">Archived Collections</h1>
|
<h1 class="text-center font-bold text-4xl mb-6">{$t('adventures.archived_collections')}</h1>
|
||||||
{#if collections.length === 0}
|
{#if collections.length === 0}
|
||||||
<NotFound error={undefined} />
|
<NotFound error={undefined} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue