Archived
1
0

feat: Сервис и контроллер сейвов с методами получения

This commit is contained in:
2025-11-19 14:43:39 +03:00
parent f3c75c3b88
commit 5f60d12996
7 changed files with 723 additions and 16 deletions

View File

@ -0,0 +1,176 @@
import { Elysia, t } from 'elysia';
import { savesService } from '@/services/saves.service';
import { s3Service } from '@/services/s3.service';
import { auth } from '@/lib/auth';
import { betterAuthMiddleware } from '@/lib/auth/middleware';
export const savesController = new Elysia({ prefix: '/saves' })
.use(betterAuthMiddleware)
.get(
'/my',
async ({ user, set }) => {
try {
const saves = await savesService.getUserSaves(user.id);
return saves.map((save) => ({
id: save.id,
name: save.name,
type: save.type,
description: save.description,
tags: save.tags,
visibility: save.visibility,
shareUrl: save.visibility === 'link' ? save.shareUrl : undefined,
url: save.url,
createdAt: save.createdAt.toISOString(),
updatedAt: save.updatedAt.toISOString(),
}));
} catch (error) {
set.status = 500;
return {
error: error instanceof Error ? error.message : 'Failed to get saves'
};
}
},
{
detail: {
tags: ['Saves'],
summary: 'Get my saves',
description: 'Returns all saves of the current user',
},
auth: true
}
)
.get(
'/u/:slug',
async ({ params: { slug }, set }) => {
try {
const saves = await savesService.getPublicSavesByUser(slug);
return saves.map((save) => ({
id: save.id,
name: save.name,
type: save.type,
description: save.description,
tags: save.tags,
visibility: save.visibility,
url: save.url,
createdAt: save.createdAt.toISOString(),
updatedAt: save.updatedAt.toISOString(),
}));
} catch (error) {
set.status = 500;
return {
error: error instanceof Error ? error.message : 'Failed to get public saves'
};
}
},
{
params: t.Object({
slug: t.String(),
}),
detail: {
tags: ['Saves'],
summary: 'Get public saves by user slug',
description: 'Returns only public saves of a specific user',
},
}
)
.get(
'/:id',
async ({ params: { id }, user, set, headers, request }) => {
let shareToken: string | undefined;
try {
const url = new URL(request.url);
shareToken = url.searchParams.get('share') || undefined;
} catch {
shareToken = undefined;
}
let userId = user?.id;
if (!userId) {
try {
const session = await auth.api.getSession({ headers });
userId = session?.user?.id!;
} catch {}
}
const saveId = Number(id);
if (isNaN(saveId)) {
set.status = 400;
return { error: 'Invalid save ID' };
}
const save = await savesService.getById(saveId, userId, shareToken);
if (!save) {
set.status = 404;
return { error: 'Save not found' };
}
return {
id: save.id,
name: save.name,
type: save.type,
description: save.description,
tags: save.tags,
visibility: save.visibility,
shareUrl: save.visibility === 'link' ? save.shareUrl : undefined,
userId: save.userId,
url: save.url,
createdAt: save.createdAt.toISOString(),
updatedAt: save.updatedAt.toISOString(),
};
},
{
params: t.Object({
id: t.String(),
}),
detail: {
tags: ['Saves'],
summary: 'Get save by ID',
description: 'Returns a specific save with access control',
},
auth: true,
}
)
.get(
'/:id/download',
async ({ params: { id }, query, set, headers }) => {
const session = await auth.api.getSession({ headers })
const shareToken = query.share;
const saveId = Number(id);
if (isNaN(saveId)) {
set.status = 400;
return { error: 'Invalid save ID' };
}
const save = await savesService.getById(saveId, session?.user.id, shareToken);
if (!save) {
set.status = 404;
return { error: 'Save not found' };
}
const signedUrl = s3Service.getSignedUrl(save.s3Key, 3600);
set.status = 302;
set.headers['Location'] = signedUrl;
return null;
},
{
params: t.Object({
id: t.String(),
}),
query: t.Object({
share: t.Optional(t.String()),
}),
detail: {
tags: ['Saves'],
summary: 'Download save file',
description: 'Redirects to a presigned URL for downloading the file',
},
}
);