mirror of
https://github.com/BobbyWibowo/lolisafe.git
synced 2025-02-07 22:09:01 +00:00
Added filtering uploads by albumid
This works when listing all uploads as well, but Album column will only be shown when albumid key is used in the filters. I plan to someday add Manage Albums menu, which will use "View uploads" buttons, just like the ones in Manage Users.
This commit is contained in:
parent
1980d536db
commit
d201b03f59
@ -808,8 +808,7 @@ self.list = async (req, res) => {
|
|||||||
|
|
||||||
// Look for any glob operators
|
// Look for any glob operators
|
||||||
const match = pattern.match(/(?<!\\)(\*|\?)/g)
|
const match = pattern.match(/(?<!\\)(\*|\?)/g)
|
||||||
if (match && match.length) {
|
if (match && match.length)
|
||||||
logger.debug(pattern, match)
|
|
||||||
return {
|
return {
|
||||||
count: match.length,
|
count: match.length,
|
||||||
// Replace glob operators with their SQL equivalents
|
// Replace glob operators with their SQL equivalents
|
||||||
@ -817,17 +816,19 @@ self.list = async (req, res) => {
|
|||||||
.replace(/(?<!\\)\*/g, '%')
|
.replace(/(?<!\\)\*/g, '%')
|
||||||
.replace(/(?<!\\)\?/g, '_')
|
.replace(/(?<!\\)\?/g, '_')
|
||||||
}
|
}
|
||||||
} else {
|
else
|
||||||
return {
|
return {
|
||||||
count: 0,
|
count: 0,
|
||||||
// Assume partial match
|
// Assume partial match
|
||||||
escaped: `%${escaped}%`
|
escaped: `%${escaped}%`
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters) {
|
if (filters) {
|
||||||
let keywords = []
|
let keywords = [
|
||||||
|
'albumid'
|
||||||
|
]
|
||||||
|
|
||||||
// Only allow filtering by 'ip' and 'user' keys when listing all uploads
|
// Only allow filtering by 'ip' and 'user' keys when listing all uploads
|
||||||
if (all)
|
if (all)
|
||||||
keywords = keywords.concat([
|
keywords = keywords.concat([
|
||||||
@ -1003,13 +1004,19 @@ self.list = async (req, res) => {
|
|||||||
// Parse sort keys
|
// Parse sort keys
|
||||||
if (filterObj.queries.sort) {
|
if (filterObj.queries.sort) {
|
||||||
let allowed = [
|
let allowed = [
|
||||||
'albumid',
|
|
||||||
'expirydate',
|
'expirydate',
|
||||||
'id',
|
'id',
|
||||||
'name',
|
'name',
|
||||||
'size',
|
'size',
|
||||||
'timestamp'
|
'timestamp'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// Only allow sorting by 'albumid' when not listing album's uploads
|
||||||
|
if (req.params.id === undefined)
|
||||||
|
allowed = allowed.concat([
|
||||||
|
'albumid'
|
||||||
|
])
|
||||||
|
|
||||||
// Only allow sorting by 'ip' and 'userid' columns when listing all uploads
|
// Only allow sorting by 'ip' and 'userid' columns when listing all uploads
|
||||||
if (all)
|
if (all)
|
||||||
allowed = allowed.concat([
|
allowed = allowed.concat([
|
||||||
@ -1046,86 +1053,102 @@ self.list = async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function filter () {
|
function filter () {
|
||||||
if (req.params.id !== undefined) {
|
// If listing all uploads
|
||||||
this.where('albumid', req.params.id)
|
if (all)
|
||||||
} else {
|
this.where(function () {
|
||||||
// Sheesh, these look so overbearing...
|
// Filter uploads matching any of the supplied 'user' keys and/or NULL flag
|
||||||
if (!all)
|
// Prioritze exclude keys when both types found
|
||||||
// If not listing all uploads, list user's uploads
|
this.orWhere(function () {
|
||||||
this.where('userid', user.id)
|
if (filterObj.excludeUploaders.length)
|
||||||
else
|
this.orWhereNotIn('userid', filterObj.excludeUploaders.map(v => v.id))
|
||||||
this.where(function () {
|
else if (filterObj.uploaders.length)
|
||||||
// Filter uploads matching any of the supplied 'user' keys and/or NULL flag
|
this.orWhereIn('userid', filterObj.uploaders.map(v => v.id))
|
||||||
// Prioritze exclude keys when both types found
|
// Such overbearing logic for NULL values, smh...
|
||||||
this.orWhere(function () {
|
if ((filterObj.excludeUploaders.length && filterObj.flags.userNull !== false) ||
|
||||||
if (filterObj.excludeUploaders.length)
|
(filterObj.uploaders.length && filterObj.flags.userNull) ||
|
||||||
this.orWhereNotIn('userid', filterObj.excludeUploaders.map(v => v.id))
|
(!filterObj.excludeUploaders.length && !filterObj.uploaders.length && filterObj.flags.userNull))
|
||||||
else if (filterObj.uploaders.length)
|
this.orWhereNull('userid')
|
||||||
this.orWhereIn('userid', filterObj.uploaders.map(v => v.id))
|
else if (filterObj.flags.userNull === false)
|
||||||
// Such overbearing logic for NULL values, smh...
|
this.orWhereNotNull('userid')
|
||||||
if ((filterObj.excludeUploaders.length && filterObj.flags.userNull !== false) ||
|
|
||||||
(filterObj.uploaders.length && filterObj.flags.userNull) ||
|
|
||||||
(!filterObj.excludeUploaders.length && !filterObj.uploaders.length && filterObj.flags.userNull))
|
|
||||||
this.orWhereNull('userid')
|
|
||||||
else if (filterObj.flags.userNull === false)
|
|
||||||
this.orWhereNotNull('userid')
|
|
||||||
})
|
|
||||||
|
|
||||||
// Filter uploads matching any of the supplied 'ip' keys and/or NULL flag
|
|
||||||
// Same prioritization logic as above
|
|
||||||
this.orWhere(function () {
|
|
||||||
if (filterObj.queries.exclude.ip)
|
|
||||||
this.orWhereNotIn('ip', filterObj.queries.exclude.ip)
|
|
||||||
else if (filterObj.queries.ip)
|
|
||||||
this.orWhereIn('ip', filterObj.queries.ip)
|
|
||||||
// ...
|
|
||||||
if ((filterObj.queries.exclude.ip && filterObj.flags.ipNull !== false) ||
|
|
||||||
(filterObj.queries.ip && filterObj.flags.ipNull) ||
|
|
||||||
(!filterObj.queries.exclude.ip && !filterObj.queries.ip && filterObj.flags.ipNull))
|
|
||||||
this.orWhereNull('ip')
|
|
||||||
else if (filterObj.flags.ipNull === false)
|
|
||||||
this.orWhereNotNull('ip')
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Then, refine using the supplied 'date' ranges
|
// Filter uploads matching any of the supplied 'ip' keys and/or NULL flag
|
||||||
|
// Same prioritization logic as above
|
||||||
|
this.orWhere(function () {
|
||||||
|
if (filterObj.queries.exclude.ip)
|
||||||
|
this.orWhereNotIn('ip', filterObj.queries.exclude.ip)
|
||||||
|
else if (filterObj.queries.ip)
|
||||||
|
this.orWhereIn('ip', filterObj.queries.ip)
|
||||||
|
// ...
|
||||||
|
if ((filterObj.queries.exclude.ip && filterObj.flags.ipNull !== false) ||
|
||||||
|
(filterObj.queries.ip && filterObj.flags.ipNull) ||
|
||||||
|
(!filterObj.queries.exclude.ip && !filterObj.queries.ip && filterObj.flags.ipNull))
|
||||||
|
this.orWhereNull('ip')
|
||||||
|
else if (filterObj.flags.ipNull === false)
|
||||||
|
this.orWhereNotNull('ip')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
else
|
||||||
|
// If not listing all uploads, list user's uploads
|
||||||
|
this.where('userid', user.id)
|
||||||
|
|
||||||
|
// Then, refine using any of the supplied 'albumid' keys and/or NULL flag
|
||||||
|
// Same prioritization logic as 'userid' and 'ip' above
|
||||||
|
if (req.params.id === undefined)
|
||||||
this.andWhere(function () {
|
this.andWhere(function () {
|
||||||
if (!filterObj.queries.date) return
|
if (filterObj.queries.exclude.albumid)
|
||||||
if (typeof filterObj.queries.date.from === 'number')
|
this.orWhereNotIn('albumid', filterObj.queries.exclude.albumid)
|
||||||
if (typeof filterObj.queries.date.to === 'number')
|
else if (filterObj.queries.albumid)
|
||||||
this.andWhereBetween('timestamp', [filterObj.queries.date.from, filterObj.queries.date.to])
|
this.orWhereIn('albumid', filterObj.queries.albumid)
|
||||||
else
|
// ...
|
||||||
this.andWhere('timestamp', '>=', filterObj.queries.date.from)
|
if ((filterObj.queries.exclude.albumid && filterObj.flags.albumidNull !== false) ||
|
||||||
|
(filterObj.queries.albumid && filterObj.flags.albumidNull) ||
|
||||||
|
(!filterObj.queries.exclude.albumid && !filterObj.queries.albumid && filterObj.flags.albumidNull))
|
||||||
|
this.orWhereNull('albumid')
|
||||||
|
else if (filterObj.flags.ipNull === false)
|
||||||
|
this.orWhereNotNull('albumid')
|
||||||
|
})
|
||||||
|
else if (!all)
|
||||||
|
// If not listing all uploads, list uploads from user's album
|
||||||
|
this.andWhere('albumid', req.params.id)
|
||||||
|
|
||||||
|
// Then, refine using the supplied 'date' ranges
|
||||||
|
this.andWhere(function () {
|
||||||
|
if (!filterObj.queries.date) return
|
||||||
|
if (typeof filterObj.queries.date.from === 'number')
|
||||||
|
if (typeof filterObj.queries.date.to === 'number')
|
||||||
|
this.andWhereBetween('timestamp', [filterObj.queries.date.from, filterObj.queries.date.to])
|
||||||
else
|
else
|
||||||
this.andWhere('timestamp', '<=', filterObj.queries.date.to)
|
this.andWhere('timestamp', '>=', filterObj.queries.date.from)
|
||||||
})
|
else
|
||||||
|
this.andWhere('timestamp', '<=', filterObj.queries.date.to)
|
||||||
|
})
|
||||||
|
|
||||||
// Then, refine using the supplied 'expiry' ranges
|
// Then, refine using the supplied 'expiry' ranges
|
||||||
this.andWhere(function () {
|
this.andWhere(function () {
|
||||||
if (!filterObj.queries.expiry) return
|
if (!filterObj.queries.expiry) return
|
||||||
if (typeof filterObj.queries.expiry.from === 'number')
|
if (typeof filterObj.queries.expiry.from === 'number')
|
||||||
if (typeof filterObj.queries.expiry.to === 'number')
|
if (typeof filterObj.queries.expiry.to === 'number')
|
||||||
this.andWhereBetween('expirydate', [filterObj.queries.expiry.from, filterObj.queries.expiry.to])
|
this.andWhereBetween('expirydate', [filterObj.queries.expiry.from, filterObj.queries.expiry.to])
|
||||||
else
|
|
||||||
this.andWhere('expirydate', '>=', filterObj.queries.date.from)
|
|
||||||
else
|
else
|
||||||
this.andWhere('expirydate', '<=', filterObj.queries.date.to)
|
this.andWhere('expirydate', '>=', filterObj.queries.date.from)
|
||||||
})
|
else
|
||||||
|
this.andWhere('expirydate', '<=', filterObj.queries.date.to)
|
||||||
|
})
|
||||||
|
|
||||||
// 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
|
||||||
for (const pattern of filterObj.queries.text)
|
for (const pattern of filterObj.queries.text)
|
||||||
this.orWhere('name', 'like', pattern)
|
this.orWhere('name', 'like', pattern)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Finally, refine using the supplied exclusions against their file names
|
// Finally, refine using the supplied exclusions against their file names
|
||||||
this.andWhere(function () {
|
this.andWhere(function () {
|
||||||
if (!filterObj.queries.exclude.text) return
|
if (!filterObj.queries.exclude.text) return
|
||||||
for (const pattern of filterObj.queries.exclude.text)
|
for (const pattern of filterObj.queries.exclude.text)
|
||||||
this.orWhere('name', 'not like', pattern)
|
this.orWhere('name', 'not like', pattern)
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -1144,9 +1167,13 @@ self.list = async (req, res) => {
|
|||||||
const columns = ['id', 'name', 'userid', 'size', 'timestamp']
|
const columns = ['id', 'name', 'userid', 'size', 'timestamp']
|
||||||
if (temporaryUploads)
|
if (temporaryUploads)
|
||||||
columns.push('expirydate')
|
columns.push('expirydate')
|
||||||
|
if (!all || filterObj.queries.albumid || filterObj.queries.exclude.albumid ||
|
||||||
|
filterObj.flags.albumidNull !== undefined)
|
||||||
|
columns.push('albumid')
|
||||||
|
|
||||||
// Only select IPs if we are listing all uploads
|
// Only select IPs if we are listing all uploads
|
||||||
columns.push(all ? 'ip' : 'albumid')
|
if (all)
|
||||||
|
columns.push('ip')
|
||||||
|
|
||||||
// Build raw query for order by (sorting) operation
|
// Build raw query for order by (sorting) operation
|
||||||
let orderByRaw
|
let orderByRaw
|
||||||
@ -1177,9 +1204,9 @@ self.list = async (req, res) => {
|
|||||||
file.thumb = `thumbs/${file.name.slice(0, -file.extname.length)}.png`
|
file.thumb = `thumbs/${file.name.slice(0, -file.extname.length)}.png`
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are not listing all uploads, query album names
|
// If we queried albumid, query album names
|
||||||
let albums = {}
|
let albums = {}
|
||||||
if (!all) {
|
if (columns.includes('albumid')) {
|
||||||
const albumids = files
|
const albumids = files
|
||||||
.map(file => file.albumid)
|
.map(file => file.albumid)
|
||||||
.filter((v, i, a) => {
|
.filter((v, i, a) => {
|
||||||
@ -1188,7 +1215,6 @@ self.list = async (req, res) => {
|
|||||||
albums = await db.table('albums')
|
albums = await db.table('albums')
|
||||||
.whereIn('id', albumids)
|
.whereIn('id', albumids)
|
||||||
.where('enabled', 1)
|
.where('enabled', 1)
|
||||||
.where('userid', user.id)
|
|
||||||
.select('id', 'name')
|
.select('id', 'name')
|
||||||
.then(rows => {
|
.then(rows => {
|
||||||
// Build Object indexed by their IDs
|
// Build Object indexed by their IDs
|
||||||
@ -1214,7 +1240,7 @@ self.list = async (req, res) => {
|
|||||||
|
|
||||||
// If there are no uploads attached to a registered user, send response
|
// If there are no uploads attached to a registered user, send response
|
||||||
if (userids.length === 0)
|
if (userids.length === 0)
|
||||||
return res.json({ success: true, files, count, basedomain })
|
return res.json({ success: true, files, count, albums, basedomain })
|
||||||
|
|
||||||
// Query usernames of user IDs from currently selected files
|
// Query usernames of user IDs from currently selected files
|
||||||
usersTable = await db.table('users')
|
usersTable = await db.table('users')
|
||||||
@ -1226,7 +1252,7 @@ self.list = async (req, res) => {
|
|||||||
for (const user of usersTable)
|
for (const user of usersTable)
|
||||||
users[user.id] = user.username
|
users[user.id] = user.username
|
||||||
|
|
||||||
return res.json({ success: true, files, count, users, basedomain })
|
return res.json({ success: true, files, count, users, albums, basedomain })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// If moderator, capture SQLITE_ERROR and use its error message for the response's description
|
// If moderator, capture SQLITE_ERROR and use its error message for the response's description
|
||||||
let errorString
|
let errorString
|
||||||
|
2
dist/js/dashboard.js
vendored
2
dist/js/dashboard.js
vendored
File diff suppressed because one or more lines are too long
2
dist/js/dashboard.js.map
vendored
2
dist/js/dashboard.js.map
vendored
File diff suppressed because one or more lines are too long
@ -718,6 +718,7 @@ page.getUploads = (params = {}) => {
|
|||||||
page.checkboxes[page.currentView] = table.querySelectorAll('.checkbox[data-action="select"]')
|
page.checkboxes[page.currentView] = table.querySelectorAll('.checkbox[data-action="select"]')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
const allAlbums = params.all && params.filters && params.filters.includes('albumid:')
|
||||||
page.dom.innerHTML = `
|
page.dom.innerHTML = `
|
||||||
${pagination}
|
${pagination}
|
||||||
${extraControls}
|
${extraControls}
|
||||||
@ -729,6 +730,7 @@ page.getUploads = (params = {}) => {
|
|||||||
<th><input id="selectAll" class="checkbox" type="checkbox" title="Select all" data-action="select-all"></th>
|
<th><input id="selectAll" class="checkbox" type="checkbox" title="Select all" data-action="select-all"></th>
|
||||||
<th>File name</th>
|
<th>File name</th>
|
||||||
${params.album === undefined ? `<th>${params.all ? 'User' : 'Album'}</th>` : ''}
|
${params.album === undefined ? `<th>${params.all ? 'User' : 'Album'}</th>` : ''}
|
||||||
|
${allAlbums ? '<th>Album</th>' : ''}
|
||||||
<th>Size</th>
|
<th>Size</th>
|
||||||
${params.all ? '<th>IP</th>' : ''}
|
${params.all ? '<th>IP</th>' : ''}
|
||||||
<th>Date</th>
|
<th>Date</th>
|
||||||
@ -755,6 +757,7 @@ page.getUploads = (params = {}) => {
|
|||||||
<td class="controls"><input type="checkbox" class="checkbox" title="Select" data-index="${i}" data-action="select"${upload.selected ? ' checked' : ''}></td>
|
<td class="controls"><input type="checkbox" class="checkbox" title="Select" data-index="${i}" data-action="select"${upload.selected ? ' checked' : ''}></td>
|
||||||
<th><a href="${upload.file}" target="_blank" title="${upload.file}">${upload.name}</a></th>
|
<th><a href="${upload.file}" target="_blank" title="${upload.file}">${upload.name}</a></th>
|
||||||
${params.album === undefined ? `<th>${upload.appendix}</th>` : ''}
|
${params.album === undefined ? `<th>${upload.appendix}</th>` : ''}
|
||||||
|
${allAlbums ? `<th>${files[i].albumid ? (albums[files[i].albumid] || '') : ''}</th>` : ''}
|
||||||
<td>${upload.prettyBytes}</td>
|
<td>${upload.prettyBytes}</td>
|
||||||
${params.all ? `<td>${upload.ip || ''}</td>` : ''}
|
${params.all ? `<td>${upload.ip || ''}</td>` : ''}
|
||||||
<td>${upload.prettyDate}</td>
|
<td>${upload.prettyDate}</td>
|
||||||
@ -1021,7 +1024,17 @@ page.uploadFiltersHelp = element => {
|
|||||||
|
|
||||||
To exclude certain users/ips while still listing every other uploads, add negation sign (<code>-</code>) before the keys.
|
To exclude certain users/ips while still listing every other uploads, add negation sign (<code>-</code>) before the keys.
|
||||||
Negation sign can also be used to exclude the special cases mentioned above (i.e. <code>-user:-</code> or <code>-ip:-</code>).
|
Negation sign can also be used to exclude the special cases mentioned above (i.e. <code>-user:-</code> or <code>-ip:-</code>).
|
||||||
` : ''}
|
|
||||||
|
If you know the ID of a user's album, you can list its uploads with <b>albumid</b> key.
|
||||||
|
Negation sign works for this key as well.
|
||||||
|
` : `
|
||||||
|
There is only 1 filter key, namely <b>albumid</b>.
|
||||||
|
This key can be specified more than once.
|
||||||
|
Special case such as uploads with no albums, use <code>albumid:-</code>.
|
||||||
|
|
||||||
|
To exclude certain albums while still listing every other uploads, add negation sign (<code>-</code>) before the keys.
|
||||||
|
Negation sign can also be used to exclude the special case mentioned above (i.e. <code>-albumid:-</code>).
|
||||||
|
`}
|
||||||
There are 2 range keys: <b>date</b> (upload date) and <b>expiry</b> (expiry date).
|
There are 2 range keys: <b>date</b> (upload date) and <b>expiry</b> (expiry date).
|
||||||
Their format is: <code>YYYY/MM/DD HH:MM:SS-YYYY/MM/DD HH:MM:SS</code> ("from" date and "to" date respectively).
|
Their format is: <code>YYYY/MM/DD HH:MM:SS-YYYY/MM/DD HH:MM:SS</code> ("from" date and "to" date respectively).
|
||||||
You may specify only one of the dates.
|
You may specify only one of the dates.
|
||||||
@ -1059,7 +1072,11 @@ page.uploadFiltersHelp = element => {
|
|||||||
<code>-user:demo -user:"John Doe"</code>
|
<code>-user:demo -user:"John Doe"</code>
|
||||||
- Uploads from IP "127.0.0.1" AND which file names match "*.rar" OR "*.zip":
|
- Uploads from IP "127.0.0.1" AND which file names match "*.rar" OR "*.zip":
|
||||||
<code>ip:127.0.0.1 *.rar *.zip</code>
|
<code>ip:127.0.0.1 *.rar *.zip</code>
|
||||||
` : ''}- Uploads uploaded since "1 June 2019 00:00:00":
|
` : ''}- Uploads without albums:
|
||||||
|
<code>albumid:-</code>
|
||||||
|
- ALL uploads, but NOT the ones from album with ID 69:
|
||||||
|
<code>-albumid:69</code>
|
||||||
|
- Uploads uploaded since "1 June 2019 00:00:00":
|
||||||
<code>date:2019/06</code>
|
<code>date:2019/06</code>
|
||||||
- Uploads uploaded between "7 April 2020 12:00:00" and "7 April 2020 23:59:59":
|
- Uploads uploaded between "7 April 2020 12:00:00" and "7 April 2020 23:59:59":
|
||||||
<code>date:2020/04/07 12-2020/04/07 23:59:59</code>
|
<code>date:2020/04/07 12-2020/04/07 23:59:59</code>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"1": "1588448172",
|
"1": "1588451242",
|
||||||
"2": "1581416390",
|
"2": "1581416390",
|
||||||
"3": "1581416390",
|
"3": "1581416390",
|
||||||
"4": "1581416390",
|
"4": "1581416390",
|
||||||
|
Loading…
Reference in New Issue
Block a user