Files
f0ckm/src/inc/routes/search.mjs

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)
});
});
};