Files
AdventureLog/install_adventurelog.sh
Sean Morley c39ff2449e [v0.12.0 pre] Planning & Itinerary Overhaul, Recommendation Engine, OIDC Enhancements, and More (#931)
* Fixes [REQUEST] Email-based auto-linking for OIDC
Fixes #921

* Add ClusterMap integration for regions and cities with fit-to-bounds functionality

* Update COUNTRY_REGION_JSON_VERSION to v3.0 and modify state ID generation to use ISO2 code

* fix: handle email verification required case during signup

Updated the signup action to return a specific message when the backend responds with a 401 status, indicating that the signup succeeded but email verification is required. This allows the frontend to display the appropriate message using an i18n key.

* feat: add Advanced Configuration documentation with optional environment variables

* Fixes #511

* fix: update appVersion to v0.11.0-main-121425 and enhance socialProviders handling in settings page

* feat: implement social signup controls and update documentation for new environment variables

* fix: update LocationCard props and enhance restore data functionality

- Changed the user prop to null in LocationCard component on the dashboard page.
- Added isRestoring state to manage loading state during data restoration in settings.
- Updated the restore button to show a loading spinner when a restore operation is in progress.

* fix: update appVersion to v0.12.0-pre-dev-121625

* feat: implement itinerary planning feature with CollectionItineraryPlanner component and related updates

* feat: add overnight lodging indicator and functionality to CollectionItineraryPlanner

* feat: add compact display option to LocationCard and enhance lodging filtering in CollectionItineraryPlanner

* feat(itinerary): add itinerary management features and link modal

- Introduced ItineraryViewSet for managing itinerary items with create and reorder functionalities.
- Added itinerary linking capabilities in CollectionModal and CollectionItineraryPlanner components.
- Implemented new ItineraryLinkModal for linking existing items to specific dates.
- Enhanced the frontend with new modals for creating locations, lodging, transportation, notes, and checklists.
- Updated the backend to handle itinerary item creation and reordering with appropriate permissions.
- Improved data handling for unscheduled items and their association with the itinerary.
- Added new dependencies to the frontend for enhanced functionality.

* feat(itinerary): implement auto-generate functionality for itinerary items based on dated records

* feat(collection): enhance collection sharing logic and improve data handling on invite acceptance

* fix: update appVersion to correct pre-dev version

* feat(wikipedia): implement image selection from Wikipedia with enhanced results display

* Refactor code structure for improved readability and maintainability

* feat: add CollectionRecommendationView component for displaying location recommendations

- Implemented CollectionRecommendationView.svelte to handle location recommendations based on user input and selected categories.
- Added Recommendation and RecommendationResponse types to types.ts for better type safety and structure.
- Updated collections/[id]/+page.svelte to include a new view for recommendations, allowing users to switch between different views seamlessly.

* fix: update appVersion and improve button accessibility in collection views

* feat: add canModify prop to collection components for user permission handling

* feat: add itinerary removal functionality to various cards and update UI components

- Implemented `removeFromItinerary` function in `LodgingCard`, `NoteCard`, and `TransportationCard` to allow users to remove items from their itinerary.
- Replaced the trash icon with a calendar remove icon in `LocationCard`, `LodgingCard`, `NoteCard`, and `TransportationCard` for better visual representation.
- Updated the dropdown menus in `LodgingCard`, `NoteCard`, and `TransportationCard` to include the new remove from itinerary option.
- Enhanced `CollectionItineraryPlanner` to pass itinerary items to the respective cards.
- Removed `PointSelectionModal.svelte` as it is no longer needed.
- Refactored `LocationMedia.svelte` to integrate `ImageManagement` component and clean up unused code related to image handling.

* feat: enhance itinerary management with deduplication and initial visit date handling

* feat: add FullMap component for enhanced map functionality with clustering support

- Introduced FullMap.svelte to handle map rendering, clustering, and marker management.
- Updated map page to utilize FullMap component, replacing direct MapLibre usage.
- Implemented clustering options and marker properties handling in FullMap.
- Added utility functions for resolving theme colors and managing marker states.
- Enhanced user experience with hover popups and improved loading states for location details.
- Updated app version to v0.12.0-pre-dev-122225.

* feat: enhance map interaction for touch devices with custom popup handling

* feat: add progress tracker for folder views to display visited and planned locations

* feat: add map center and zoom state management with URL synchronization

* feat: add status and days until start fields to collections with filtering options

* Component folder structure changes

* feat: add LodgingMedia and LodgingModal components for managing lodging details and media attachments

feat: implement LocationSearchMap component for interactive location searching and mapping functionality

* fix: update contentType in ImageManagement component to 'lodging' for correct media handling

* feat: enhance lodging management with date validation and update messages

* feat: implement lodging detail page with server-side loading and image modal functionality

- Added a new server-side load function to fetch lodging details by ID.
- Created a new Svelte component for the lodging detail page, including image carousel and map integration.
- Implemented a modal for displaying images with navigation.
- Enhanced URL handling in the locations page to only read parameters.

* feat: add Transportation modal component and related routes

- Implemented TransportationModal component for creating and editing transportation entries.
- Added server-side loading for transportation details in the new route [id]/+page.server.ts.
- Created a new Svelte page for displaying transportation details with image and attachment handling.
- Integrated modal for editing transportation in the transportation details page.
- Updated lodging routes to include a modal for editing lodging entries.
- Removed unused delete action from lodging server-side logic.

* feat: add start_code and end_code fields to Transportation model and update related components

* feat: implement date validation for itinerary items and add day picker modal for scheduling

* Reorder town and county checks in geocoding.py

Fix detection if only town exists for a location but county is no city name

* Use address keys only if city is found

* Make sure reverse geocoding uses correct key for cities (#938)

* Reorder town and county checks in geocoding.py

Fix detection if only town exists for a location but county is no city name

* Use address keys only if city is found

* Refactor code structure for improved readability and maintainability

* Enhance collection management with modal updates and item handling

* feat: integrate CollectionMap component in collections page and update map titles in lodging and transportation pages

- Replaced inline map implementation with CollectionMap component in collections/[id]/+page.svelte for better modularity.
- Updated the map title in lodging/[id]/+page.svelte to reflect lodging context.
- Updated the map title in transportations/[id]/+page.svelte to reflect transportation context.
- Added functionality to collect and render GeoJSON data from transportation attachments in transportations/[id]/+page.svelte.

* chore: update copyright year to 2026 in various files

* feat: enhance backup export functionality with itinerary items and export IDs

* fix: improve dropdown close behavior by handling multiple event types

* fix: remove unnecessary cache decorator from globespin function

* feat: add initial visit date support in ChecklistModal and NoteModal, with UI suggestions for prefilled dates

* feat: add details view for checklist and note cards with edit functionality

* feat: add travel duration and GPX distance calculation to Transportation model and UI

* feat: add primary image support to Collection model, serializers, and UI components

* Refactor calendar components and enhance event detail handling

- Replaced direct calendar implementation with a reusable CalendarComponent in the calendar route.
- Introduced EventDetailsModal for displaying event details, improving modularity and readability.
- Added functionality to fetch event details asynchronously when an event is clicked.
- Implemented ICS calendar download functionality with loading state management.
- Enhanced collections page to support calendar view, integrating event handling and timezone management.
- Improved lodging and transportation pages to display local time for stays and trips, including timezone badges.
- Cleaned up unused code and comments for better maintainability.

* feat: enhance hero image handling in collection view by prioritizing primary image

* chore: update .env.example to include account email verification configuration

* feat: enhance LodgingCard and TransportationCard components with expandable details and improved layout

* feat: add price and currency fields to locations, lodging, and transportation components

- Introduced price and price_currency fields in LocationModal, LodgingDetails, LodgingModal, TransportationDetails, and TransportationModal components.
- Implemented MoneyInput and CurrencyDropdown components for handling monetary values and currency selection.
- Updated data structures and types to accommodate new price and currency fields across various models.
- Enhanced cost summary calculations in collections and routes to display total costs by currency.
- Added user preference for default currency in settings, affecting new item forms.
- Updated UI to display price information in relevant components, ensuring consistent formatting and user experience.

* feat: add Development Timeline link to overview and create timeline documentation

* feat: enhance map functionality with search and zoom features

- Updated availableViews in collection page to include map view based on lodging and transportation locations.
- Added search functionality to the map page, allowing users to filter pins by name and category.
- Implemented auto-zoom feature to adjust the map view based on filtered search results.
- Introduced a search bar with a clear button for better user experience.

* feat: enhance ISO code extraction and region matching logic in extractIsoCode function

* feat: enhance extractIsoCode function with normalization for locality matching

* feat: update extractIsoCode function to include additional ISO3166 levels for improved region matching

* feat: enhance extractIsoCode function to handle cases without city information and update CollectionMap to bind user data

* feat: add cron job for syncing visited regions and cities, enhance Docker and supervisord configurations

* feat: add CollectionItineraryDay model and related functionality for itinerary day metadata management

* feat: implement cleanup of out-of-range itinerary items and notify users of potential impacts on itinerary when dates change

* Refactor collection page for improved localization and code clarity

- Removed unused imports and consolidated cost category labels to be reactive.
- Updated cost summary function to accept localized labels.
- Enhanced localization for various UI elements, including buttons, headings, and statistics.
- Improved user feedback messages for better clarity and consistency.
- Ensured all relevant text is translatable using the i18n library.

* feat: add collaborator serialization and display in collections

- Implemented `_build_profile_pic_url` and `_serialize_collaborator` functions for user profile picture URLs and serialization.
- Updated `CollectionSerializer` and `UltraSlimCollectionSerializer` to include collaborators in the serialized output.
- Enhanced `CollectionViewSet` to prefetch shared_with users for optimized queries.
- Modified frontend components to display collaborators in collection details, including profile pictures and initials.
- Added new localization strings for collaborators.
- Refactored map and location components to improve usability and functionality.
- Updated app version to reflect new changes.

* feat: add dynamic lodging icons based on type in CollectionMap component

* feat: add CollectionStats component for detailed trip statistics

- Implemented CollectionStats.svelte to display various statistics related to the collection, including distances, activities, and locations visited.
- Enhanced CollectionMap.svelte to filter activities based on date range using new getActivityDate function.
- Updated LocationSearchMap.svelte to handle airport mode for start and end locations.
- Modified types.ts to include is_global property in CollectionItineraryItem for trip-wide items.
- Updated +page.svelte to integrate the new stats view and manage view state accordingly.

* feat: enhance itinerary management by removing old items on date change for notes and checklists; normalize date handling in CollectionMap

* feat: add functionality to change day and move items to trip-wide itinerary

- Implemented changeDay function in ChecklistCard, LocationCard, LodgingCard, NoteCard, and TransportationCard components to allow users to change the scheduled day of items.
- Added a button to move items to the global (trip-wide) itinerary in the aforementioned components, with appropriate dispatch events.
- Enhanced CollectionItineraryPlanner to handle moving items to the global itinerary and added UI elements for unscheduled items.
- Updated ItineraryDayPickModal to support the deletion of source visits when moving locations.
- Added new translations for "Change Day" and "Move Trip Wide" in the English locale.

* fix: specify full path for python3 in cron job and add shell and path variables

* fix: update appVersion to v0.12.0-pre-dev-010726

* feat: enhance CollectionItineraryPlanner and CollectionStats with dynamic links and transport type normalization

* Add Dev Container + WSL install docs and link in install guide (#944) (#951)

* feat: enhance internationalization support in CollectionMap and CollectionStats components

- Added translation support for various labels and messages in CollectionMap.svelte and CollectionStats.svelte using svelte-i18n.
- Updated English and Chinese locale files to include new translation keys for improved user experience.
- Simplified the rendering of recommendation views in the collections page.

* Refactor itinerary management and UI components

- Updated ItineraryViewSet to handle visit updates and creations more efficiently, preserving visit IDs when moving between days.
- Enhanced ChecklistCard, LodgingCard, TransportationCard, and NoteCard to include a new "Change Day" option in the actions menu.
- Improved user experience in CollectionItineraryPlanner by tracking specific itinerary items being moved and ensuring only the relevant entries are deleted.
- Added new location sharing options in LodgingCard and TransportationCard for Apple Maps, Google Maps, and OpenStreetMap.
- Updated translations in en.json for consistency and clarity.
- Minor UI adjustments for better accessibility and usability across various components.

* feat: implement action menus and close event handling in card components

* feat: refactor Dockerfile and supervisord configuration to remove cron and add periodic sync script

* feat: enhance LocationSearchMap and TransportationDetails components with initialization handling and airport mode logic

* feat: add airport and location search mode labels to localization file

* feat: enhance periodic sync logging and improve airport mode handling in LocationSearchMap

* feat: enhance unscheduled items display with improved card interactions and accessibility

* Add dev compose for hot reload and update WSL dev container docs (#958)

* feat: enhance localization for itinerary linking and transportation components

* Localization: update localization files with new keys and values

* fix: improve error messages for Overpass API responses

* chore: update dependencies in frontend package.json and pnpm-lock.yaml

- Updated @sveltejs/adapter-node from ^5.2.12 to ^5.4.0
- Updated @sveltejs/adapter-vercel from ^5.7.0 to ^6.3.0
- Updated tailwindcss from ^3.4.17 to ^3.4.19
- Updated typescript from ^5.8.3 to ^5.9.3
- Updated vite from ^5.4.19 to ^5.4.21

* chore: update dependencies in pnpm-lock.yaml to latest versions

* Refactor code structure for improved readability and maintainability

* Refactor code structure for improved readability and maintainability

* fix: update package dependencies to resolve compatibility issues

* Add "worldtravel" translations to multiple locale files

- Added "worldtravel" key with translations for Spanish, French, Hungarian, Italian, Japanese, Korean, Dutch, Norwegian, Polish, Brazilian Portuguese, Russian, Slovak, Swedish, Turkish, Ukrainian, and Chinese.
- Updated the navigation section in each locale file to include the new "worldtravel" entry.

* Add new screenshots and update email verification message in locale file

* feat: Implement data restoration functionality with file import

- Added a new action `restoreData` in `+page.server.ts` to handle file uploads for restoring collections.
- Enhanced the UI in `+page.svelte` to include an import button and a modal for import progress.
- Integrated file input handling to trigger form submission upon file selection.
- Removed unused GSAP animations from the login, profile, and signup pages for cleaner code.

* feat: Add modals for creating locations and lodging from recommendations, enhance image import functionality

* fix: Adjust styles to prevent horizontal scroll and enhance floating action button visibility

* feat: Enhance error handling and messaging for Google Maps and OpenStreetMap geocoding functions

* fix: Enhance error messaging for Google Maps access forbidden response

* feat: Add User-Agent header to Google Maps API requests and refine error messaging for access forbidden response

* fix: Update User-Agent header in Google Maps API requests for improved compatibility

* fix: Disable proxy settings in Google Maps API request to prevent connection issues

* fix: Update Trivy security scan configuration and add .trivyignore for known false positives

* fix: Refactor update method to handle is_public cascading for related items

* feat: Integrate django-invitations for user invitation management and update settings

* feat: Add Tailwind CSS and DaisyUI plugin for styling

* feat: Add Tailwind CSS and DaisyUI plugin for styling

* feat: Add "Invite a User" guide and update navigation links

* docs: Update "Invite a User" guide to include email configuration tip

* feat: Update email invitation template for improved styling and clarity

* fix: Remove trailing backslash from installation note in Unraid documentation

* feat: Add export/import messages and user email verification prompts in multiple languages

* Squashed commit of the following:

commit a993a15b93ebb7521ae2e5cc31596b98b29fcd6c
Author: Alex <div@alexe.at>
Date:   Mon Jan 12 20:44:47 2026 +0100

    Translated using Weblate (German)

    Currently translated at 100.0% (1048 of 1048 strings)

    Translation: AdventureLog/Web App
    Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/de/

commit fdc455d9424fbb0f6b72179d9eb1340411700773
Author: Ettore Atalan <atalanttore@googlemail.com>
Date:   Sat Jan 10 23:24:23 2026 +0100

    Translated using Weblate (German)

    Currently translated at 100.0% (1048 of 1048 strings)

    Translation: AdventureLog/Web App
    Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/de/

commit 5942129c55e89dd999a13d4df9c40e6e3189355c
Author: Orhun <orhunavcu@gmail.com>
Date:   Sun Jan 11 13:05:31 2026 +0100

    Translated using Weblate (Turkish)

    Currently translated at 100.0% (1048 of 1048 strings)

    Translation: AdventureLog/Web App
    Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/tr/

commit 8712e43d8ba4a7e7fe163fb454d6577187f9a375
Author: Henrique Fonseca Veloso <henriquefv@tutamail.com>
Date:   Fri Jan 9 22:53:11 2026 +0100

    Translated using Weblate (Portuguese (Brazil))

    Currently translated at 99.9% (1047 of 1048 strings)

    Translation: AdventureLog/Web App
    Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/pt_BR/

commit 18ee56653470413afe8d71ecd2b5028f6e4cf118
Author: Anonymous <noreply@weblate.org>
Date:   Fri Jan 9 22:52:57 2026 +0100

    Translated using Weblate (Dutch)

    Currently translated at 99.9% (1047 of 1048 strings)

    Translation: AdventureLog/Web App
    Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/nl/

commit 57783c544e583c035c8b57b5c10ca320f25f399e
Author: Anonymous <noreply@weblate.org>
Date:   Fri Jan 9 22:52:14 2026 +0100

    Translated using Weblate (Arabic)

    Currently translated at 99.9% (1047 of 1048 strings)

    Translation: AdventureLog/Web App
    Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/ar/

commit fb09edfd85bc85234b1c1ba7dd499f2915093fff
Author: Anonymous <noreply@weblate.org>
Date:   Fri Jan 9 22:52:26 2026 +0100

    Translated using Weblate (Spanish)

    Currently translated at 99.9% (1047 of 1048 strings)

    Translation: AdventureLog/Web App
    Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/es/

commit 554a207d8e454a1f7ae826e2a40d389b94be5512
Author: Anonymous <noreply@weblate.org>
Date:   Fri Jan 9 22:52:21 2026 +0100

    Translated using Weblate (German)

    Currently translated at 99.9% (1047 of 1048 strings)

    Translation: AdventureLog/Web App
    Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/de/

commit b70b9db27fb8607beefeb288185601c8f5eae28d
Author: Anonymous <noreply@weblate.org>
Date:   Fri Jan 9 22:53:02 2026 +0100

    Translated using Weblate (Norwegian Bokmål)

    Currently translated at 99.9% (1047 of 1048 strings)

    Translation: AdventureLog/Web App
    Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/nb_NO/

commit 3b467caa9007c553e4ae7de97f53b6e462161ea3
Author: Anonymous <noreply@weblate.org>
Date:   Fri Jan 9 22:53:07 2026 +0100

    Translated using Weblate (Polish)

    Currently translated at 99.9% (1047 of 1048 strings)

    Translation: AdventureLog/Web App
    Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/pl/

commit 30fbbfba3572c8f78ec7c7e1a231e363aca1ef10
Author: Anonymous <noreply@weblate.org>
Date:   Fri Jan 9 22:53:17 2026 +0100

    Translated using Weblate (Russian)

    Currently translated at 99.9% (1047 of 1048 strings)

    Translation: AdventureLog/Web App
    Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/ru/

commit 8cecb492cfcac0a1f93ee8919f7b41d978d331ee
Author: Anonymous <noreply@weblate.org>
Date:   Fri Jan 9 22:52:42 2026 +0100

    Translated using Weblate (Italian)

    Currently translated at 99.9% (1047 of 1048 strings)

    Translation: AdventureLog/Web App
    Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/it/

commit f0d3d41029c89bfa83d5891ee7af70241f27b7be
Author: Anonymous <noreply@weblate.org>
Date:   Fri Jan 9 22:52:38 2026 +0100

    Translated using Weblate (Hungarian)

    Currently translated at 99.9% (1047 of 1048 strings)

    Translation: AdventureLog/Web App
    Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/hu/

commit 102e0f1912d010d38755a1713abb2a7f7564aafb
Author: Anonymous <noreply@weblate.org>
Date:   Fri Jan 9 22:53:21 2026 +0100

    Translated using Weblate (Slovak)

    Currently translated at 99.9% (1047 of 1048 strings)

    Translation: AdventureLog/Web App
    Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/sk/

commit 428b8f18cf6195a96b55109e0221413d82415a2f
Author: Максим Горпиніч <gorpinicmaksim0@gmail.com>
Date:   Sat Jan 10 08:55:28 2026 +0100

    Translated using Weblate (Ukrainian)

    Currently translated at 100.0% (1048 of 1048 strings)

    Translation: AdventureLog/Web App
    Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/uk/

commit 1a71aaf279ecab26c0c1fede05025732e6dcfa5e
Author: Anonymous <noreply@weblate.org>
Date:   Fri Jan 9 22:53:27 2026 +0100

    Translated using Weblate (Swedish)

    Currently translated at 99.9% (1047 of 1048 strings)

    Translation: AdventureLog/Web App
    Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/sv/

commit 36ec3701f3a1a904e7c42ac4ffbe6a050dc6d1ed
Author: Anonymous <noreply@weblate.org>
Date:   Fri Jan 9 22:53:43 2026 +0100

    Translated using Weblate (Chinese (Simplified Han script))

    Currently translated at 99.9% (1047 of 1048 strings)

    Translation: AdventureLog/Web App
    Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/zh_Hans/

commit 65d8b74b340c877cad2028b7142c783a1b568d49
Author: Anonymous <noreply@weblate.org>
Date:   Fri Jan 9 22:52:48 2026 +0100

    Translated using Weblate (Japanese)

    Currently translated at 99.9% (1047 of 1048 strings)

    Translation: AdventureLog/Web App
    Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/ja/

commit 4d11d1d31022583657e93aee70301a8ffcde1340
Author: Anonymous <noreply@weblate.org>
Date:   Fri Jan 9 22:52:52 2026 +0100

    Translated using Weblate (Korean)

    Currently translated at 99.9% (1047 of 1048 strings)

    Translation: AdventureLog/Web App
    Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/ko/

commit bd1135bcb965ad73cf493771b15081cc97cf513a
Author: Orhun <orhunavcu@gmail.com>
Date:   Fri Jan 9 22:53:33 2026 +0100

    Translated using Weblate (Turkish)

    Currently translated at 99.9% (1047 of 1048 strings)

    Translation: AdventureLog/Web App
    Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/tr/

commit 2c3d814119f4cf2dabd20933699f5b991f20f3e6
Author: Anonymous <noreply@weblate.org>
Date:   Fri Jan 9 22:52:32 2026 +0100

    Translated using Weblate (French)

    Currently translated at 99.9% (1047 of 1048 strings)

    Translation: AdventureLog/Web App
    Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/fr/

* Refactor code structure and remove redundant code blocks for improved readability and maintainability

* fix: Correct appVersion to match the latest pre-release version

* fix: Add missing vulnerability reference for jaraco.context in .trivyignore

---------

Co-authored-by: Lars Lehmann <33843261+larsl-net@users.noreply.github.com>
Co-authored-by: Lars Lehmann <lars@lmail.eu>
Co-authored-by: Nick Petrushin <n.a.petrushin@gmail.com>
2026-01-14 10:22:14 -05:00

797 lines
26 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
set -euo pipefail
# =============================================================================
# AdventureLog Installer Script
# (c) 2023-2026 Sean Morley <https://seanmorley.com>
# https://adventurelog.app
# License: GPL-3.0
# =============================================================================
APP_NAME="AdventureLog"
INSTALL_DIR="./adventurelog"
COMPOSE_FILE_URL="https://raw.githubusercontent.com/seanmorley15/AdventureLog/main/docker-compose.yml"
ENV_FILE_URL="https://raw.githubusercontent.com/seanmorley15/AdventureLog/main/.env.example"
# Global configuration variables
declare -g FRONTEND_ORIGIN=""
declare -g BACKEND_URL=""
declare -g ADMIN_PASSWORD=""
declare -g DB_PASSWORD=""
declare -g FRONTEND_PORT=""
declare -g BACKEND_PORT=""
# Color codes for beautiful output
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly PURPLE='\033[0;35m'
readonly CYAN='\033[0;36m'
readonly MAGENTA='\033[0;35m'
readonly BOLD='\033[1m'
readonly NC='\033[0m' # No Color
# =============================================================================
# Utility Functions
# =============================================================================
log_info() {
echo -e "${BLUE} $1${NC}"
}
log_success() {
echo -e "${GREEN}$1${NC}"
}
log_warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
log_error() {
echo -e "${RED}$1${NC}"
}
log_header() {
echo -e "${PURPLE}$1${NC}"
}
print_banner() {
cat << 'EOF'
╔═════════════════════════════════════════════════════════════════════════╗
║ ║
║ A D V E N T U R E L O G I N S T A L L E R ║
║ ║
║ The Ultimate Travel Companion ║
║ ║
╚═════════════════════════════════════════════════════════════════════════╝
EOF
}
print_header() {
clear
echo ""
print_banner
echo ""
log_header "🚀 Starting installation — $(date)"
echo ""
}
generate_secure_password() {
# Generate a 24-character password with mixed case, numbers, and safe symbols
local length=${1:-24}
# Test if /dev/urandom exists
if [[ ! -r "/dev/urandom" ]]; then
echo "ERROR: /dev/urandom not readable" >&2
return 1
fi
# Try the main approach
if command -v tr &>/dev/null; then
LC_ALL=C tr -dc 'A-Za-z0-9!#$%&*+-=?@^_' </dev/urandom 2>/dev/null | head -c "$length" 2>/dev/null
return 0
fi
# Fallback approach using od
if command -v od &>/dev/null; then
dd if=/dev/urandom bs=1 count=100 2>/dev/null | od -An -tx1 | tr -d ' \n' | cut -c1-"$length"
return 0
fi
# Last resort - use openssl if available
if command -v openssl &>/dev/null; then
openssl rand -base64 32 | tr -d "=+/" | cut -c1-"$length"
return 0
fi
echo "ERROR: No suitable random generation method found" >&2
return 1
}
check_os() {
if [[ "$OSTYPE" == "darwin"* ]]; then
echo "macos"
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
echo "linux"
else
echo "unknown"
fi
}
# =============================================================================
# Validation Functions
# =============================================================================
validate_url() {
local url="$1"
if [[ $url =~ ^https?://[a-zA-Z0-9.-]+(:[0-9]+)?(/.*)?$ ]]; then
return 0
else
return 1
fi
}
extract_port_from_url() {
local url="$1"
local default_port="$2"
# Extract port from URL using regex
if [[ $url =~ :([0-9]+) ]]; then
echo "${BASH_REMATCH[1]}"
else
# Use default port based on protocol
if [[ $url =~ ^https:// ]]; then
echo "443"
elif [[ $url =~ ^http:// ]]; then
echo "${default_port:-80}"
else
echo "$default_port"
fi
fi
}
check_port_availability() {
local port="$1"
local service_name="$2"
# Check if port is in use
if command -v netstat &>/dev/null; then
if netstat -ln 2>/dev/null | grep -q ":$port "; then
log_warning "Port $port is already in use"
echo ""
read -r -p "Do you want to continue anyway? The $service_name service may fail to start. [y/N]: " confirm
if [[ ! $confirm =~ ^[Yy]$ ]]; then
echo "Installation cancelled."
exit 0
fi
fi
elif command -v ss &>/dev/null; then
if ss -ln 2>/dev/null | grep -q ":$port "; then
log_warning "Port $port is already in use"
echo ""
read -r -p "Do you want to continue anyway? The $service_name service may fail to start. [y/N]: " confirm
if [[ ! $confirm =~ ^[Yy]$ ]]; then
echo "Installation cancelled."
exit 0
fi
fi
fi
}
check_dependencies() {
log_info "Checking system dependencies..."
local missing_deps=()
if ! command -v curl &>/dev/null; then
missing_deps+=("curl")
fi
if ! command -v docker &>/dev/null; then
missing_deps+=("docker")
fi
if ! command -v docker-compose &>/dev/null && ! docker compose version &>/dev/null; then
missing_deps+=("docker-compose")
fi
if [ ${#missing_deps[@]} -ne 0 ]; then
log_error "Missing dependencies: ${missing_deps[*]}"
echo ""
echo "Please install the missing dependencies:"
for dep in "${missing_deps[@]}"; do
case $dep in
"curl")
echo " • curl: apt-get install curl (Ubuntu/Debian) or brew install curl (macOS)"
;;
"docker")
echo " • Docker: https://docs.docker.com/get-docker/"
;;
"docker-compose")
echo " • Docker Compose: https://docs.docker.com/compose/install/"
;;
esac
done
exit 1
fi
log_success "All dependencies are installed"
}
check_docker_status() {
log_info "Checking Docker daemon status..."
if ! docker info &>/dev/null; then
log_error "Docker daemon is not running"
echo ""
echo "Please start Docker and try again:"
echo " • On macOS/Windows: Start Docker Desktop"
echo " • On Linux: sudo systemctl start docker"
exit 1
fi
log_success "Docker daemon is running"
}
# =============================================================================
# Installation Functions
# =============================================================================
create_directory() {
log_info "Setting up installation directory: $INSTALL_DIR"
if [ -d "$INSTALL_DIR" ]; then
log_warning "Directory already exists"
echo ""
read -r -p "Do you want to continue and overwrite existing files? [y/N]: " confirm
if [[ ! $confirm =~ ^[Yy]$ ]]; then
echo "Installation cancelled."
exit 0
fi
else
mkdir -p "$INSTALL_DIR"
log_success "Created directory: $INSTALL_DIR"
fi
cd "$INSTALL_DIR" || {
log_error "Failed to change to directory: $INSTALL_DIR"
exit 1
}
}
# Check for AdventureLog running as a docker container
check_running_container() {
if docker ps -a --filter "name=adventurelog" --format '{{.Names}}' | grep -q "adventurelog"; then
log_error "AdventureLog is already running as a Docker container (including stopped or restarting states)."
echo ""
echo "Running this installer further can break existing installs."
echo "Please stop and remove the existing AdventureLog container manually before proceeding."
echo " • To stop: docker compose down --remove-orphans"
echo "Installation aborted to prevent data loss."
exit 1
fi
}
download_files() {
log_info "Downloading configuration files..."
# Download with better error handling
if ! curl -fsSL --connect-timeout 10 --max-time 30 "$COMPOSE_FILE_URL" -o docker-compose.yml; then
log_error "Failed to download docker-compose.yml"
exit 1
fi
log_success "docker-compose.yml downloaded"
if ! curl -fsSL --connect-timeout 10 --max-time 30 "$ENV_FILE_URL" -o .env; then
log_error "Failed to download .env template"
exit 1
fi
log_success ".env template downloaded"
}
prompt_configuration() {
echo ""
log_header "🛠️ Configuration Setup"
echo ""
echo "Configure the URLs where AdventureLog will be accessible."
echo "Press Enter to use the default values shown in brackets."
echo ""
echo "⚠️ Note: The installer will automatically configure Docker ports based on your URLs"
echo ""
# Frontend URL
local default_frontend="http://localhost:8015"
while true; do
read -r -p "🌐 Frontend URL [$default_frontend]: " input_frontend
FRONTEND_ORIGIN=${input_frontend:-$default_frontend}
if validate_url "$FRONTEND_ORIGIN"; then
FRONTEND_PORT=$(extract_port_from_url "$FRONTEND_ORIGIN" "8015")
break
else
log_error "Invalid URL format. Please enter a valid URL (e.g., http://localhost:8015)"
fi
done
log_success "Frontend URL: $FRONTEND_ORIGIN (Port: $FRONTEND_PORT)"
# Backend URL
local default_backend="http://localhost:8016"
while true; do
read -r -p "🔧 Backend URL [$default_backend]: " input_backend
BACKEND_URL=${input_backend:-$default_backend}
if validate_url "$BACKEND_URL"; then
BACKEND_PORT=$(extract_port_from_url "$BACKEND_URL" "8016")
break
else
log_error "Invalid URL format. Please enter a valid URL (e.g., http://localhost:8016)"
fi
done
log_success "Backend URL: $BACKEND_URL (Port: $BACKEND_PORT)"
# Check port availability
check_port_availability "$FRONTEND_PORT" "frontend"
check_port_availability "$BACKEND_PORT" "backend"
echo ""
}
configure_environment_fallback() {
log_info "Using simple configuration approach..."
# Generate simple passwords using a basic method
DB_PASSWORD="$(date +%s | sha256sum | base64 | head -c 32)"
ADMIN_PASSWORD="$(date +%s | sha256sum | base64 | head -c 24)"
log_info "Generated passwords using fallback method"
# Create backup
cp .env .env.backup
# Use simple string replacement with perl if available
if command -v perl &>/dev/null; then
log_info "Using perl for configuration..."
# Fix: Update BOTH password variables for database consistency
perl -pi -e "s/^POSTGRES_PASSWORD=.*/POSTGRES_PASSWORD=$DB_PASSWORD/" .env
perl -pi -e "s/^DATABASE_PASSWORD=.*/DATABASE_PASSWORD=$DB_PASSWORD/" .env
perl -pi -e "s/^DJANGO_ADMIN_PASSWORD=.*/DJANGO_ADMIN_PASSWORD=$ADMIN_PASSWORD/" .env
perl -pi -e "s|^ORIGIN=.*|ORIGIN=$FRONTEND_ORIGIN|" .env
perl -pi -e "s|^PUBLIC_URL=.*|PUBLIC_URL=$BACKEND_URL|" .env
perl -pi -e "s|^CSRF_TRUSTED_ORIGINS=.*|CSRF_TRUSTED_ORIGINS=$FRONTEND_ORIGIN,$BACKEND_URL|" .env
perl -pi -e "s|^FRONTEND_URL=.*|FRONTEND_URL=$FRONTEND_ORIGIN|" .env
# Add port configuration
perl -pi -e "s/^FRONTEND_PORT=.*/FRONTEND_PORT=$FRONTEND_PORT/" .env
perl -pi -e "s/^BACKEND_PORT=.*/BACKEND_PORT=$BACKEND_PORT/" .env
# Add port variables if they don't exist
if ! grep -q "^FRONTEND_PORT=" .env; then
echo "FRONTEND_PORT=$FRONTEND_PORT" >> .env
fi
if ! grep -q "^BACKEND_PORT=" .env; then
echo "BACKEND_PORT=$BACKEND_PORT" >> .env
fi
if grep -q "POSTGRES_PASSWORD=$DB_PASSWORD" .env; then
log_success "Configuration completed successfully"
return 0
fi
fi
# Manual approach - create .env from scratch with key variables
log_info "Creating minimal .env configuration..."
cat > .env << EOF
# Database Configuration
POSTGRES_DB=adventurelog
POSTGRES_USER=adventurelog
POSTGRES_PASSWORD=$DB_PASSWORD
DATABASE_PASSWORD=$DB_PASSWORD
# Django Configuration
DJANGO_ADMIN_USERNAME=admin
DJANGO_ADMIN_PASSWORD=$ADMIN_PASSWORD
SECRET_KEY=$(openssl rand -base64 32 2>/dev/null || echo "change-this-secret-key-$(date +%s)")
# URL Configuration
ORIGIN=$FRONTEND_ORIGIN
PUBLIC_URL=$BACKEND_URL
FRONTEND_URL=$FRONTEND_ORIGIN
CSRF_TRUSTED_ORIGINS=$FRONTEND_ORIGIN,$BACKEND_URL
# Port Configuration
FRONTEND_PORT=$FRONTEND_PORT
BACKEND_PORT=$BACKEND_PORT
# Additional Settings
DEBUG=False
EOF
log_success "Created minimal .env configuration"
return 0
}
configure_environment() {
log_info "Generating secure configuration..."
# Debug: Test password generation first
log_info "Testing password generation..."
if ! command -v tr &>/dev/null; then
log_error "tr command not found - required for password generation"
exit 1
fi
# Generate secure passwords with error checking
log_info "Generating database password..."
DB_PASSWORD=$(generate_secure_password 32)
if [[ -z "$DB_PASSWORD" ]]; then
log_error "Failed to generate database password"
exit 1
fi
log_success "Database password generated (${#DB_PASSWORD} characters)"
log_info "Generating admin password..."
ADMIN_PASSWORD=$(generate_secure_password 24)
if [[ -z "$ADMIN_PASSWORD" ]]; then
log_error "Failed to generate admin password"
exit 1
fi
log_success "Admin password generated (${#ADMIN_PASSWORD} characters)"
# Debug: Check if .env file exists and is readable
log_info "Checking .env file..."
if [[ ! -f ".env" ]]; then
log_error ".env file not found"
exit 1
fi
if [[ ! -r ".env" ]]; then
log_error ".env file is not readable"
exit 1
fi
log_info "File check passed - .env exists and is readable ($(wc -l < .env) lines)"
# Try fallback method first (simpler and more reliable)
log_info "Attempting configuration..."
if configure_environment_fallback; then
return 0
fi
log_warning "Fallback method failed, trying advanced processing..."
# Fallback to bash processing
# Create backup of original .env
cp .env .env.backup
# Create a new .env file by processing the original line by line
local temp_file=".env.temp"
local processed_lines=0
local updated_lines=0
while IFS= read -r line || [[ -n "$line" ]]; do
((processed_lines++))
case "$line" in
POSTGRES_PASSWORD=*)
echo "POSTGRES_PASSWORD=$DB_PASSWORD"
((updated_lines++))
;;
DATABASE_PASSWORD=*)
echo "DATABASE_PASSWORD=$DB_PASSWORD"
((updated_lines++))
;;
DJANGO_ADMIN_PASSWORD=*)
echo "DJANGO_ADMIN_PASSWORD=$ADMIN_PASSWORD"
((updated_lines++))
;;
ORIGIN=*)
echo "ORIGIN=$FRONTEND_ORIGIN"
((updated_lines++))
;;
PUBLIC_URL=*)
echo "PUBLIC_URL=$BACKEND_URL"
((updated_lines++))
;;
CSRF_TRUSTED_ORIGINS=*)
echo "CSRF_TRUSTED_ORIGINS=$FRONTEND_ORIGIN,$BACKEND_URL"
((updated_lines++))
;;
FRONTEND_URL=*)
echo "FRONTEND_URL=$FRONTEND_ORIGIN"
((updated_lines++))
;;
FRONTEND_PORT=*)
echo "FRONTEND_PORT=$FRONTEND_PORT"
((updated_lines++))
;;
BACKEND_PORT=*)
echo "BACKEND_PORT=$BACKEND_PORT"
((updated_lines++))
;;
*)
echo "$line"
;;
esac
done < .env > "$temp_file"
# Add port variables if they weren't found in the original file
if ! grep -q "^FRONTEND_PORT=" "$temp_file"; then
echo "FRONTEND_PORT=$FRONTEND_PORT" >> "$temp_file"
((updated_lines++))
fi
if ! grep -q "^BACKEND_PORT=" "$temp_file"; then
echo "BACKEND_PORT=$BACKEND_PORT" >> "$temp_file"
((updated_lines++))
fi
log_info "Processed $processed_lines lines, updated $updated_lines configuration values"
# Check if temp file was created successfully
if [[ ! -f "$temp_file" ]]; then
log_error "Failed to create temporary configuration file"
exit 1
fi
# Replace the original .env with the configured one
if mv "$temp_file" .env; then
log_success "Environment configured with secure passwords and port settings"
else
log_error "Failed to replace .env file"
log_info "Restoring backup and exiting"
mv .env.backup .env
rm -f "$temp_file"
exit 1
fi
# Verify critical configuration was applied
if grep -q "POSTGRES_PASSWORD=$DB_PASSWORD" .env && (grep -q "DATABASE_PASSWORD=$DB_PASSWORD" .env || grep -q "POSTGRES_PASSWORD=$DB_PASSWORD" .env); then
log_success "Configuration verification passed - database password variables set"
else
log_error "Configuration verification failed - database passwords not properly configured"
log_info "Showing database-related lines in .env for debugging:"
grep -E "(POSTGRES_PASSWORD|DATABASE_PASSWORD)" .env | while read -r line; do
echo " $line"
done
mv .env.backup .env
exit 1
fi
# Verify port configuration
if grep -q "FRONTEND_PORT=$FRONTEND_PORT" .env && grep -q "BACKEND_PORT=$BACKEND_PORT" .env; then
log_success "Port configuration verified - frontend: $FRONTEND_PORT, backend: $BACKEND_PORT"
else
log_warning "Port configuration may not be complete - check .env file manually"
fi
}
update_docker_compose_ports() {
log_info "Updating Docker Compose port configuration..."
# Create backup of docker-compose.yml
cp docker-compose.yml docker-compose.yml.backup
# Update ports in docker-compose.yml using sed
if command -v sed &>/dev/null; then
# For frontend service port mapping
sed -i.tmp "s/\"[0-9]*:3000\"/\"$FRONTEND_PORT:3000\"/g" docker-compose.yml
# For backend service port mapping
sed -i.tmp "s/\"[0-9]*:8000\"/\"$BACKEND_PORT:8000\"/g" docker-compose.yml
# Clean up temporary files created by sed -i
rm -f docker-compose.yml.tmp
log_success "Docker Compose ports updated - Frontend: $FRONTEND_PORT, Backend: $BACKEND_PORT"
else
log_warning "sed command not available - Docker Compose ports may need manual configuration"
fi
}
start_services() {
log_info "Starting AdventureLog services..."
echo ""
# Use docker compose or docker-compose based on availability
local compose_cmd
if docker compose version &>/dev/null; then
compose_cmd="docker compose"
else
compose_cmd="docker-compose"
fi
# Pull images first for better progress indication
log_info "Pulling required Docker images..."
$compose_cmd pull
# Start services
log_info "Starting containers..."
if $compose_cmd up -d --remove-orphans; then
log_success "All services started successfully"
else
log_error "Failed to start services"
echo ""
log_info "Checking service status..."
$compose_cmd ps
exit 1
fi
}
wait_for_services() {
log_info "Waiting for services to be ready... (up to 90 seconds, first startup may take longer)"
local max_attempts=45 # 45 attempts * 2 seconds = 90 seconds total
local attempt=1
local frontend_ready=false
local backend_ready=false
while [ $attempt -le $max_attempts ]; do
# Check frontend
if [ "$frontend_ready" = false ]; then
if curl -s -o /dev/null -w "%{http_code}" "$FRONTEND_ORIGIN" | grep -q "200\|404\|302"; then
log_success "Frontend is responding"
frontend_ready=true
fi
fi
# Check backend
if [ "$backend_ready" = false ]; then
if curl -s -o /dev/null -w "%{http_code}" "$BACKEND_URL" | grep -q "200\|404\|302"; then
log_success "Backend is responding"
backend_ready=true
fi
fi
# If both are ready, break the loop
if [ "$frontend_ready" = true ] && [ "$backend_ready" = true ]; then
break
fi
# Check if we've reached max attempts
if [ $attempt -eq $max_attempts ]; then
if [ "$frontend_ready" = false ]; then
log_warning "Frontend may still be starting up (this is normal for first run)"
fi
if [ "$backend_ready" = false ]; then
log_warning "Backend may still be starting up (this is normal for first run)"
fi
break
fi
# Wait and increment counter
printf "."
sleep 2
((attempt++))
done
echo ""
}
# =============================================================================
# Output Functions
# =============================================================================
print_success_message() {
local ip_address
ip_address=$(hostname -I 2>/dev/null | cut -d' ' -f1 || echo "localhost")
echo ""
cat << 'EOF'
╔════════════════════════════════════════════════════════════════════════════╗
║ ║
║ A D V E N T U R E L O G I S R E A D Y F O R L A U N C H! ║
║ ║
╚════════════════════════════════════════════════════════════════════════════╝
EOF
echo ""
log_success "🎉 Installation completed successfully!"
echo ""
echo -e "${BOLD}🌐 Access Points:${NC}"
echo -e " 🖥️ Frontend: ${CYAN}$FRONTEND_ORIGIN${NC}"
echo -e " ⚙️ Backend: ${CYAN}$BACKEND_URL${NC}"
echo ""
echo -e "${BOLD}🔐 Admin Credentials:${NC}"
echo -e " 👤 Username: ${GREEN}admin${NC}"
echo -e " 🔑 Password: ${GREEN}$ADMIN_PASSWORD${NC}"
echo ""
echo -e "${BOLD}📁 Important Locations:${NC}"
echo -e " 🛠️ Config: ${YELLOW}$(pwd)/.env${NC}"
echo -e " 📦 Media Vol: ${YELLOW}adventurelog_media${NC}"
echo -e " 📜 Logs: ${YELLOW}docker compose logs -f${NC}"
echo ""
echo -e "${BOLD}🧰 Management Commands:${NC}"
echo -e " ⛔ Stop: ${CYAN}docker compose down${NC}"
echo -e " ▶️ Start: ${CYAN}docker compose up -d${NC}"
echo -e " 🔄 Update: ${CYAN}docker compose pull && docker compose up -d${NC}"
echo -e " 📖 Logs: ${CYAN}docker compose logs -f${NC}"
echo ""
log_info "💾 Save your admin password in a secure location!"
echo ""
# Show port information
echo -e "${BOLD}🔧 Port Configuration:${NC}"
echo -e " 🖥️ Frontend Port: ${YELLOW}$FRONTEND_PORT${NC}"
echo -e " ⚙️ Backend Port: ${YELLOW}$BACKEND_PORT${NC}"
echo ""
# Optional donation link
echo -e "${BOLD}❤️ Enjoying AdventureLog?${NC}"
echo -e " Support future development: ${MAGENTA}https://seanmorley.com/sponsor${NC}"
echo ""
echo -e "${BOLD}🌍 Adventure awaits — your journey starts now with AdventureLog!${NC}"
}
print_failure_message() {
echo ""
log_error "Installation failed!"
echo ""
echo "Troubleshooting steps:"
echo "1. Check Docker is running: docker info"
echo "2. Check available ports: netstat -an | grep :$FRONTEND_PORT"
echo "3. Check available ports: netstat -an | grep :$BACKEND_PORT"
echo "4. View logs: docker compose logs"
echo "5. Check .env configuration: cat .env"
echo "6. Check docker-compose.yml ports: grep -A5 ports docker-compose.yml"
echo ""
echo "For support, visit: https://github.com/seanmorley15/AdventureLog"
}
cleanup_on_failure() {
log_info "Cleaning up after failure..."
if [ -f ".env.backup" ]; then
mv .env.backup .env
log_info "Restored original .env file"
fi
if [ -f "docker-compose.yml.backup" ]; then
mv docker-compose.yml.backup docker-compose.yml
log_info "Restored original docker-compose.yml file"
fi
if command -v docker &>/dev/null; then
docker compose down --remove-orphans 2>/dev/null || true
fi
}
# =============================================================================
# Main Installation Flow
# =============================================================================
main() {
# Set up error handling
trap 'cleanup_on_failure; print_failure_message; exit 1' ERR
# Installation steps
print_header
check_dependencies
check_docker_status
check_running_container
create_directory
download_files
prompt_configuration
configure_environment
update_docker_compose_ports
start_services
wait_for_services
print_success_message
# Clean up backup files on success
rm -f .env.backup
rm -f docker-compose.yml.backup
}
# Script entry point
# Allow interactive install even when piped
if [[ -t 1 ]]; then
# stdout is a terminal → likely interactive
exec < /dev/tty # reconnect stdin to terminal for user input
main "$@"
else
echo "Error: This script needs an interactive terminal." >&2
exit 1
fi