diff --git a/server/controllers/servers.controller.ts b/server/controllers/servers.controller.ts index 8d4c10c12..0a325f3d8 100644 --- a/server/controllers/servers.controller.ts +++ b/server/controllers/servers.controller.ts @@ -162,12 +162,51 @@ const disableServerUrl = async ( return res.status(success.statusCode).json(getSuccessResponse(success)); }; +const deleteServerFolder = async ( + req: TypedRequest, + res: Response +) => { + const { folderId } = req.params; + + await service.servers.deleteFolderById({ id: folderId }); + + const success = ApiSuccess.noContent({ data: null }); + return res.status(success.statusCode).json(getSuccessResponse(success)); +}; + +const enableServerFolder = async ( + req: TypedRequest, + res: Response +) => { + const { folderId } = req.params; + + await service.servers.enableFolderById({ id: folderId }); + + const success = ApiSuccess.noContent({ data: null }); + return res.status(success.statusCode).json(getSuccessResponse(success)); +}; + +const disableServerFolder = async ( + req: TypedRequest, + res: Response +) => { + const { folderId } = req.params; + + await service.servers.disableFolderById({ id: folderId }); + + const success = ApiSuccess.noContent({ data: null }); + return res.status(success.statusCode).json(getSuccessResponse(success)); +}; + export const serversController = { createServer, createServerUrl, deleteServer, + deleteServerFolder, deleteServerUrl, + disableServerFolder, disableServerUrl, + enableServerFolder, enableServerUrl, getServerDetail, getServerList, diff --git a/server/helpers/albums.helpers.ts b/server/helpers/albums.helpers.ts index b1eec5d68..b188d35a4 100644 --- a/server/helpers/albums.helpers.ts +++ b/server/helpers/albums.helpers.ts @@ -13,7 +13,7 @@ export enum AlbumSort { RATING = 'rating', } -const include = (options: { songs?: boolean; user?: AuthUser }) => { +const include = (user: AuthUser, options: { songs?: boolean }) => { // Prisma.AlbumInclude const props = { _count: { @@ -24,17 +24,17 @@ const include = (options: { songs?: boolean; user?: AuthUser }) => { }, albumArtists: true, artists: true, - favorites: { where: { userId: options.user?.id } }, + favorites: { where: { userId: user?.id } }, genres: true, images: true, ratings: { where: { - userId: options.user?.id, + userId: user?.id, }, }, server: true, serverFolders: true, - songs: options?.songs && songHelpers.findMany(), + songs: options?.songs && songHelpers.findMany(user), }; return props; diff --git a/server/helpers/api-model.ts b/server/helpers/api-model.ts index 6957271ca..155d2773d 100644 --- a/server/helpers/api-model.ts +++ b/server/helpers/api-model.ts @@ -176,6 +176,7 @@ const relatedServerFolders = (items: ServerFolder[]) => { /* eslint-disable sort-keys-fix/sort-keys-fix */ id: item.id, name: item.name, + enabled: item.enabled, remoteId: item.remoteId, lastScannedAt: item.lastScannedAt, /* eslint-enable sort-keys-fix/sort-keys-fix */ @@ -266,13 +267,14 @@ const songs = ( ) => { return ( items?.map((item) => { - const url = options.url ? options.url : item.server.serverUrls[0].url; + const customUrl = item.server.serverUrls[0].url; + const baseUrl = customUrl ? customUrl : options.url; const stream = streamUrl(options.type, { deviceId: options.deviceId, remoteId: item.remoteId, token: options.token, - url: options.url, + url: baseUrl, userId: options.userId, }); @@ -294,7 +296,7 @@ const songs = ( item.images, options.type, ImageType.PRIMARY, - url, + baseUrl, item.remoteId ), releaseDate: item.releaseDate, diff --git a/server/helpers/songs.helpers.ts b/server/helpers/songs.helpers.ts index 14b74b15e..920fe9bd0 100644 --- a/server/helpers/songs.helpers.ts +++ b/server/helpers/songs.helpers.ts @@ -1,4 +1,5 @@ import { Prisma } from '@prisma/client'; +import { AuthUser } from '@middleware/authenticate'; const include = () => { const props: Prisma.SongInclude = { @@ -16,7 +17,7 @@ const include = () => { return props; }; -const findMany = () => { +const findMany = (user: AuthUser) => { const props: Prisma.SongFindManyArgs = { include: { album: true, @@ -26,7 +27,11 @@ const findMany = () => { images: true, ratings: true, server: { - include: { serverUrls: true }, + include: { + serverUrls: { + where: { userServerUrls: { some: { userId: user.id } } }, + }, + }, }, }, orderBy: [ diff --git a/server/routes/servers.route.ts b/server/routes/servers.route.ts index 542d714ee..fff7e5947 100644 --- a/server/routes/servers.route.ts +++ b/server/routes/servers.route.ts @@ -85,3 +85,30 @@ router validateRequest(validation.servers.disableUrl), controller.servers.disableServerUrl ); + +router.param('folderId', async (_req, _res, next, folderId) => { + await service.servers.findFolderById({ id: folderId }); + next(); +}); + +router + .route('/:serverId/folder/:folderId') + .delete( + authenticateAdmin, + validateRequest(validation.servers.deleteFolder), + controller.servers.deleteServerFolder + ); + +router + .route('/:serverId/folder/:folderId/enable') + .post( + validateRequest(validation.servers.enableFolder), + controller.servers.enableServerFolder + ); + +router + .route('/:serverId/folder/:folderId/disable') + .post( + validateRequest(validation.servers.disableFolder), + controller.servers.disableServerFolder + ); diff --git a/server/services/albums.service.ts b/server/services/albums.service.ts index 508ba989b..c72379fe1 100644 --- a/server/services/albums.service.ts +++ b/server/services/albums.service.ts @@ -9,7 +9,7 @@ const findById = async (user: AuthUser, options: { id: string }) => { const { id } = options; const album = await prisma.album.findUnique({ - include: helpers.albums.include({ songs: true }), + include: helpers.albums.include(user, { songs: true }), where: { id }, }); @@ -53,7 +53,7 @@ const findMany = async (options: AlbumFindManyOptions) => { prisma.albumRating.findMany({ include: { album: { - include: helpers.albums.include({ songs: false, user }), + include: helpers.albums.include(user, { songs: false }), }, }, orderBy: { value: orderBy }, @@ -78,7 +78,7 @@ const findMany = async (options: AlbumFindManyOptions) => { }, }), prisma.album.findMany({ - include: helpers.albums.include({ songs: false, user }), + include: helpers.albums.include(user, { songs: false }), skip, take, where: { @@ -95,7 +95,7 @@ const findMany = async (options: AlbumFindManyOptions) => { where: { OR: helpers.shared.serverFolderFilter(serverFolderIds) }, }), prisma.album.findMany({ - include: helpers.albums.include({ songs: false, user }), + include: helpers.albums.include(user, { songs: false }), orderBy: [helpers.albums.sort(sortBy, orderBy)], skip, take, diff --git a/server/services/servers.service.ts b/server/services/servers.service.ts index a8dd3ce42..07a8a8475 100644 --- a/server/services/servers.service.ts +++ b/server/services/servers.service.ts @@ -370,8 +370,10 @@ const refresh = async (options: { id: string }) => { const fullScan = async (options: { id: string; serverFolderId?: string[] }) => { const { id, serverFolderId } = options; + + // Only allow scan of enabled folders const server = await prisma.server.findUnique({ - include: { serverFolders: true }, + include: { serverFolders: { where: { enabled: true } } }, where: { id }, }); @@ -544,14 +546,52 @@ const disableUrlById = async (user: AuthUser) => { return null; }; +const findFolderById = async (options: { id: string }) => { + const url = await prisma.serverFolder.findUnique({ + where: { id: options.id }, + }); + + if (!url) { + throw ApiError.notFound('Folder not found.'); + } + + return url; +}; + +const deleteFolderById = async (options: { id: string }) => { + return null; +}; + +const enableFolderById = async (options: { id: string }) => { + await prisma.serverFolder.update({ + data: { enabled: true }, + where: { id: options.id }, + }); + + return null; +}; + +const disableFolderById = async (options: { id: string }) => { + await prisma.serverFolder.update({ + data: { enabled: false }, + where: { id: options.id }, + }); + + return null; +}; + export const serversService = { create, createUrl, deleteById, + deleteFolderById, deleteUrlById, + disableFolderById, disableUrlById, + enableFolderById, enableUrlById, findById, + findFolderById, findMany, findServerUrlById, findUrlById, diff --git a/server/validations/servers.validation.ts b/server/validations/servers.validation.ts index c398d42dd..720c1ba82 100644 --- a/server/validations/servers.validation.ts +++ b/server/validations/servers.validation.ts @@ -134,17 +134,47 @@ const disableUrl = { query: z.object({}), }; +const deleteFolder = { + body: z.object({}), + params: z.object({ + ...idValidation('serverId'), + ...idValidation('folderId'), + }), + query: z.object({}), +}; + +const enableFolder = { + body: z.object({}), + params: z.object({ + ...idValidation('serverId'), + ...idValidation('folderId'), + }), + query: z.object({}), +}; + +const disableFolder = { + body: z.object({}), + params: z.object({ + ...idValidation('serverId'), + ...idValidation('folderId'), + }), + query: z.object({}), +}; + export const serversValidation = { create, createCredential, createUrl, deleteCredential, + deleteFolder, deleteServer, deleteUrl, detail, disableCredential, + disableFolder, disableUrl, enableCredential, + enableFolder, enableUrl, getCredentialDetail, list,