Skip to content

Commit

Permalink
feat(blacklist): allow filtering between manually blacklisted and aut…
Browse files Browse the repository at this point in the history
…omatically blacklisted entries
  • Loading branch information
benbeauchamp7 committed Jan 26, 2025
1 parent 478760f commit 0d6d2d3
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 14 deletions.
6 changes: 6 additions & 0 deletions overseerr-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4122,6 +4122,12 @@ paths:
type: string
nullable: true
example: dune
- in: query
name: filter
schema:
type: string
enum: [all, manual, blacktags]
default: manual
responses:
'200':
description: Blacklisted items returned
Expand Down
35 changes: 25 additions & 10 deletions server/routes/blacklist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,39 +19,54 @@ export const blacklistAdd = z.object({
user: z.coerce.number(),
});

const blacklistGet = z.object({
take: z.coerce.number().int().positive().default(25),
skip: z.coerce.number().int().nonnegative().default(0),
search: z.string().optional(),
filter: z.enum(['all', 'manual', 'blacktags']).optional(),
});

blacklistRoutes.get(
'/',
isAuthenticated([Permission.MANAGE_BLACKLIST, Permission.VIEW_BLACKLIST], {
type: 'or',
}),
async (req, res, next) => {
const pageSize = req.query.take ? Number(req.query.take) : 25;
const skip = req.query.skip ? Number(req.query.skip) : 0;
const search = (req.query.search as string) ?? '';
const { take, skip, search, filter } = blacklistGet.parse(req.query);

try {
let query = getRepository(Blacklist)
.createQueryBuilder('blacklist')
.leftJoinAndSelect('blacklist.user', 'user');
.leftJoinAndSelect('blacklist.user', 'user')
.where('1 = 1'); // Allow use of andWhere later

switch (filter) {
case 'manual':
query = query.andWhere('blacklist.blacktags IS NULL');
break;
case 'blacktags':
query = query.andWhere('blacklist.blacktags IS NOT NULL');
break;
}

if (search.length > 0) {
query = query.where('blacklist.title like :title', {
if (search) {
query = query.andWhere('blacklist.title like :title', {
title: `%${search}%`,
});
}

const [blacklistedItems, itemsCount] = await query
.orderBy('blacklist.createdAt', 'DESC')
.take(pageSize)
.take(take)
.skip(skip)
.getManyAndCount();

return res.status(200).json({
pageInfo: {
pages: Math.ceil(itemsCount / pageSize),
pageSize,
pages: Math.ceil(itemsCount / take),
pageSize: take,
results: itemsCount,
page: Math.ceil(skip / pageSize) + 1,
page: Math.ceil(skip / take) + 1,
},
results: blacklistedItems,
} as BlacklistResultsResponse);
Expand Down
62 changes: 58 additions & 4 deletions src/components/Blacklist/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import defineMessages from '@app/utils/defineMessages';
import {
ChevronLeftIcon,
ChevronRightIcon,
FunnelIcon,
MagnifyingGlassIcon,
TrashIcon,
} from '@heroicons/react/24/solid';
Expand Down Expand Up @@ -42,8 +43,17 @@ const messages = defineMessages('components.Blacklist', {
blacklistdate: 'date',
blacklistedby: '{date} by {user}',
blacklistNotFoundError: '<strong>{title}</strong> is not blacklisted.',
filterManual: 'Manual',
filterBlacktags: 'Blacktags',
showAllBlacklisted: 'Show All Blacklisted Media',
});

enum Filter {
ALL = 'all',
MANUAL = 'manual',
BLACKTAGS = 'blacktags',
}

const isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => {
return (movie as MovieDetails).title !== undefined;
};
Expand All @@ -52,6 +62,7 @@ const Blacklist = () => {
const [currentPageSize, setCurrentPageSize] = useState<number>(10);
const [searchFilter, debouncedSearchFilter, setSearchFilter] =
useDebouncedState('');
const [currentFilter, setCurrentFilter] = useState<Filter>(Filter.MANUAL);
const router = useRouter();
const intl = useIntl();

Expand All @@ -64,9 +75,11 @@ const Blacklist = () => {
error,
mutate: revalidate,
} = useSWR<BlacklistResultsResponse>(
`/api/v1/blacklist/?take=${currentPageSize}
&skip=${pageIndex * currentPageSize}
${debouncedSearchFilter ? `&search=${debouncedSearchFilter}` : ''}`,
`/api/v1/blacklist/?take=${currentPageSize}&skip=${
pageIndex * currentPageSize
}&filter=${currentFilter}${
debouncedSearchFilter ? `&search=${debouncedSearchFilter}` : ''
}`,
{
refreshInterval: 0,
revalidateOnFocus: false,
Expand Down Expand Up @@ -97,7 +110,38 @@ const Blacklist = () => {
<div className="mb-4 flex flex-col justify-between lg:flex-row lg:items-end">
<Header>{intl.formatMessage(globalMessages.blacklist)}</Header>

<div className="mt-2 flex flex-grow flex-col sm:flex-grow-0 sm:flex-row sm:justify-end">
<div className="mt-2 flex flex-grow flex-col sm:flex-row lg:flex-grow-0">
<div className="mb-2 flex flex-grow sm:mb-0 sm:mr-2 lg:flex-grow-0">
<span className="inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-800 px-3 text-sm text-gray-100">
<FunnelIcon className="h-6 w-6" />
</span>
<select
id="filter"
name="filter"
onChange={(e) => {
setCurrentFilter(e.target.value as Filter);
router.push({
pathname: router.pathname,
query: router.query.userId
? { userId: router.query.userId }
: {},
});
}}
value={currentFilter}
className="rounded-r-only"
>
<option value="all">
{intl.formatMessage(globalMessages.all)}
</option>
<option value="manual">
{intl.formatMessage(messages.filterManual)}
</option>
<option value="blacktags">
{intl.formatMessage(messages.filterBlacktags)}
</option>
</select>
</div>

<div className="mb-2 flex flex-grow sm:mb-0 sm:mr-2 md:flex-grow-0">
<span className="inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-800 px-3 text-sm text-gray-100">
<MagnifyingGlassIcon className="h-6 w-6" />
Expand All @@ -119,6 +163,16 @@ const Blacklist = () => {
<span className="text-2xl text-gray-400">
{intl.formatMessage(globalMessages.noresults)}
</span>
{currentFilter !== Filter.ALL && (
<div className="mt-4">
<Button
buttonType="primary"
onClick={() => setCurrentFilter(Filter.ALL)}
>
{intl.formatMessage(messages.showAllBlacklisted)}
</Button>
</div>
)}
</div>
) : (
data.results.map((item: BlacklistItem) => {
Expand Down

0 comments on commit 0d6d2d3

Please sign in to comment.