mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-22 06:41:46 +00:00
moving linking album to common interface
This commit is contained in:
@@ -81,7 +81,6 @@ export default function MemoriesPanel({ tripId, startDate, endDate }: MemoriesPa
|
|||||||
const [albumsLoading, setAlbumsLoading] = useState(false)
|
const [albumsLoading, setAlbumsLoading] = useState(false)
|
||||||
const [albumLinks, setAlbumLinks] = useState<{ id: number; provider: string; album_id: string; album_name: string; user_id: number; username: string; sync_enabled: number; last_synced_at: string | null }[]>([])
|
const [albumLinks, setAlbumLinks] = useState<{ id: number; provider: string; album_id: string; album_name: string; user_id: number; username: string; sync_enabled: number; last_synced_at: string | null }[]>([])
|
||||||
const [syncing, setSyncing] = useState<number | null>(null)
|
const [syncing, setSyncing] = useState<number | null>(null)
|
||||||
const pickerIntegrationBase = selectedProvider ? `/integrations/${selectedProvider}` : ''
|
|
||||||
|
|
||||||
const loadAlbumLinks = async () => {
|
const loadAlbumLinks = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -110,8 +109,17 @@ export default function MemoriesPanel({ tripId, startDate, endDate }: MemoriesPa
|
|||||||
}
|
}
|
||||||
|
|
||||||
const linkAlbum = async (albumId: string, albumName: string) => {
|
const linkAlbum = async (albumId: string, albumName: string) => {
|
||||||
|
if (!selectedProvider) {
|
||||||
|
toast.error(t('memories.error.linkAlbum'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await apiClient.post(`${pickerIntegrationBase}/trips/${tripId}/album-links`, { album_id: albumId, album_name: albumName })
|
await apiClient.post(`/integrations/memories/trips/${tripId}/album-links`, {
|
||||||
|
album_id: albumId,
|
||||||
|
album_name: albumName,
|
||||||
|
provider: selectedProvider,
|
||||||
|
})
|
||||||
setShowAlbumPicker(false)
|
setShowAlbumPicker(false)
|
||||||
await loadAlbumLinks()
|
await loadAlbumLinks()
|
||||||
// Auto-sync after linking
|
// Auto-sync after linking
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import {
|
|||||||
proxyOriginal,
|
proxyOriginal,
|
||||||
isValidAssetId,
|
isValidAssetId,
|
||||||
listAlbums,
|
listAlbums,
|
||||||
createAlbumLink,
|
|
||||||
syncAlbumAssets,
|
syncAlbumAssets,
|
||||||
getAssetInfo,
|
getAssetInfo,
|
||||||
} from '../services/immichService';
|
} from '../services/immichService';
|
||||||
@@ -125,17 +124,6 @@ router.get('/albums', authenticate, async (req: Request, res: Response) => {
|
|||||||
res.json({ albums: result.albums });
|
res.json({ albums: result.albums });
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/trips/:tripId/album-links', authenticate, async (req: Request, res: Response) => {
|
|
||||||
const authReq = req as AuthRequest;
|
|
||||||
const { tripId } = req.params;
|
|
||||||
if (!canAccessTrip(tripId, authReq.user.id)) return res.status(404).json({ error: 'Trip not found' });
|
|
||||||
const { album_id, album_name } = req.body;
|
|
||||||
if (!album_id) return res.status(400).json({ error: 'album_id required' });
|
|
||||||
const result = createAlbumLink(tripId, authReq.user.id, album_id, album_name);
|
|
||||||
if (!result.success) return res.status(400).json({ error: result.error });
|
|
||||||
res.json({ success: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post('/trips/:tripId/album-links/:linkId/sync', authenticate, async (req: Request, res: Response) => {
|
router.post('/trips/:tripId/album-links/:linkId/sync', authenticate, async (req: Request, res: Response) => {
|
||||||
const authReq = req as AuthRequest;
|
const authReq = req as AuthRequest;
|
||||||
const { tripId, linkId } = req.params;
|
const { tripId, linkId } = req.params;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { AuthRequest } from '../types';
|
|||||||
import {
|
import {
|
||||||
listTripPhotos,
|
listTripPhotos,
|
||||||
listTripAlbumLinks,
|
listTripAlbumLinks,
|
||||||
|
createTripAlbumLink,
|
||||||
removeAlbumLink,
|
removeAlbumLink,
|
||||||
addTripPhotos,
|
addTripPhotos,
|
||||||
removeTripPhoto,
|
removeTripPhoto,
|
||||||
@@ -90,4 +91,12 @@ router.put('/trips/:tripId/photos/sharing', authenticate, (req: Request, res: Re
|
|||||||
broadcast(tripId, 'memories:updated', { userId: authReq.user.id }, req.headers['x-socket-id'] as string);
|
broadcast(tripId, 'memories:updated', { userId: authReq.user.id }, req.headers['x-socket-id'] as string);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.post('/trips/:tripId/album-links', authenticate, (req: Request, res: Response) => {
|
||||||
|
const authReq = req as AuthRequest;
|
||||||
|
const { tripId } = req.params;
|
||||||
|
const result = createTripAlbumLink(tripId, authReq.user.id, req.body?.provider, req.body?.album_id, req.body?.album_name);
|
||||||
|
if ('error' in result) return res.status(result.status).json({ error: result.error });
|
||||||
|
res.json({ success: true });
|
||||||
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
@@ -86,25 +86,6 @@ router.get('/albums', authenticate, async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/trips/:tripId/album-links', authenticate, (req: Request, res: Response) => {
|
|
||||||
const authReq = req as AuthRequest;
|
|
||||||
const { tripId } = req.params;
|
|
||||||
const body = req.body as Record<string, unknown>;
|
|
||||||
const albumId = parseStringBodyField(body.album_id);
|
|
||||||
const albumName = parseStringBodyField(body.album_name);
|
|
||||||
|
|
||||||
if (!albumId) {
|
|
||||||
return handleSynologyError(res, new SynologyServiceError(400, 'Album ID is required'), 'Missing required fields');
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
linkSynologyAlbum(authReq.user.id, tripId, albumId, albumName || undefined);
|
|
||||||
res.json({ success: true });
|
|
||||||
} catch (err: unknown) {
|
|
||||||
handleSynologyError(res, err, 'Failed to link album');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post('/trips/:tripId/album-links/:linkId/sync', authenticate, async (req: Request, res: Response) => {
|
router.post('/trips/:tripId/album-links/:linkId/sync', authenticate, async (req: Request, res: Response) => {
|
||||||
const authReq = req as AuthRequest;
|
const authReq = req as AuthRequest;
|
||||||
const { tripId, linkId } = req.params;
|
const { tripId, linkId } = req.params;
|
||||||
|
|||||||
@@ -285,22 +285,6 @@ export async function listAlbums(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function createAlbumLink(
|
|
||||||
tripId: string,
|
|
||||||
userId: number,
|
|
||||||
albumId: string,
|
|
||||||
albumName: string
|
|
||||||
): { success: boolean; error?: string } {
|
|
||||||
try {
|
|
||||||
db.prepare(
|
|
||||||
'INSERT OR IGNORE INTO trip_album_links (trip_id, user_id, provider, album_id, album_name) VALUES (?, ?, ?, ?, ?)'
|
|
||||||
).run(tripId, userId, 'immich', albumId, albumName || '');
|
|
||||||
return { success: true };
|
|
||||||
} catch {
|
|
||||||
return { success: false, error: 'Album already linked' };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function syncAlbumAssets(
|
export async function syncAlbumAssets(
|
||||||
tripId: string,
|
tripId: string,
|
||||||
linkId: string,
|
linkId: string,
|
||||||
|
|||||||
@@ -76,6 +76,37 @@ export function listTripAlbumLinks(tripId: string, userId: number): { links: any
|
|||||||
return { links };
|
return { links };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createTripAlbumLink(
|
||||||
|
tripId: string,
|
||||||
|
userId: number,
|
||||||
|
providerRaw: unknown,
|
||||||
|
albumIdRaw: unknown,
|
||||||
|
albumNameRaw: unknown,
|
||||||
|
): { success: true } | ServiceError {
|
||||||
|
const denied = accessDeniedIfMissing(tripId, userId);
|
||||||
|
if (denied) return denied;
|
||||||
|
|
||||||
|
const provider = String(providerRaw || '').toLowerCase();
|
||||||
|
const albumId = String(albumIdRaw || '').trim();
|
||||||
|
const albumName = String(albumNameRaw || '').trim();
|
||||||
|
|
||||||
|
if (!provider) {
|
||||||
|
return { error: 'provider is required', status: 400 };
|
||||||
|
}
|
||||||
|
if (!albumId) {
|
||||||
|
return { error: 'album_id required', status: 400 };
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
db.prepare(
|
||||||
|
'INSERT OR IGNORE INTO trip_album_links (trip_id, user_id, provider, album_id, album_name) VALUES (?, ?, ?, ?, ?)'
|
||||||
|
).run(tripId, userId, provider, albumId, albumName);
|
||||||
|
return { success: true };
|
||||||
|
} catch {
|
||||||
|
return { error: 'Album already linked', status: 400 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function removeAlbumLink(tripId: string, linkId: string, userId: number): { success: true } | ServiceError {
|
export function removeAlbumLink(tripId: string, linkId: string, userId: number): { success: true } | ServiceError {
|
||||||
const denied = accessDeniedIfMissing(tripId, userId);
|
const denied = accessDeniedIfMissing(tripId, userId);
|
||||||
if (denied) return denied;
|
if (denied) return denied;
|
||||||
|
|||||||
@@ -438,23 +438,6 @@ export async function listSynologyAlbums(userId: number): Promise<{ albums: Arra
|
|||||||
return { albums };
|
return { albums };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function linkSynologyAlbum(userId: number, tripId: string, albumId: string | number | undefined, albumName?: string): void {
|
|
||||||
if (!canAccessTrip(tripId, userId)) {
|
|
||||||
throw new SynologyServiceError(404, 'Trip not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!albumId) {
|
|
||||||
throw new SynologyServiceError(400, 'album_id required');
|
|
||||||
}
|
|
||||||
|
|
||||||
const changes = db.prepare(
|
|
||||||
'INSERT OR IGNORE INTO trip_album_links (trip_id, user_id, provider, album_id, album_name) VALUES (?, ?, ?, ?, ?)'
|
|
||||||
).run(tripId, userId, SYNOLOGY_PROVIDER, String(albumId), albumName || '').changes;
|
|
||||||
|
|
||||||
if (changes === 0) {
|
|
||||||
throw new SynologyServiceError(400, 'Album already linked');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function syncSynologyAlbumLink(userId: number, tripId: string, linkId: string): Promise<{ added: number; total: number }> {
|
export async function syncSynologyAlbumLink(userId: number, tripId: string, linkId: string): Promise<{ added: number; total: number }> {
|
||||||
const link = db.prepare(`SELECT * FROM trip_album_links WHERE id = ? AND trip_id = ? AND user_id = ? AND provider = ?`)
|
const link = db.prepare(`SELECT * FROM trip_album_links WHERE id = ? AND trip_id = ? AND user_id = ? AND provider = ?`)
|
||||||
|
|||||||
Reference in New Issue
Block a user