Added type-is filter keys (is:image and is:video)

Fixed text queries threshold being applied to moderators

Bumped v1 version string and rebuilt client assets
This commit is contained in:
Bobby Wibowo 2020-05-03 04:32:45 +07:00
parent d201b03f59
commit 126cfe0e15
No known key found for this signature in database
GPG Key ID: 51C3A1E1E22D26CF
5 changed files with 71 additions and 10 deletions

View File

@ -770,6 +770,7 @@ self.list = async (req, res) => {
const MAX_WILDCARDS_IN_KEY = 2 const MAX_WILDCARDS_IN_KEY = 2
const MAX_TEXT_QUERIES = 3 // non-keyed keywords const MAX_TEXT_QUERIES = 3 // non-keyed keywords
const MAX_SORT_KEYS = 1 const MAX_SORT_KEYS = 1
const MAX_IS_KEYS = 1
const filterObj = { const filterObj = {
uploaders: [], uploaders: [],
@ -777,6 +778,10 @@ self.list = async (req, res) => {
queries: { queries: {
exclude: {} exclude: {}
}, },
typeIs: [
'image',
'video'
],
flags: {} flags: {}
} }
@ -843,6 +848,7 @@ self.list = async (req, res) => {
filterObj.queries = searchQuery.parse(filters, { filterObj.queries = searchQuery.parse(filters, {
keywords: keywords.concat([ keywords: keywords.concat([
'is',
'sort' 'sort'
]), ]),
ranges, ranges,
@ -855,6 +861,7 @@ self.list = async (req, res) => {
if (typeof filterObj.queries.exclude.text === 'string') if (typeof filterObj.queries.exclude.text === 'string')
filterObj.queries.exclude.text = [filterObj.queries.exclude.text] filterObj.queries.exclude.text = [filterObj.queries.exclude.text]
// Text (non-keyed keywords) queries
let textQueries = 0 let textQueries = 0
if (filterObj.queries.text) textQueries += filterObj.queries.text.length if (filterObj.queries.text) textQueries += filterObj.queries.text.length
if (filterObj.queries.exclude.text) textQueries += filterObj.queries.exclude.text.length if (filterObj.queries.exclude.text) textQueries += filterObj.queries.exclude.text.length
@ -869,7 +876,7 @@ self.list = async (req, res) => {
if (filterObj.queries.text) if (filterObj.queries.text)
for (let i = 0; i < filterObj.queries.text.length; i++) { for (let i = 0; i < filterObj.queries.text.length; i++) {
const result = sqlLikeParser(filterObj.queries.text[i]) const result = sqlLikeParser(filterObj.queries.text[i])
if (result.count > MAX_WILDCARDS_IN_KEY) if (!ismoderator && result.count > MAX_WILDCARDS_IN_KEY)
return res.json({ return res.json({
success: false, success: false,
description: `Users are only allowed to use ${MAX_WILDCARDS_IN_KEY} wildcard${MAX_WILDCARDS_IN_KEY === 1 ? '' : 's'} per key.` description: `Users are only allowed to use ${MAX_WILDCARDS_IN_KEY} wildcard${MAX_WILDCARDS_IN_KEY === 1 ? '' : 's'} per key.`
@ -877,18 +884,16 @@ self.list = async (req, res) => {
filterObj.queries.text[i] = result.escaped filterObj.queries.text[i] = result.escaped
} }
if (filterObj.queries.exclude.text) { if (filterObj.queries.exclude.text)
textQueries += filterObj.queries.exclude.text.length
for (let i = 0; i < filterObj.queries.exclude.text.length; i++) { for (let i = 0; i < filterObj.queries.exclude.text.length; i++) {
const result = sqlLikeParser(filterObj.queries.exclude.text[i]) const result = sqlLikeParser(filterObj.queries.exclude.text[i])
if (result.count > MAX_WILDCARDS_IN_KEY) if (!ismoderator && result.count > MAX_WILDCARDS_IN_KEY)
return res.json({ return res.json({
success: false, success: false,
description: `Users are only allowed to use ${MAX_WILDCARDS_IN_KEY} wildcard${MAX_WILDCARDS_IN_KEY === 1 ? '' : 's'} per key.` description: `Users are only allowed to use ${MAX_WILDCARDS_IN_KEY} wildcard${MAX_WILDCARDS_IN_KEY === 1 ? '' : 's'} per key.`
}) })
filterObj.queries.exclude.text[i] = result.escaped filterObj.queries.exclude.text[i] = result.escaped
} }
}
for (const key of keywords) { for (const key of keywords) {
let queryIndex = -1 let queryIndex = -1
@ -1050,6 +1055,39 @@ self.list = async (req, res) => {
// Delete key to avoid unexpected behavior // Delete key to avoid unexpected behavior
delete filterObj.queries.sort delete filterObj.queries.sort
} }
// Parse is keys
let isKeys = 0
let isLast
if (filterObj.queries.is || filterObj.queries.exclude.is) {
for (const type of filterObj.typeIs) {
const inQuery = filterObj.queries.is && filterObj.queries.is.includes(type)
const inExclude = filterObj.queries.exclude.is && filterObj.queries.exclude.is.includes(type)
// Prioritize exclude keys when both types found
if (inQuery || inExclude) {
filterObj.flags[`is${type}`] = inExclude ? false : inQuery
if (isLast !== undefined && isLast !== filterObj.flags[`is${type}`])
return res.json({
success: false,
description: 'Cannot mix inclusion and exclusion type-is keys.'
})
isKeys++
isLast = filterObj.flags[`is${type}`]
}
}
// Delete keys to avoid unexpected behavior
delete filterObj.queries.is
delete filterObj.queries.exclude.is
}
// Regular user threshold check
if (!ismoderator && isKeys > MAX_IS_KEYS)
return res.json({
success: false,
description: `Users are only allowed to use ${MAX_IS_KEYS} type-is key${MAX_IS_KEYS === 1 ? '' : 's'} at a time.`
})
} }
function filter () { function filter () {
@ -1136,6 +1174,23 @@ self.list = async (req, res) => {
this.andWhere('expirydate', '<=', filterObj.queries.date.to) this.andWhere('expirydate', '<=', filterObj.queries.date.to)
}) })
// Then, refine using type-is flags
this.andWhere(function () {
for (const type of filterObj.typeIs) {
const patterns = utils[`${type}Exts`].map(ext => `%${ext}`)
let operator
if (filterObj.flags[`is${type}`] === true)
operator = 'like'
else if (filterObj.flags[`is${type}`] === false)
operator = 'not like'
if (operator)
for (const pattern of patterns)
this.orWhere('name', operator, pattern)
}
})
// Then, refine using the supplied keywords against their file names // Then, refine using the supplied keywords against their file names
this.andWhere(function () { this.andWhere(function () {
if (!filterObj.queries.text) return if (!filterObj.queries.text) return

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1049,13 +1049,19 @@ page.uploadFiltersHelp = element => {
API requests to the filter endpoint will attach your browser's timezone offset, so the server will automatically calculate timezone differences. API requests to the filter endpoint will attach your browser's timezone offset, so the server will automatically calculate timezone differences.
Matches can also be sorted with <b>sort</b> keys. Matches can also be sorted with <b>sort</b> keys.
Its format is: <code>sort:columnName[:d[escending]]</code>, where <code>:d[escending]</code> is an optional tag to set the direction to descending. Their formats are: <code>sort:columnName[:d[escending]]</code>, where <code>:d[escending]</code> is an optional tag to set the direction to descending.
This key must be used with internal column names used in the database (<code>id</code>, <code>${all ? 'userid' : 'albumid'}</code>, and so on), This key must be used with internal column names used in the database (<code>id</code>, <code>${all ? 'userid' : 'albumid'}</code>, and so on),
but there are 2 shortcuts available: <b>date</b> for <code>timestamp</code> column and <b>expiry</b> for <code>expirydate</code> column. but there are 2 shortcuts available: <b>date</b> for <code>timestamp</code> column and <b>expiry</b> for <code>expirydate</code> column.
This key can also be specified more than once, where their order will decide the sorting steps. This key can also be specified more than once, where their order will decide the sorting steps.
Finally, there are type-<b>is</b> keys to refine by types.
You can use <code>is:image</code> and <code>is:video</code> to list images and videos respectively.
This will only use image/video extensions whose thumbnails can be generated by the safe.
Negation sign works for this key as well.
Mixing inclusion and exclusion is not allowed (i.e. <code>is:image -is:video</code>, since the second key is redundant).
Any leftover keywords which do not use keys (non-keyed keywords) will be matched against the matches' file names. Any leftover keywords which do not use keys (non-keyed keywords) will be matched against the matches' file names.
Excluding certain keywords is also supported by adding negation sign (<b>-</b>) before the keywords. Excluding certain keywords is also supported by adding negation sign before the keywords.
<b>Internal steps:</b> <b>Internal steps:</b>
${all ? `- Query uploads passing ALL exclusion filter keys OR matching ANY filter keys, if any. ${all ? `- Query uploads passing ALL exclusion filter keys OR matching ANY filter keys, if any.

View File

@ -1,5 +1,5 @@
{ {
"1": "1588451242", "1": "1588455082",
"2": "1581416390", "2": "1581416390",
"3": "1581416390", "3": "1581416390",
"4": "1581416390", "4": "1581416390",