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:
parent
79db20a903
commit
dc89743569
12 changed files with 148 additions and 2 deletions
|
@ -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')
|
||||||
|
|
0
backend/server/integrations/__init__.py
Normal file
0
backend/server/integrations/__init__.py
Normal file
9
backend/server/integrations/admin.py
Normal file
9
backend/server/integrations/admin.py
Normal 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)
|
6
backend/server/integrations/apps.py
Normal file
6
backend/server/integrations/apps.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class IntegrationsConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'integrations'
|
26
backend/server/integrations/migrations/0001_initial.py
Normal file
26
backend/server/integrations/migrations/0001_initial.py
Normal 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)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
0
backend/server/integrations/migrations/__init__.py
Normal file
0
backend/server/integrations/migrations/__init__.py
Normal file
12
backend/server/integrations/models.py
Normal file
12
backend/server/integrations/models.py
Normal 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
|
3
backend/server/integrations/tests.py
Normal file
3
backend/server/integrations/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
12
backend/server/integrations/urls.py
Normal file
12
backend/server/integrations/urls.py
Normal 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
|
||||||
|
]
|
77
backend/server/integrations/views.py
Normal file
77
backend/server/integrations/views.py
Normal 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)
|
|
@ -56,6 +56,7 @@ INSTALLED_APPS = (
|
||||||
'adventures',
|
'adventures',
|
||||||
'worldtravel',
|
'worldtravel',
|
||||||
'users',
|
'users',
|
||||||
|
'integrations',
|
||||||
'django.contrib.gis',
|
'django.contrib.gis',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue