fix(overriderules): apply override rules during request only for non-admin/non-auto-approve users (#1197)

Updated the logic of override rules to be applied during the request phase and not during
send-to-arr phase. In addition, override rules will only apply for non-admin/non-auto-approve users.

fix #1195
This commit is contained in:
Fallenbagel
2024-12-30 10:25:02 +08:00
committed by GitHub
parent c98becf936
commit 8da4870997

View File

@@ -207,6 +207,84 @@ export class MediaRequest {
} }
} }
// Apply overrides if the user is not an admin or has the "auto approve" permission
const useOverrides = !user.hasPermission(
[
requestBody.is4k ? Permission.AUTO_APPROVE_4K : Permission.AUTO_APPROVE,
Permission.MANAGE_REQUESTS,
],
{ type: 'or' }
);
let rootFolder = requestBody.rootFolder;
let profileId = requestBody.profileId;
let tags = requestBody.tags;
if (useOverrides) {
const overrideRuleRepository = getRepository(OverrideRule);
const overrideRules = await overrideRuleRepository.find({
where:
requestBody.mediaType === MediaType.MOVIE
? { radarrServiceId: requestBody.serverId }
: { sonarrServiceId: requestBody.serverId },
});
const appliedOverrideRules = overrideRules.filter((rule) => {
if (
rule.users &&
!rule.users
.split(',')
.some((userId) => Number(userId) === requestUser.id)
) {
return false;
}
if (
rule.genre &&
!rule.genre
.split(',')
.some((genreId) =>
tmdbMedia.genres
.map((genre) => genre.id)
.includes(Number(genreId))
)
) {
return false;
}
if (
rule.language &&
!rule.language
.split('|')
.some((languageId) => languageId === tmdbMedia.original_language)
) {
return false;
}
return true;
});
const overrideRootFolder = appliedOverrideRules.find(
(rule) => rule.rootFolder
)?.rootFolder;
if (overrideRootFolder) {
rootFolder = overrideRootFolder;
}
const overrideProfileId = appliedOverrideRules.find(
(rule) => rule.profileId
)?.profileId;
if (overrideProfileId) {
profileId = overrideProfileId;
}
const overrideTags = appliedOverrideRules.find((rule) => rule.tags)?.tags;
if (overrideTags) {
tags = [
...new Set([
...(tags || []),
...overrideTags.split(',').map((tag) => Number(tag)),
]),
];
}
}
if (requestBody.mediaType === MediaType.MOVIE) { if (requestBody.mediaType === MediaType.MOVIE) {
await mediaRepository.save(media); await mediaRepository.save(media);
@@ -245,9 +323,9 @@ export class MediaRequest {
: undefined, : undefined,
is4k: requestBody.is4k, is4k: requestBody.is4k,
serverId: requestBody.serverId, serverId: requestBody.serverId,
profileId: requestBody.profileId, profileId: profileId,
rootFolder: requestBody.rootFolder, rootFolder: rootFolder,
tags: requestBody.tags, tags: tags,
isAutoRequest: options.isAutoRequest ?? false, isAutoRequest: options.isAutoRequest ?? false,
}); });
@@ -717,6 +795,48 @@ export class MediaRequest {
return; return;
} }
let rootFolder = radarrSettings.activeDirectory;
let qualityProfile = radarrSettings.activeProfileId;
let tags = radarrSettings.tags ? [...radarrSettings.tags] : [];
if (
this.rootFolder &&
this.rootFolder !== '' &&
this.rootFolder !== radarrSettings.activeDirectory
) {
rootFolder = this.rootFolder;
logger.info(`Request has an override root folder: ${rootFolder}`, {
label: 'Media Request',
requestId: this.id,
mediaId: this.media.id,
});
}
if (
this.profileId &&
this.profileId !== radarrSettings.activeProfileId
) {
qualityProfile = this.profileId;
logger.info(
`Request has an override quality profile ID: ${qualityProfile}`,
{
label: 'Media Request',
requestId: this.id,
mediaId: this.media.id,
}
);
}
if (this.tags && !isEqual(this.tags, radarrSettings.tags)) {
tags = this.tags;
logger.info(`Request has override tags`, {
label: 'Media Request',
requestId: this.id,
mediaId: this.media.id,
tagIds: tags,
});
}
const tmdb = new TheMovieDb(); const tmdb = new TheMovieDb();
const radarr = new RadarrAPI({ const radarr = new RadarrAPI({
apiKey: radarrSettings.apiKey, apiKey: radarrSettings.apiKey,
@@ -737,151 +857,6 @@ export class MediaRequest {
return; return;
} }
let rootFolder = radarrSettings.activeDirectory;
let qualityProfile = radarrSettings.activeProfileId;
let tags = radarrSettings.tags ? [...radarrSettings.tags] : [];
const overrideRuleRepository = getRepository(OverrideRule);
const overrideRules = await overrideRuleRepository.find({
where: { radarrServiceId: radarrSettings.id },
});
const appliedOverrideRules = overrideRules.filter((rule) => {
if (
rule.users &&
!rule.users
.split(',')
.some((userId) => Number(userId) === this.requestedBy.id)
) {
return false;
}
if (
rule.genre &&
!rule.genre
.split(',')
.some((genreId) =>
movie.genres.map((genre) => genre.id).includes(Number(genreId))
)
) {
return false;
}
if (
rule.language &&
!rule.language
.split('|')
.some((languageId) => languageId === movie.original_language)
) {
return false;
}
if (
rule.keywords &&
!rule.keywords
.split(',')
.some((keywordId) =>
movie.keywords.keywords
.map((keyword) => keyword.id)
.includes(Number(keywordId))
)
) {
return false;
}
return true;
});
if (
this.rootFolder &&
this.rootFolder !== '' &&
this.rootFolder !== radarrSettings.activeDirectory
) {
rootFolder = this.rootFolder;
logger.info(
`Request has a manually overriden root folder: ${rootFolder}`,
{
label: 'Media Request',
requestId: this.id,
mediaId: this.media.id,
}
);
} else {
const overrideRootFolder = appliedOverrideRules.find(
(rule) => rule.rootFolder
)?.rootFolder;
if (overrideRootFolder) {
rootFolder = overrideRootFolder;
this.rootFolder = rootFolder;
logger.info(
`Request has an override root folder from override rules: ${rootFolder}`,
{
label: 'Media Request',
requestId: this.id,
mediaId: this.media.id,
}
);
}
}
if (
this.profileId &&
this.profileId !== radarrSettings.activeProfileId
) {
qualityProfile = this.profileId;
logger.info(
`Request has a manually overriden quality profile ID: ${qualityProfile}`,
{
label: 'Media Request',
requestId: this.id,
mediaId: this.media.id,
}
);
} else {
const overrideProfileId = appliedOverrideRules.find(
(rule) => rule.profileId
)?.profileId;
if (overrideProfileId) {
qualityProfile = overrideProfileId;
this.profileId = qualityProfile;
logger.info(
`Request has an override quality profile ID from override rules: ${qualityProfile}`,
{
label: 'Media Request',
requestId: this.id,
mediaId: this.media.id,
}
);
}
}
if (this.tags && !isEqual(this.tags, radarrSettings.tags)) {
tags = this.tags;
logger.info(`Request has manually overriden tags`, {
label: 'Media Request',
requestId: this.id,
mediaId: this.media.id,
tagIds: tags,
});
} else {
const overrideTags = appliedOverrideRules.find(
(rule) => rule.tags
)?.tags;
if (overrideTags) {
tags = [
...new Set([
...tags,
...overrideTags.split(',').map((tag) => Number(tag)),
]),
];
this.tags = tags;
logger.info(`Request has override tags from override rules`, {
label: 'Media Request',
requestId: this.id,
mediaId: this.media.id,
tagIds: tags,
});
}
}
const requestRepository = getRepository(MediaRequest);
requestRepository.save(this);
if (radarrSettings.tagRequests) { if (radarrSettings.tagRequests) {
let userTag = (await radarr.getTags()).find((v) => let userTag = (await radarr.getTags()).find((v) =>
v.label.startsWith(this.requestedBy.id + ' - ') v.label.startsWith(this.requestedBy.id + ' - ')
@@ -923,6 +898,7 @@ export class MediaRequest {
mediaId: this.media.id, mediaId: this.media.id,
}); });
const requestRepository = getRepository(MediaRequest);
this.status = MediaRequestStatus.APPROVED; this.status = MediaRequestStatus.APPROVED;
await requestRepository.save(this); await requestRepository.save(this);
return; return;
@@ -962,6 +938,8 @@ export class MediaRequest {
await mediaRepository.save(media); await mediaRepository.save(media);
}) })
.catch(async () => { .catch(async () => {
const requestRepository = getRepository(MediaRequest);
this.status = MediaRequestStatus.FAILED; this.status = MediaRequestStatus.FAILED;
await requestRepository.save(this); await requestRepository.save(this);
@@ -1061,7 +1039,6 @@ export class MediaRequest {
throw new Error('Media data not found'); throw new Error('Media data not found');
} }
const requestRepository = getRepository(MediaRequest);
if ( if (
media[this.is4k ? 'status4k' : 'status'] === MediaStatus.AVAILABLE media[this.is4k ? 'status4k' : 'status'] === MediaStatus.AVAILABLE
) { ) {
@@ -1071,6 +1048,7 @@ export class MediaRequest {
mediaId: this.media.id, mediaId: this.media.id,
}); });
const requestRepository = getRepository(MediaRequest);
this.status = MediaRequestStatus.APPROVED; this.status = MediaRequestStatus.APPROVED;
await requestRepository.save(this); await requestRepository.save(this);
return; return;
@@ -1085,6 +1063,7 @@ export class MediaRequest {
const tvdbId = series.external_ids.tvdb_id ?? media.tvdbId; const tvdbId = series.external_ids.tvdb_id ?? media.tvdbId;
if (!tvdbId) { if (!tvdbId) {
const requestRepository = getRepository(MediaRequest);
await mediaRepository.remove(media); await mediaRepository.remove(media);
await requestRepository.remove(this); await requestRepository.remove(this);
throw new Error('TVDB ID not found'); throw new Error('TVDB ID not found');
@@ -1122,110 +1101,29 @@ export class MediaRequest {
? [...sonarrSettings.tags] ? [...sonarrSettings.tags]
: []; : [];
const overrideRuleRepository = getRepository(OverrideRule);
const overrideRules = await overrideRuleRepository.find({
where: { sonarrServiceId: sonarrSettings.id },
});
const appliedOverrideRules = overrideRules.filter((rule) => {
if (
rule.users &&
!rule.users
.split(',')
.some((userId) => Number(userId) === this.requestedBy.id)
) {
return false;
}
if (
rule.genre &&
!rule.genre
.split(',')
.some((genreId) =>
series.genres.map((genre) => genre.id).includes(Number(genreId))
)
) {
return false;
}
if (
rule.language &&
!rule.language
.split('|')
.some((languageId) => languageId === series.original_language)
) {
return false;
}
if (
rule.keywords &&
!rule.keywords
.split(',')
.some((keywordId) =>
series.keywords.results
.map((keyword) => keyword.id)
.includes(Number(keywordId))
)
) {
return false;
}
return true;
});
if ( if (
this.rootFolder && this.rootFolder &&
this.rootFolder !== '' && this.rootFolder !== '' &&
this.rootFolder !== rootFolder this.rootFolder !== rootFolder
) { ) {
rootFolder = this.rootFolder; rootFolder = this.rootFolder;
logger.info( logger.info(`Request has an override root folder: ${rootFolder}`, {
`Request has a manually overriden root folder: ${rootFolder}`, label: 'Media Request',
{ requestId: this.id,
label: 'Media Request', mediaId: this.media.id,
requestId: this.id, });
mediaId: this.media.id,
}
);
} else {
const overrideRootFolder = appliedOverrideRules.find(
(rule) => rule.rootFolder
)?.rootFolder;
if (overrideRootFolder) {
rootFolder = overrideRootFolder;
this.rootFolder = rootFolder;
logger.info(
`Request has an override root folder from override rules: ${rootFolder}`,
{
label: 'Media Request',
requestId: this.id,
mediaId: this.media.id,
}
);
}
} }
if (this.profileId && this.profileId !== qualityProfile) { if (this.profileId && this.profileId !== qualityProfile) {
qualityProfile = this.profileId; qualityProfile = this.profileId;
logger.info( logger.info(
`Request has a manually overriden quality profile ID: ${qualityProfile}`, `Request has an override quality profile ID: ${qualityProfile}`,
{ {
label: 'Media Request', label: 'Media Request',
requestId: this.id, requestId: this.id,
mediaId: this.media.id, mediaId: this.media.id,
} }
); );
} else {
const overrideProfileId = appliedOverrideRules.find(
(rule) => rule.profileId
)?.profileId;
if (overrideProfileId) {
qualityProfile = overrideProfileId;
this.profileId = qualityProfile;
logger.info(
`Request has an override quality profile ID from override rules: ${qualityProfile}`,
{
label: 'Media Request',
requestId: this.id,
mediaId: this.media.id,
}
);
}
} }
if ( if (
@@ -1245,31 +1143,12 @@ export class MediaRequest {
if (this.tags && !isEqual(this.tags, tags)) { if (this.tags && !isEqual(this.tags, tags)) {
tags = this.tags; tags = this.tags;
logger.info(`Request has manually overriden tags`, { logger.info(`Request has override tags`, {
label: 'Media Request', label: 'Media Request',
requestId: this.id, requestId: this.id,
mediaId: this.media.id, mediaId: this.media.id,
tagIds: tags, tagIds: tags,
}); });
} else {
const overrideTags = appliedOverrideRules.find(
(rule) => rule.tags
)?.tags;
if (overrideTags) {
tags = [
...new Set([
...tags,
...overrideTags.split(',').map((tag) => Number(tag)),
]),
];
this.tags = tags;
logger.info(`Request has override tags from override rules`, {
label: 'Media Request',
requestId: this.id,
mediaId: this.media.id,
tagIds: tags,
});
}
} }
if (sonarrSettings.tagRequests) { if (sonarrSettings.tagRequests) {
@@ -1304,8 +1183,6 @@ export class MediaRequest {
} }
} }
requestRepository.save(this);
const sonarrSeriesOptions: AddSeriesOptions = { const sonarrSeriesOptions: AddSeriesOptions = {
profileId: qualityProfile, profileId: qualityProfile,
languageProfileId: languageProfile, languageProfileId: languageProfile,
@@ -1343,6 +1220,8 @@ export class MediaRequest {
await mediaRepository.save(media); await mediaRepository.save(media);
}) })
.catch(async () => { .catch(async () => {
const requestRepository = getRepository(MediaRequest);
this.status = MediaRequestStatus.FAILED; this.status = MediaRequestStatus.FAILED;
await requestRepository.save(this); await requestRepository.save(this);