fix(server): improve error handling and API spec

This commit is contained in:
Michael Thomas
2024-11-12 10:49:09 -05:00
parent 445041e89d
commit 70524a19e9
3 changed files with 39 additions and 34 deletions

View File

@@ -4427,6 +4427,8 @@ paths:
responses:
'204':
description: Unlinking account succeeded
'400':
description: Unlink request invalid
'404':
description: User does not exist
/user/{userId}/settings/linked-accounts/jellyfin:
@@ -4475,6 +4477,8 @@ paths:
responses:
'204':
description: Unlinking account succeeded
'400':
description: Unlink request invalid
'404':
description: User does not exist
/user/{userId}/settings/notifications:

View File

@@ -7,5 +7,6 @@ export enum ApiErrorCode {
NoAdminUser = 'NO_ADMIN_USER',
SyncErrorGroupedFolders = 'SYNC_ERROR_GROUPED_FOLDERS',
SyncErrorNoLibraries = 'SYNC_ERROR_NO_LIBRARIES',
Unauthorized = 'UNAUTHORIZED',
Unknown = 'UNKNOWN',
}

View File

@@ -200,9 +200,8 @@ userSettingsRoutes.post<
status: e.statusCode,
message: e.errorCode,
});
} else {
return next({ status: 500, message: e.message });
}
return next({ status: 500, message: e.message });
}
});
@@ -310,16 +309,16 @@ userSettingsRoutes.post<
userSettingsRoutes.post<{ authToken: string }>(
'/linked-accounts/plex',
isOwnProfile(),
async (req, res, next) => {
async (req, res) => {
const settings = getSettings();
const userRepository = getRepository(User);
if (!req.user) {
return next({ status: 404, message: 'Unauthorized' });
return res.status(404).json({ code: ApiErrorCode.Unauthorized });
}
// Make sure Plex login is enabled
if (settings.main.mediaServerType !== MediaServerType.PLEX) {
return res.status(500).json({ error: 'Plex login is disabled' });
return res.status(500).json({ message: 'Plex login is disabled' });
}
// First we need to use this auth token to get the user's email from plex.tv
@@ -329,7 +328,7 @@ userSettingsRoutes.post<{ authToken: string }>(
// Do not allow linking of an already linked account
if (await userRepository.exist({ where: { plexId: account.id } })) {
return res.status(422).json({
error: 'This Plex account is already linked to a Jellyseerr user',
message: 'This Plex account is already linked to a Jellyseerr user',
});
}
@@ -338,7 +337,7 @@ userSettingsRoutes.post<{ authToken: string }>(
// Emails do not match
if (user.email !== account.email) {
return res.status(422).json({
error:
message:
'This Plex account is registered under a different email address.',
});
}
@@ -357,13 +356,13 @@ userSettingsRoutes.post<{ authToken: string }>(
userSettingsRoutes.delete<{ id: string }>(
'/linked-accounts/plex',
isOwnProfileOrAdmin(),
async (req, res, next) => {
async (req, res) => {
const settings = getSettings();
const userRepository = getRepository(User);
// Make sure Plex login is enabled
if (settings.main.mediaServerType !== MediaServerType.PLEX) {
return res.status(500).json({ error: 'Plex login is disabled' });
return res.status(500).json({ message: 'Plex login is disabled' });
}
try {
@@ -372,12 +371,11 @@ userSettingsRoutes.delete<{ id: string }>(
});
if (!user) {
return next({ status: 404, message: 'User not found.' });
return res.status(404).json({ message: 'User not found.' });
}
if (user.id === 1) {
return next({
status: 400,
return res.status(400).json({
message:
'Cannot unlink media server accounts for the primary administrator.',
});
@@ -391,8 +389,7 @@ userSettingsRoutes.delete<{ id: string }>(
)?.password;
if (!user.email || !hasPassword) {
return next({
status: 400,
return res.status(400).json({
message: 'User does not have a local email or password set.',
});
}
@@ -405,7 +402,7 @@ userSettingsRoutes.delete<{ id: string }>(
return res.status(204).send();
} catch (e) {
next({ status: 500, message: e.message });
return res.status(500).json({ message: e.message });
}
}
);
@@ -413,19 +410,21 @@ userSettingsRoutes.delete<{ id: string }>(
userSettingsRoutes.post<{ username: string; password: string }>(
'/linked-accounts/jellyfin',
isOwnProfile(),
async (req, res, next) => {
async (req, res) => {
const settings = getSettings();
const userRepository = getRepository(User);
if (!req.user) {
return next({ status: 401, message: 'Unauthorized' });
return res.status(401).json({ code: ApiErrorCode.Unauthorized });
}
// Make sure jellyfin login is enabled
if (
settings.main.mediaServerType !== MediaServerType.JELLYFIN &&
settings.main.mediaServerType !== MediaServerType.EMBY
) {
return res.status(500).json({ error: 'Jellyfin/Emby login is disabled' });
return res
.status(500)
.json({ message: 'Jellyfin/Emby login is disabled' });
}
// Do not allow linking of an already linked account
@@ -435,7 +434,7 @@ userSettingsRoutes.post<{ username: string; password: string }>(
})
) {
return res.status(422).json({
error: 'The specified account is already linked to a Jellyseerr user',
message: 'The specified account is already linked to a Jellyseerr user',
});
}
@@ -447,7 +446,7 @@ userSettingsRoutes.post<{ username: string; password: string }>(
const jellyfinserver = new JellyfinAPI(hostname, undefined, deviceId);
const ip = req.ip;
let clientIp;
let clientIp: string | undefined;
if (ip) {
if (net.isIPv4(ip)) {
clientIp = ip;
@@ -470,7 +469,8 @@ userSettingsRoutes.post<{ username: string; password: string }>(
})
) {
return res.status(422).json({
error: 'The specified account is already linked to a Jellyseerr user',
message:
'The specified account is already linked to a Jellyseerr user',
});
}
@@ -496,12 +496,12 @@ userSettingsRoutes.post<{ username: string; password: string }>(
});
if (
e instanceof ApiError &&
(e.errorCode == ApiErrorCode.InvalidCredentials ||
e.errorCode == ApiErrorCode.NotAdmin)
)
return next({ status: 401, message: 'Unauthorized' });
e.errorCode === ApiErrorCode.InvalidCredentials
) {
return res.status(401).json({ code: e.errorCode });
}
return next({ status: 500 });
return res.status(500).send();
}
}
);
@@ -509,7 +509,7 @@ userSettingsRoutes.post<{ username: string; password: string }>(
userSettingsRoutes.delete<{ id: string }>(
'/linked-accounts/jellyfin',
isOwnProfileOrAdmin(),
async (req, res, next) => {
async (req, res) => {
const settings = getSettings();
const userRepository = getRepository(User);
@@ -518,7 +518,9 @@ userSettingsRoutes.delete<{ id: string }>(
settings.main.mediaServerType !== MediaServerType.JELLYFIN &&
settings.main.mediaServerType !== MediaServerType.EMBY
) {
return res.status(500).json({ error: 'Jellyfin/Emby login is disabled' });
return res
.status(500)
.json({ message: 'Jellyfin/Emby login is disabled' });
}
try {
@@ -527,12 +529,11 @@ userSettingsRoutes.delete<{ id: string }>(
});
if (!user) {
return next({ status: 404, message: 'User not found.' });
return res.status(404).json({ message: 'User not found.' });
}
if (user.id === 1) {
return next({
status: 400,
return res.status(400).json({
message:
'Cannot unlink media server accounts for the primary administrator.',
});
@@ -546,8 +547,7 @@ userSettingsRoutes.delete<{ id: string }>(
)?.password;
if (!user.email || !hasPassword) {
return next({
status: 400,
return res.status(400).json({
message: 'User does not have a local email or password set.',
});
}
@@ -561,7 +561,7 @@ userSettingsRoutes.delete<{ id: string }>(
return res.status(204).send();
} catch (e) {
next({ status: 500, message: e.message });
return res.status(500).json({ message: e.message });
}
}
);