Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
e847091
feat(docs): adding haproxy configuration example
kirby0025 Jun 2, 2025
4bc7f3b
Implement code changes to enhance functionality and improve performance
seanmorley15 Jun 20, 2025
0723ad7
Update nl.json
Ycer0n Jun 23, 2025
dc67ad1
Merge pull request #694 from Ycer0n/patch-1
seanmorley15 Jun 23, 2025
12a5221
feat(security): add Trivy security scans for Docker images and source…
seanmorley15 Jun 23, 2025
d865454
feat(security): restructure Trivy scans for improved clarity and orga…
seanmorley15 Jun 23, 2025
5026243
fix(dependencies): update Django version to 5.2.2
seanmorley15 Jun 23, 2025
d797095
style(workflows): standardize quotes and fix typo in frontend-test.yml
seanmorley15 Jun 23, 2025
b8d30d2
feat(workflows): add job names for clarity in backend and frontend te…
seanmorley15 Jun 23, 2025
e335d7d
refactor(workflows): remove path filters from pull_request and push t…
seanmorley15 Jun 23, 2025
42982d5
Merge branch 'development' into feat/docs_haproy
seanmorley15 Jun 23, 2025
00a6e67
feat(workflows): add paths to push and pull_request triggers for back…
seanmorley15 Jun 23, 2025
bad7021
Merge branch 'development' into feat/docs_haproy
seanmorley15 Jun 23, 2025
b6e5e4a
refactor(workflows): simplify trigger paths for backend and frontend …
seanmorley15 Jun 23, 2025
ed11d29
fix(package): add missing pnpm overrides for esbuild in package.json
seanmorley15 Jun 23, 2025
b4407dc
fix(workflows): add missing severity parameter for Trivy filesystem scan
seanmorley15 Jun 23, 2025
6665422
fix(workflows): add missing severity parameter for Docker image scans…
seanmorley15 Jun 23, 2025
295ecd1
fix(workflows): remove MEDIUM severity from Trivy scans in security w…
seanmorley15 Jun 23, 2025
1609c9e
Merge branch 'development' into feat/docs_haproy
seanmorley15 Jun 23, 2025
5308ec2
added-fix-image-deletion (#681)
taninme Jun 23, 2025
ce3fa9d
fix(docs): enhance HAProxy description in installation guide
seanmorley15 Jun 24, 2025
7b3d7aa
Merge branch 'development' into feat/docs_haproy
seanmorley15 Jun 24, 2025
493a139
Rename Adventures to Locations (#696)
seanmorley15 Jun 25, 2025
c461f7b
Import and Export Functionality (#698)
seanmorley15 Jun 26, 2025
fc358b9
enhance haproxy example
kirby0025 Jul 7, 2025
83e6510
Merge branch 'development' into feat/docs_haproy
kirby0025 Jul 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 6 additions & 12 deletions .github/workflows/backend-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,33 @@ permissions:

on:
pull_request:
paths:
- 'backend/server/**'
- '.github/workflows/backend-test.yml'
push:
paths:
- 'backend/server/**'
- '.github/workflows/backend-test.yml'

jobs:
build:
name: Build and Test Backend
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: set up python 3.12
uses: actions/setup-python@v5
with:
python-version: '3.12'
python-version: "3.12"

- name: install dependencies
run: |
sudo apt update -q
sudo apt install -y -q \
python3-gdal
sudo apt install -y -q python3-gdal

- name: start database
run: |
docker compose -f .github/.docker-compose-database.yml up -d

- name: install python libreries
- name: install python libraries
working-directory: backend/server
run: |
pip install -r requirements.txt
run: pip install -r requirements.txt

- name: run server
working-directory: backend/server
Expand Down
8 changes: 2 additions & 6 deletions .github/workflows/frontend-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,13 @@ permissions:

on:
pull_request:
paths:
- "frontend/**"
- ".github/workflows/frontend-test.yml"
push:
paths:
- "frontend/**"
- ".github/workflows/frontend-test.yml"

jobs:
build:
name: Build and Test Frontend
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

Expand Down
75 changes: 75 additions & 0 deletions .github/workflows/trivy_security_scans.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: Trivy Security Scans

on:
push:
branches:
- main
- development
pull_request:
branches:
- main
- development
schedule:
- cron: "0 8 * * 1" # Weekly scan on Mondays at 8 AM UTC

jobs:
filesystem-scan:
name: Trivy Filesystem Scan (Source Code)
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Scan source code (Filesystem) with Trivy
uses: aquasecurity/trivy-action@master
with:
scan-type: fs
scan-ref: .
format: table
exit-code: 1
ignore-unfixed: true
severity: CRITICAL,HIGH

image-scan:
name: Trivy Docker Image Scan (Backend & Frontend)
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

# Optional login step (remove if you're not pushing images to GHCR)
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build backend Docker image
run: docker build -t adventurelog-backend ./backend

- name: Build frontend Docker image
run: docker build -t adventurelog-frontend ./frontend

- name: Scan backend Docker image with Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: adventurelog-backend
format: table
exit-code: 1
ignore-unfixed: true
severity: CRITICAL,HIGH

- name: Scan frontend Docker image with Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: adventurelog-frontend
format: table
exit-code: 1
ignore-unfixed: true
severity: CRITICAL,HIGH
4 changes: 3 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ We’re excited to have you contribute to AdventureLog! To ensure that this comm

1. **Open an Issue First**: Discuss any changes or features you plan to implement by opening an issue. This helps to clarify your idea and ensures there’s a shared understanding.
2. **Document Changes**: If your changes impact the user interface, add new environment variables, or introduce new container configurations, make sure to update the documentation accordingly. The documentation is located in the `documentation` folder.
3. **Pull Request**: Submit a pull request with your changes. Make sure to reference the issue you opened in the description.
3. **Pull Request**: Submit a pull request with your changes directed towards the `development` branch. Make sure to reference the issue you opened in the description. After your pull request is submitted, it will be reviewed by the maintainers.
4. **Review Process**: The maintainers will review your pull request. They may suggest changes or improvements. Please be open to feedback and ready to make adjustments as needed.
5. **Merge**: Once your pull request is approved, it will be merged into the `development` branch. This branch is where all new features and changes are integrated before being released to the main branch.

## Code of Conduct

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

## ⭐ About the Project

Starting from a simple idea of tracking travel locations (called adventures), AdventureLog has grown into a full-fledged travel companion. With AdventureLog, you can log your adventures, keep track of where you've been on the world map, plan your next trip collaboratively, and share your experiences with friends and family.
Starting from a simple idea of tracking travel locations, AdventureLog has grown into a full-fledged travel companion. With AdventureLog, you can log your adventures, keep track of where you've been on the world map, plan your next trip collaboratively, and share your experiences with friends and family.

AdventureLog was created to solve a problem: the lack of a modern, open-source, user-friendly travel companion. Many existing travel apps are either too complex, too expensive, or too closed-off to be useful for the average traveler. AdventureLog aims to be the opposite: simple, beautiful, and open to everyone.

Expand Down
32 changes: 32 additions & 0 deletions adventurelog_overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# About AdventureLog

Starting from a /locations, AdventureLog has grown into a full-fledged travel companion. With AdventureLog, you can log your adventures, keep track of where you've been on the world map, plan your next trip collaboratively, and share your experiences with friends and family. **AdventureLog is the ultimate travel companion for the modern-day explorer**.

## Features

- **Track Your Adventures** 🌍: Log your adventures and keep track of where you've been on the world map.
- Adventures can store a variety of information, including the location, date, and description.
- Adventures can be sorted into custom categories for easy organization.
- Adventures can be marked as private or public, allowing you to share your adventures with friends and family.
- Keep track of the countries and regions you've visited with the world travel book.
- **Plan Your Next Trip** 📃: Take the guesswork out of planning your next adventure with an easy-to-use itinerary planner.
- Itineraries can be created for any number of days and can include multiple destinations.
- Itineraries include many planning features like flight information, notes, checklists, and links to external resources.
- Itineraries can be shared with friends and family for collaborative planning.
- **Share Your Experiences** 📸: Share your adventures with friends and family and collaborate on trips together.
- Adventures and itineraries can be shared via a public link or directly with other AdventureLog users.
- Collaborators can view and edit shared itineraries (collections), making planning a breeze.

## Why AdventureLog?

AdventureLog was created to solve a problem: the lack of a modern, open-source, user-friendly travel companion. Many existing travel apps are either too complex, too expensive, or too closed-off to be useful for the average traveler. AdventureLog aims to be the opposite: simple, beautiful, and open to everyone.

### Open Source (GPL-3.0)

AdventureLog is open-source software, licensed under the GPL-3.0 license. This means that you are free to use, modify, and distribute AdventureLog as you see fit. The source code is available on GitHub, and contributions are welcome from anyone who wants to help improve the project.

## About the Maintainer

Hi, I'm [Sean Morley](https://seanmorley.com), the creator of AdventureLog. I'm an Electrical Engineering student at the University of Connecticut, and I'm passionate about open-source software and building modern tools that help people solve real-world problems. I created AdventureLog to solve a problem: the lack of a modern, open-source, user-friendly travel companion. Many existing travel apps are either too complex, too expensive, or too closed-off to be useful for the average traveler. AdventureLog aims to be the opposite: simple, beautiful, and open to everyone.

I hope you enjoy using AdventureLog as much as I enjoy creating it! If you have any questions, feedback, or suggestions, feel free to reach out to me via the email address listed on my website. I'm always happy to hear from users and help in any way I can. Thank you for using AdventureLog, and happy travels! 🌍
30 changes: 15 additions & 15 deletions backend/server/adventures/admin.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os
from django.contrib import admin
from django.utils.html import mark_safe
from .models import Adventure, Checklist, ChecklistItem, Collection, Transportation, Note, AdventureImage, Visit, Category, Attachment, Lodging
from .models import Location, Checklist, ChecklistItem, Collection, Transportation, Note, LocationImage, Visit, Category, Attachment, Lodging
from worldtravel.models import Country, Region, VisitedRegion, City, VisitedCity
from allauth.account.decorators import secure_admin_login

Expand All @@ -11,19 +11,19 @@
@admin.action(description="Trigger geocoding")
def trigger_geocoding(modeladmin, request, queryset):
count = 0
for adventure in queryset:
for location in queryset:
try:
adventure.save() # Triggers geocoding logic in your model
location.save() # Triggers geocoding logic in your model
count += 1
except Exception as e:
modeladmin.message_user(request, f"Error geocoding {adventure}: {e}", level='error')
modeladmin.message_user(request, f"Geocoding triggered for {count} adventures.", level='success')
modeladmin.message_user(request, f"Error geocoding {location}: {e}", level='error')
modeladmin.message_user(request, f"Geocoding triggered for {count} locations.", level='success')



class AdventureAdmin(admin.ModelAdmin):
list_display = ('name', 'get_category', 'get_visit_count', 'user_id', 'is_public')
list_filter = ( 'user_id', 'is_public')
class LocationAdmin(admin.ModelAdmin):
list_display = ('name', 'get_category', 'get_visit_count', 'user', 'is_public')
list_filter = ( 'user', 'is_public')
search_fields = ('name',)
readonly_fields = ('city', 'region', 'country')
actions = [trigger_geocoding]
Expand Down Expand Up @@ -96,8 +96,8 @@ def image_display(self, obj):
else:
return

class AdventureImageAdmin(admin.ModelAdmin):
list_display = ('user_id', 'image_display')
class LocationImageAdmin(admin.ModelAdmin):
list_display = ('user', 'image_display')

def image_display(self, obj):
if obj.image:
Expand All @@ -109,7 +109,7 @@ def image_display(self, obj):


class VisitAdmin(admin.ModelAdmin):
list_display = ('adventure', 'start_date', 'end_date', 'notes')
list_display = ('location', 'start_date', 'end_date', 'notes')
list_filter = ('start_date', 'end_date')
search_fields = ('notes',)

Expand All @@ -125,19 +125,19 @@ def image_display(self, obj):
image_display.short_description = 'Image Preview'

class CategoryAdmin(admin.ModelAdmin):
list_display = ('name', 'user_id', 'display_name', 'icon')
list_display = ('name', 'user', 'display_name', 'icon')
search_fields = ('name', 'display_name')

class CollectionAdmin(admin.ModelAdmin):


list_display = ('name', 'user_id', 'is_public')
list_display = ('name', 'user', 'is_public')

admin.site.register(CustomUser, CustomUserAdmin)



admin.site.register(Adventure, AdventureAdmin)
admin.site.register(Location, LocationAdmin)
admin.site.register(Collection, CollectionAdmin)
admin.site.register(Visit, VisitAdmin)
admin.site.register(Country, CountryAdmin)
Expand All @@ -147,7 +147,7 @@ class CollectionAdmin(admin.ModelAdmin):
admin.site.register(Note)
admin.site.register(Checklist)
admin.site.register(ChecklistItem)
admin.site.register(AdventureImage, AdventureImageAdmin)
admin.site.register(LocationImage, LocationImageAdmin)
admin.site.register(Category, CategoryAdmin)
admin.site.register(City, CityAdmin)
admin.site.register(VisitedCity)
Expand Down
4 changes: 2 additions & 2 deletions backend/server/adventures/geocoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def extractIsoCode(user, data):
return {"error": "No region found"}

region = Region.objects.filter(id=iso_code).first()
visited_region = VisitedRegion.objects.filter(region=region, user_id=user).first()
visited_region = VisitedRegion.objects.filter(region=region, user=user).first()

region_visited = False
city_visited = False
Expand All @@ -177,7 +177,7 @@ def extractIsoCode(user, data):
if town_city_or_county:
display_name = f"{town_city_or_county}, {region.name}, {country_code}"
city = City.objects.filter(name__contains=town_city_or_county, region=region).first()
visited_city = VisitedCity.objects.filter(city=city, user_id=user).first()
visited_city = VisitedCity.objects.filter(city=city, user=user).first()

if visited_region:
region_visited = True
Expand Down
94 changes: 94 additions & 0 deletions backend/server/adventures/management/commands/image_cleanup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import os
from django.core.management.base import BaseCommand
from django.conf import settings
from adventures.models import LocationImage, Attachment
from users.models import CustomUser


class Command(BaseCommand):
help = 'Find and prompt for deletion of unused image files and attachments in filesystem'

def add_arguments(self, parser):
parser.add_argument(
'--dry-run',
action='store_true',
help='Show files that would be deleted without actually deleting them',
)

def handle(self, **options):
dry_run = options['dry_run']

# Get all image and attachment file paths from database
used_files = set()

# Get LocationImage file paths
for img in LocationImage.objects.all():
if img.image and img.image.name:
used_files.add(os.path.join(settings.MEDIA_ROOT, img.image.name))

# Get Attachment file paths
for attachment in Attachment.objects.all():
if attachment.file and attachment.file.name:
used_files.add(os.path.join(settings.MEDIA_ROOT, attachment.file.name))

# Get user profile picture file paths
for user in CustomUser.objects.all():
if user.profile_pic and user.profile_pic.name:
used_files.add(os.path.join(settings.MEDIA_ROOT, user.profile_pic.name))

# Find all files in media/images and media/attachments directories
media_root = settings.MEDIA_ROOT
all_files = []

# Scan images directory
images_dir = os.path.join(media_root, 'images')
# Scan attachments directory
attachments_dir = os.path.join(media_root, 'attachments')
if os.path.exists(attachments_dir):
for root, _, files in os.walk(attachments_dir):
for file in files:
all_files.append(os.path.join(root, file))

# Scan profile-pics directory
profile_pics_dir = os.path.join(media_root, 'profile-pics')
if os.path.exists(profile_pics_dir):
for root, _, files in os.walk(profile_pics_dir):
for file in files:
all_files.append(os.path.join(root, file))
attachments_dir = os.path.join(media_root, 'attachments')
if os.path.exists(attachments_dir):
for root, _, files in os.walk(attachments_dir):
for file in files:
all_files.append(os.path.join(root, file))

# Find unused files
unused_files = [f for f in all_files if f not in used_files]

if not unused_files:
self.stdout.write(self.style.SUCCESS('No unused files found.'))
return

self.stdout.write(f'Found {len(unused_files)} unused files:')
for file_path in unused_files:
self.stdout.write(f' {file_path}')

if dry_run:
self.stdout.write(self.style.WARNING('Dry run mode - no files were deleted.'))
return

# Prompt for deletion
confirm = input('\nDo you want to delete these files? (yes/no): ')
if confirm.lower() in ['yes', 'y']:
deleted_count = 0
for file_path in unused_files:
try:
os.remove(file_path)
self.stdout.write(f'Deleted: {file_path}')
deleted_count += 1
except OSError as e:
self.stdout.write(self.style.ERROR(f'Error deleting {file_path}: {e}'))

self.stdout.write(self.style.SUCCESS(f'Successfully deleted {deleted_count} files.'))
else:
self.stdout.write('Operation cancelled.')

Loading