mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-07-30 18:29:37 +02:00
feat: Add additional adventure type and endpoint for sunrise/sunset information
This commit is contained in:
parent
13d3b24ec2
commit
16a7772003
5 changed files with 146 additions and 95 deletions
|
@ -10,6 +10,7 @@ from adventures.models import Adventure, Category, Transportation, Lodging
|
|||
from adventures.permissions import IsOwnerOrSharedWithFullAccess
|
||||
from adventures.serializers import AdventureSerializer, TransportationSerializer, LodgingSerializer
|
||||
from adventures.utils import pagination
|
||||
import requests
|
||||
|
||||
class AdventureViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = AdventureSerializer
|
||||
|
@ -170,48 +171,38 @@ class AdventureViewSet(viewsets.ModelViewSet):
|
|||
serializer = self.get_serializer(queryset, many=True)
|
||||
return Response(serializer.data)
|
||||
|
||||
# @action(detail=True, methods=['post'])
|
||||
# def convert(self, request, pk=None):
|
||||
# """
|
||||
# Convert an Adventure instance into a Transportation or Lodging instance.
|
||||
# Expects a JSON body with "target_type": "transportation" or "lodging".
|
||||
# """
|
||||
# adventure = self.get_object()
|
||||
# target_type = request.data.get("target_type", "").lower()
|
||||
@action(detail=True, methods=['get'], url_path='additional-info')
|
||||
def additional_info(self, request, pk=None):
|
||||
adventure = self.get_object()
|
||||
|
||||
# if target_type not in ["transportation", "lodging"]:
|
||||
# return Response(
|
||||
# {"error": "Invalid target type. Must be 'transportation' or 'lodging'."},
|
||||
# status=400
|
||||
# )
|
||||
# if not adventure.collection:
|
||||
# return Response(
|
||||
# {"error": "Adventure must be part of a collection to be converted."},
|
||||
# status=400
|
||||
# )
|
||||
# Permission check: owner or shared collection member
|
||||
if adventure.user_id != request.user:
|
||||
if not (adventure.collection and adventure.collection.shared_with.filter(id=request.user.id).exists()):
|
||||
return Response({"error": "User does not have permission to access this adventure"},
|
||||
status=status.HTTP_403_FORBIDDEN)
|
||||
|
||||
# # Define the overlapping fields that both the Adventure and target models share.
|
||||
# overlapping_fields = ["name", "description", "is_public", 'collection']
|
||||
serializer = self.get_serializer(adventure)
|
||||
response_data = serializer.data
|
||||
|
||||
# # Gather the overlapping data from the adventure instance.
|
||||
# conversion_data = {}
|
||||
# for field in overlapping_fields:
|
||||
# if hasattr(adventure, field):
|
||||
# conversion_data[field] = getattr(adventure, field)
|
||||
visits = response_data.get('visits', [])
|
||||
sun_times = []
|
||||
|
||||
# # Make sure to include the user reference
|
||||
# conversion_data["user_id"] = adventure.user_id
|
||||
for visit in visits:
|
||||
date = visit.get('start_date')
|
||||
if date and adventure.longitude and adventure.latitude:
|
||||
api_url = f'https://api.sunrisesunset.io/json?lat={adventure.latitude}&lng={adventure.longitude}&date={date}'
|
||||
res = requests.get(api_url)
|
||||
if res.status_code == 200:
|
||||
data = res.json()
|
||||
results = data.get('results', {})
|
||||
if results.get('sunrise') and results.get('sunset'):
|
||||
sun_times.append({
|
||||
"date": date,
|
||||
"visit_id": visit.get('id'),
|
||||
"sunrise": results.get('sunrise'),
|
||||
"sunset": results.get('sunset')
|
||||
})
|
||||
|
||||
# # Convert the adventure instance within an atomic transaction.
|
||||
# with transaction.atomic():
|
||||
# if target_type == "transportation":
|
||||
# new_instance = Transportation.objects.create(**conversion_data)
|
||||
# serializer = TransportationSerializer(new_instance)
|
||||
# else: # target_type == "lodging"
|
||||
# new_instance = Lodging.objects.create(**conversion_data)
|
||||
# serializer = LodgingSerializer(new_instance)
|
||||
|
||||
# # Optionally, delete the original adventure to avoid duplicates.
|
||||
# adventure.delete()
|
||||
|
||||
# return Response(serializer.data)
|
||||
response_data['sun_times'] = sun_times
|
||||
return Response(response_data)
|
|
@ -44,6 +44,15 @@ export type Adventure = {
|
|||
user?: User | null;
|
||||
};
|
||||
|
||||
export type AdditionalAdventure = Adventure & {
|
||||
sun_times: {
|
||||
date: string;
|
||||
visit_id: string;
|
||||
sunrise: string;
|
||||
sunset: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
export type Country = {
|
||||
id: number;
|
||||
name: string;
|
||||
|
|
|
@ -90,6 +90,8 @@
|
|||
"visits": "Visits",
|
||||
"create_new": "Create New...",
|
||||
"adventure": "Adventure",
|
||||
"additional_info": "Additional Information",
|
||||
"sunrise_sunset": "Sunrise & Sunset",
|
||||
"count_txt": "results matching your search",
|
||||
"sort": "Sort",
|
||||
"order_by": "Order By",
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import type { PageServerLoad } from './$types';
|
||||
const PUBLIC_SERVER_URL = process.env['PUBLIC_SERVER_URL'];
|
||||
import type { Adventure, Collection } from '$lib/types';
|
||||
import type { AdditionalAdventure, Adventure, Collection } from '$lib/types';
|
||||
const endpoint = PUBLIC_SERVER_URL || 'http://localhost:8000';
|
||||
|
||||
export const load = (async (event) => {
|
||||
const id = event.params as { id: string };
|
||||
let request = await fetch(`${endpoint}/api/adventures/${id.id}/`, {
|
||||
let request = await fetch(`${endpoint}/api/adventures/${id.id}/additional-info/`, {
|
||||
headers: {
|
||||
Cookie: `sessionid=${event.cookies.get('sessionid')}`
|
||||
},
|
||||
|
@ -19,7 +19,7 @@ export const load = (async (event) => {
|
|||
}
|
||||
};
|
||||
} else {
|
||||
let adventure = (await request.json()) as Adventure;
|
||||
let adventure = (await request.json()) as AdditionalAdventure;
|
||||
let collection: Collection | null = null;
|
||||
|
||||
if (adventure.collection) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import type { Adventure } from '$lib/types';
|
||||
import type { AdditionalAdventure, Adventure } from '$lib/types';
|
||||
import { onMount } from 'svelte';
|
||||
import type { PageData } from './$types';
|
||||
import { goto } from '$app/navigation';
|
||||
|
@ -12,6 +12,7 @@
|
|||
import toGeoJSON from '@mapbox/togeojson';
|
||||
|
||||
import LightbulbOn from '~icons/mdi/lightbulb-on';
|
||||
import WeatherSunset from '~icons/mdi/weather-sunset';
|
||||
|
||||
let geojson: any;
|
||||
|
||||
|
@ -75,7 +76,7 @@
|
|||
export let data: PageData;
|
||||
console.log(data);
|
||||
|
||||
let adventure: Adventure;
|
||||
let adventure: AdditionalAdventure;
|
||||
|
||||
let currentSlide = 0;
|
||||
|
||||
|
@ -112,7 +113,7 @@
|
|||
await getGpxFiles();
|
||||
});
|
||||
|
||||
async function saveEdit(event: CustomEvent<Adventure>) {
|
||||
async function saveEdit(event: CustomEvent<AdditionalAdventure>) {
|
||||
adventure = event.detail;
|
||||
isEditModalOpen = false;
|
||||
geojson = null;
|
||||
|
@ -522,6 +523,53 @@
|
|||
</MapLibre>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Additional Info Display Section -->
|
||||
|
||||
<div>
|
||||
{#if adventure.sun_times && adventure.sun_times.length > 0}
|
||||
<h2 class="text-2xl font-bold mt-4 mb-4">{$t('adventures.additional_info')}</h2>
|
||||
{#if adventure.sun_times && adventure.sun_times.length > 0}
|
||||
<div class="collapse collapse-plus bg-base-200 mb-2 overflow-visible">
|
||||
<input type="checkbox" />
|
||||
<div class="collapse-title text-xl font-medium">
|
||||
<span>
|
||||
{$t('adventures.sunrise_sunset')}
|
||||
<WeatherSunset class="w-6 h-6 inline-block ml-2 -mt-1" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="collapse-content">
|
||||
<div class="grid gap-4 mt-4">
|
||||
<!-- Sunrise and Sunset times -->
|
||||
{#each adventure.sun_times as sun_time}
|
||||
<div class="grid md:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<p class="text-sm text-muted-foreground">Date</p>
|
||||
<p class="text-base font-medium">
|
||||
{new Date(sun_time.date).toLocaleDateString()}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm text-muted-foreground">Sunrise</p>
|
||||
<p class="text-base font-medium">
|
||||
{sun_time.sunrise}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm text-muted-foreground">Sunset</p>
|
||||
<p class="text-base font-medium">
|
||||
{sun_time.sunset}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
{#if adventure.attachments && adventure.attachments.length > 0}
|
||||
<div>
|
||||
<!-- attachments -->
|
||||
|
@ -579,6 +627,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue