1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-07-19 21:09:37 +02:00

feat: add Immich integration module with API endpoints and admin interface

This commit is contained in:
Sean Morley 2024-12-31 10:38:15 -05:00
parent 79db20a903
commit dc89743569
12 changed files with 148 additions and 2 deletions

View file

@ -8,8 +8,6 @@ from allauth.account.decorators import secure_admin_login
admin.autodiscover() admin.autodiscover()
admin.site.login = secure_admin_login(admin.site.login) admin.site.login = secure_admin_login(admin.site.login)
class AdventureAdmin(admin.ModelAdmin): class AdventureAdmin(admin.ModelAdmin):
list_display = ('name', 'get_category', 'get_visit_count', 'user_id', 'is_public') list_display = ('name', 'get_category', 'get_visit_count', 'user_id', 'is_public')
list_filter = ( 'user_id', 'is_public') list_filter = ( 'user_id', 'is_public')

View file

View file

@ -0,0 +1,9 @@
from django.contrib import admin
from allauth.account.decorators import secure_admin_login
from .models import ImmichIntegration
admin.autodiscover()
admin.site.login = secure_admin_login(admin.site.login)
admin.site.register(ImmichIntegration)

View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class IntegrationsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'integrations'

View file

@ -0,0 +1,26 @@
# Generated by Django 5.0.8 on 2024-12-31 15:02
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='ImmichIntegration',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('server_url', models.CharField(max_length=255)),
('api_key', models.CharField(max_length=255)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
]

View file

@ -0,0 +1,12 @@
from django.db import models
from django.contrib.auth import get_user_model
User = get_user_model()
class ImmichIntegration(models.Model):
server_url = models.CharField(max_length=255)
api_key = models.CharField(max_length=255)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.user.username + ' - ' + self.server_url

View file

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View file

@ -0,0 +1,12 @@
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from integrations.views import ImmichIntegrationView
# Create the router and register the ViewSet
router = DefaultRouter()
router.register(r'immich', ImmichIntegrationView, basename='immich')
# Include the router URLs
urlpatterns = [
path("", include(router.urls)), # Includes /immich/ routes
]

View file

@ -0,0 +1,77 @@
from rest_framework.response import Response
from rest_framework import viewsets, status
from .models import ImmichIntegration
from rest_framework.decorators import action
import requests
class ImmichIntegrationView(viewsets.ViewSet):
def check_integration(self, request):
"""
Checks if the user has an active Immich integration.
Returns:
- None if the integration exists.
- A Response with an error message if the integration is missing.
"""
user_integrations = ImmichIntegration.objects.filter(user=request.user)
if not user_integrations.exists():
return Response(
{
'message': 'You need to have an active Immich integration to use this feature.',
'error': True,
'code': 'immich.integration_missing'
},
status=status.HTTP_403_FORBIDDEN
)
return ImmichIntegration.objects.first()
@action(detail=False, methods=['get'], url_path='search')
def search(self, request):
"""
Handles the logic for searching Immich images.
"""
# Check for integration before proceeding
integration = self.check_integration(request)
if isinstance(integration, Response):
return integration
query = request.query_params.get('query', '')
if not query:
return Response(
{
'message': 'Query is required.',
'error': True,
'code': 'immich.query_required'
},
status=status.HTTP_400_BAD_REQUEST
)
immich_fetch = requests.post(f'{integration.server_url}/search/smart', headers={
'x-api-key': integration.api_key
},
json = {
'query': query
}
)
res = immich_fetch.json()
if 'assets' in res and 'items' in res['assets']:
return Response(res['assets']['items'], status=status.HTTP_200_OK)
else:
return Response(
{
'message': 'No items found.',
'error': True,
'code': 'immich.no_items_found'
},
status=status.HTTP_404_NOT_FOUND
)
def get(self, request):
"""
RESTful GET method for searching Immich images.
"""
return self.search(request)

View file

@ -56,6 +56,7 @@ INSTALLED_APPS = (
'adventures', 'adventures',
'worldtravel', 'worldtravel',
'users', 'users',
'integrations',
'django.contrib.gis', 'django.contrib.gis',
) )

View file

@ -39,6 +39,8 @@ urlpatterns = [
# path('auth/account-confirm-email/', VerifyEmailView.as_view(), name='account_email_verification_sent'), # path('auth/account-confirm-email/', VerifyEmailView.as_view(), name='account_email_verification_sent'),
path("accounts/", include("allauth.urls")), path("accounts/", include("allauth.urls")),
path("api/integrations/", include("integrations.urls")),
# Include the API endpoints: # Include the API endpoints:
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)