feat: Сервис и контроллер сейвов с методами получения
This commit is contained in:
176
apps/backend/src/controllers/saves.controller.ts
Normal file
176
apps/backend/src/controllers/saves.controller.ts
Normal 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',
|
||||
},
|
||||
}
|
||||
);
|
||||
Reference in New Issue
Block a user