236 lines
7.4 KiB
JavaScript
236 lines
7.4 KiB
JavaScript
import db from "../sql.mjs";
|
|
import lib from "../lib.mjs";
|
|
import search from "../routeinc/search.mjs";
|
|
|
|
const _eps = 20;
|
|
|
|
export default (router, tpl) => {
|
|
router.get(/^\/search(\/)?$/, lib.loggedin, async (req, res) => {
|
|
let ret;
|
|
let mode = req.url.qs.mode;
|
|
let tag = req.url.qs.tag ?? [];
|
|
let page = req.url.qs.page ?? 1;
|
|
let total = 0;
|
|
let pagination, link;
|
|
|
|
if (tag.length > 0) {
|
|
if (tag.startsWith('src:')) {
|
|
total = (await db`
|
|
select count(*) as total
|
|
from "items"
|
|
where src ilike ${'%' + tag.substring(4) + '%'} and active = true
|
|
group by "items".id
|
|
`).length;
|
|
|
|
const pages = +Math.ceil(total / _eps);
|
|
const act_page = Math.min(pages, page || 1);
|
|
const offset = Math.max(0, (act_page - 1) * _eps);
|
|
|
|
ret = await db`
|
|
select *
|
|
from "items"
|
|
where
|
|
src ilike ${'%' + tag.substring(4) + '%'} and
|
|
active = true
|
|
group by "items".id
|
|
order by "items".id desc
|
|
offset ${offset}
|
|
limit ${_eps}
|
|
`;
|
|
|
|
const cheat = [];
|
|
for (let i = Math.max(1, act_page - 3); i <= Math.min(act_page + 3, pages); i++)
|
|
cheat.push(i);
|
|
|
|
pagination = {
|
|
start: 1,
|
|
end: pages,
|
|
prev: (act_page > 1) ? act_page - 1 : null,
|
|
next: (act_page < pages) ? act_page + 1 : null,
|
|
page: act_page,
|
|
cheat: cheat,
|
|
uff: false
|
|
};
|
|
link = {
|
|
main: `/search/?tag=${tag}`,
|
|
path: '&page='
|
|
};
|
|
}
|
|
else if (tag.startsWith('title:')) {
|
|
const titleQuery = tag.substring(6).trim();
|
|
const q = '%' + titleQuery + '%';
|
|
|
|
total = (await db`
|
|
select count(*) as total
|
|
from "items"
|
|
where title ilike ${q} and active = true
|
|
`)[0]?.total ?? 0;
|
|
total = +total;
|
|
|
|
const pages = +Math.ceil(total / _eps);
|
|
const act_page = Math.min(Math.max(pages, 1), page || 1);
|
|
const offset = Math.max(0, (act_page - 1) * _eps);
|
|
|
|
ret = await db`
|
|
select *
|
|
from "items"
|
|
where title ilike ${q} and active = true
|
|
order by id desc
|
|
offset ${offset}
|
|
limit ${_eps}
|
|
`;
|
|
|
|
const cheat = [];
|
|
for (let i = Math.max(1, act_page - 3); i <= Math.min(act_page + 3, pages); i++)
|
|
cheat.push(i);
|
|
|
|
pagination = {
|
|
start: 1,
|
|
end: pages,
|
|
prev: (act_page > 1) ? act_page - 1 : null,
|
|
next: (act_page < pages) ? act_page + 1 : null,
|
|
page: act_page,
|
|
cheat: cheat,
|
|
uff: false
|
|
};
|
|
link = {
|
|
main: `/search/?tag=${encodeURIComponent(tag)}`,
|
|
path: '&page='
|
|
};
|
|
}
|
|
else if (mode === 'strict') {
|
|
const tags = tag.split(',').map(t => t.trim()).filter(t => t.length > 0);
|
|
|
|
if (tags.length > 0) {
|
|
const lowerTags = tags.map(t => t.toLowerCase());
|
|
|
|
const countResult = await db`
|
|
select count(sub.id) as total from (
|
|
select "items".id
|
|
from "items"
|
|
join "tags_assign" on "tags_assign".item_id = "items".id
|
|
join "tags" on "tags".id = "tags_assign".tag_id
|
|
where "tags".normalized = ANY(ARRAY(SELECT slugify(x) FROM unnest(${tags}::text[]) AS x))
|
|
and "items".active = true
|
|
group by "items".id
|
|
having count(distinct "tags".normalized) = ${tags.length}
|
|
) sub
|
|
`;
|
|
total = countResult.length > 0 ? countResult[0].total : 0;
|
|
|
|
const pages = +Math.ceil(total / _eps);
|
|
const act_page = Math.min(pages, page || 1);
|
|
const offset = Math.max(0, (act_page - 1) * _eps);
|
|
|
|
const rows = await db`
|
|
select "items".id, "items".username, "items".mime, min("tags".tag) as tag
|
|
from "items"
|
|
join "tags_assign" on "tags_assign".item_id = "items".id
|
|
join "tags" on "tags".id = "tags_assign".tag_id
|
|
where "tags".normalized = ANY(ARRAY(SELECT slugify(x) FROM unnest(${tags}::text[]) AS x))
|
|
and "items".active = true
|
|
group by "items".id
|
|
having count(distinct "tags".normalized) = ${tags.length}
|
|
order by "items".id desc
|
|
offset ${offset}
|
|
limit ${_eps}
|
|
`;
|
|
|
|
ret = rows.map(r => ({ ...r, score: 1.0 }));
|
|
|
|
const cheat = [];
|
|
for (let i = Math.max(1, act_page - 3); i <= Math.min(act_page + 3, pages); i++)
|
|
cheat.push(i);
|
|
|
|
pagination = {
|
|
start: 1,
|
|
end: pages,
|
|
prev: (act_page > 1) ? act_page - 1 : null,
|
|
next: (act_page < pages) ? act_page + 1 : null,
|
|
page: act_page,
|
|
cheat: cheat,
|
|
uff: false
|
|
};
|
|
link = {
|
|
main: `/search/?tag=${encodeURIComponent(tag)}&mode=strict`,
|
|
path: '&page='
|
|
};
|
|
} else {
|
|
total = 0;
|
|
ret = [];
|
|
}
|
|
}
|
|
else {
|
|
const q = '%' + tag + '%';
|
|
|
|
const countResult = await db`
|
|
select count(*) as total from (
|
|
select 1
|
|
from "items"
|
|
join "tags_assign" on "tags_assign".item_id = "items".id
|
|
join "tags" on "tags".id = "tags_assign".tag_id
|
|
where ("tags".tag ilike ${q} or "tags".normalized like '%' || slugify(${tag}) || '%')
|
|
and "items".active = true
|
|
group by "items".id
|
|
) sub
|
|
`;
|
|
total = countResult.length > 0 ? parseInt(countResult[0].total) : 0;
|
|
|
|
const pages = +Math.ceil(total / _eps);
|
|
const act_page = Math.min(pages, page || 1);
|
|
const offset = Math.max(0, (act_page - 1) * _eps);
|
|
|
|
const rows = await db`
|
|
select "items".id, "items".username, "items".mime, min("tags".tag) as tag
|
|
from "items"
|
|
join "tags_assign" on "tags_assign".item_id = "items".id
|
|
join "tags" on "tags".id = "tags_assign".tag_id
|
|
where ("tags".tag ilike ${q} or "tags".normalized like '%' || slugify(${tag}) || '%')
|
|
and "items".active = true
|
|
group by "items".id
|
|
order by "items".id desc
|
|
offset ${offset}
|
|
limit ${_eps}
|
|
`;
|
|
ret = search(rows, tag);
|
|
|
|
const cheat = [];
|
|
for (let i = Math.max(1, act_page - 3); i <= Math.min(act_page + 3, pages); i++)
|
|
cheat.push(i);
|
|
|
|
pagination = {
|
|
start: 1,
|
|
end: pages,
|
|
prev: (act_page > 1) ? act_page - 1 : null,
|
|
next: (act_page < pages) ? act_page + 1 : null,
|
|
page: act_page,
|
|
cheat: cheat,
|
|
uff: false
|
|
};
|
|
link = {
|
|
main: `/search/?tag=${encodeURIComponent(tag)}`,
|
|
path: '&page='
|
|
};
|
|
}
|
|
}
|
|
|
|
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
|
|
res.setHeader('Pragma', 'no-cache');
|
|
res.setHeader('Expires', '0');
|
|
res.setHeader('Surrogate-Control', 'no-store');
|
|
|
|
res.reply({
|
|
body: tpl.render("search", {
|
|
result: ret,
|
|
totals: await lib.countf0cks(),
|
|
searchstring: tag,
|
|
count: total,
|
|
pagination,
|
|
link,
|
|
session: (req.session && req.session.user) ? { ...req.session } : false,
|
|
mode: req.url.qs.mode
|
|
}, req)
|
|
});
|
|
});
|
|
};
|