Substitute illegal attachments with redacted thumbnail
This commit is contained in:
parent
f2bdf5a279
commit
30fecd588f
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
231
script.js
231
script.js
|
@ -298,19 +298,21 @@ function parseRangeHeader(rangeHeader) {
|
||||||
|
|
||||||
function resolveResponse(resolve, reject) {
|
function resolveResponse(resolve, reject) {
|
||||||
return function(e) {
|
return function(e) {
|
||||||
var status = e.target.getResponseHeader("Status");
|
const status = e.target.getResponseHeader("Status");
|
||||||
|
|
||||||
if (status != null) {
|
if (status != null) {
|
||||||
var status_code = Number(status.split(" ")[0]);
|
const status_code = Number(status.split(" ")[0]);
|
||||||
|
|
||||||
if (status_code >= 200 && status_code < 300) {
|
if (status_code >= 200 && status_code < 300) {
|
||||||
resolve(e.target.responseText);
|
resolve(e.target.responseText);
|
||||||
} else {
|
} else {
|
||||||
reject(new Error('API responded with ' + status));
|
reject(new Error('API responded with ' + status + ". " + e.target.responseText));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (e.target.status >= 200 && e.target.status < 300) {
|
if (e.target.status >= 200 && e.target.status < 300) {
|
||||||
return resolve(e.target);
|
return resolve(e.target);
|
||||||
} else {
|
} else {
|
||||||
reject(new Error('API responded with ' + e.target.status));
|
reject(new Error('API responded with ' + e.target.status + ". " + e.target.responseText));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -341,6 +343,31 @@ function get(url, xhr_req_follower, headers) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function post(url, body, xhr_req_follower, headers) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
var req = new XMLHttpRequest();
|
||||||
|
xhr_req_follower(req);
|
||||||
|
req.onload = resolveResponse(resolve, reject);
|
||||||
|
req.onerror = reject;
|
||||||
|
req.open('POST', url);
|
||||||
|
|
||||||
|
if (headers) {
|
||||||
|
Object.entries(headers)
|
||||||
|
.forEach(function([header_name, header_value]) {
|
||||||
|
req.setRequestHeader(header_name, header_value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
req.setRequestHeader('Content-Type', 'application/json');
|
||||||
|
|
||||||
|
if (body) {
|
||||||
|
req.send(JSON.stringify(body));
|
||||||
|
} else {
|
||||||
|
req.send();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Given a BigInt that is packed bytes, unpack the bytes into an ArrayBuffer
|
// Given a BigInt that is packed bytes, unpack the bytes into an ArrayBuffer
|
||||||
function unpackBytes(bigint) {
|
function unpackBytes(bigint) {
|
||||||
const buffer = new ArrayBuffer(8);
|
const buffer = new ArrayBuffer(8);
|
||||||
|
@ -384,100 +411,6 @@ function hammingDistance(buffer1, buffer2) {
|
||||||
return distance;
|
return distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseFilePath(s) {
|
|
||||||
return JSON.parse(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
function FileSize(s) {
|
|
||||||
this.filesize = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
function tree(rows) {
|
|
||||||
var c = {};
|
|
||||||
|
|
||||||
for (var row of rows) {
|
|
||||||
var path = parseFilePath(row.path);
|
|
||||||
var tree = c;
|
|
||||||
var previous = c;
|
|
||||||
var filename = 'NOPATH';
|
|
||||||
|
|
||||||
for (var p of path) {
|
|
||||||
previous = tree;
|
|
||||||
|
|
||||||
if (p in tree) {
|
|
||||||
tree = tree[p];
|
|
||||||
} else {
|
|
||||||
var newtree = {};
|
|
||||||
tree[p] = newtree;
|
|
||||||
tree = newtree;
|
|
||||||
}
|
|
||||||
|
|
||||||
filename = p;
|
|
||||||
}
|
|
||||||
|
|
||||||
previous[filename] = new FileSize(row.filesize);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(c);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderTree(rows) {
|
|
||||||
var list_elem = ul();
|
|
||||||
|
|
||||||
function draw(list_elem, t) {
|
|
||||||
Object.entries(t)
|
|
||||||
.forEach(function([key, val]) {
|
|
||||||
if (val instanceof FileSize) {
|
|
||||||
var contents = div(span(text(key)));
|
|
||||||
contents.appendChild(italic(text(val.filesize)));
|
|
||||||
list_elem.appendChild(contents);
|
|
||||||
} else {
|
|
||||||
var new_list = ul();
|
|
||||||
var elem = li(text(key));
|
|
||||||
elem.appendChild(new_list);
|
|
||||||
list_elem.appendChild(elem);
|
|
||||||
draw(new_list, val);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
draw(list_elem, tree(rows));
|
|
||||||
|
|
||||||
return list_elem;
|
|
||||||
}
|
|
||||||
|
|
||||||
function assembleTable(rows) {
|
|
||||||
var t = document.createElement('table');
|
|
||||||
|
|
||||||
rows.forEach(function(r) {
|
|
||||||
var row = t.insertRow();
|
|
||||||
|
|
||||||
TableHeadings.forEach(function(header) {
|
|
||||||
var cell = row.insertCell();
|
|
||||||
|
|
||||||
cell.appendChild(header[1](r));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
var thead = t.createTHead().insertRow();
|
|
||||||
|
|
||||||
TableHeadingNames.forEach(function(header) {
|
|
||||||
var th = document.createElement('th');
|
|
||||||
|
|
||||||
th.appendChild(text(header));
|
|
||||||
thead.appendChild(th);
|
|
||||||
});
|
|
||||||
|
|
||||||
var countElem = div(text(rows.length + ' rows'))
|
|
||||||
|
|
||||||
var wrapper = div();
|
|
||||||
wrapper.appendChild(t);
|
|
||||||
wrapper.appendChild(countElem);
|
|
||||||
|
|
||||||
return wrapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
function text(s) {
|
function text(s) {
|
||||||
return document.createTextNode(s);
|
return document.createTextNode(s);
|
||||||
}
|
}
|
||||||
|
@ -527,20 +460,31 @@ function mkSpamImgElement(img_description) {
|
||||||
var mime = img_description.mimetype;
|
var mime = img_description.mimetype;
|
||||||
var thumb_url;
|
var thumb_url;
|
||||||
|
|
||||||
if (mime == "audio/mpeg") {
|
var illegal = img_description.illegal;
|
||||||
|
console.log('img_description.illegal', img_description.illegal);
|
||||||
|
|
||||||
|
if (illegal) {
|
||||||
|
thumb_url = `/bin/?path=${GlobalVars.settings.redacted_thumbnail_path}&mimetype=image/jpeg`
|
||||||
|
} else if (mime == "audio/mpeg") {
|
||||||
thumb_url = `/bin/?path=${GlobalVars.settings.audio_mpeg_thumbnail_path}&mimetype=image/jpeg`
|
thumb_url = `/bin/?path=${GlobalVars.settings.audio_mpeg_thumbnail_path}&mimetype=image/jpeg`
|
||||||
} else {
|
} else {
|
||||||
thumb_url = `/bin/?path=${GlobalVars.settings.content_directory}/${img_description.md5_hash}_thumbnail.jpg&mimetype=image/jpeg`
|
thumb_url = `/bin/?path=${GlobalVars.settings.content_directory}/${img_description.md5_hash}_thumbnail.jpg&mimetype=image/jpeg`
|
||||||
}
|
}
|
||||||
|
|
||||||
var image_url = `/bin/?path=${GlobalVars.settings.content_directory}/${img_description.md5_hash}.attachment&mimetype=${mime}`
|
|
||||||
img_elem.setAttribute('src', thumb_url);
|
img_elem.setAttribute('src', thumb_url);
|
||||||
img_elem.setAttribute('decoding', 'async');
|
img_elem.setAttribute('decoding', 'async');
|
||||||
img_elem.setAttribute('loading', 'lazy');
|
img_elem.setAttribute('loading', 'lazy');
|
||||||
|
|
||||||
var a_elem = document.createElement('a');
|
var a_elem;
|
||||||
a_elem.setAttribute('href', image_url);
|
|
||||||
a_elem.appendChild(img_elem);
|
if (!illegal) {
|
||||||
|
var image_url = `/bin/?path=${GlobalVars.settings.content_directory}/${img_description.md5_hash}.attachment&mimetype=${mime}`
|
||||||
|
a_elem = document.createElement('a');
|
||||||
|
a_elem.setAttribute('href', image_url);
|
||||||
|
a_elem.appendChild(img_elem);
|
||||||
|
} else {
|
||||||
|
a_elem = div(img_elem);
|
||||||
|
}
|
||||||
|
|
||||||
var img_container_elem = div(a_elem);
|
var img_container_elem = div(a_elem);
|
||||||
img_container_elem.classList.add('post--image_container');
|
img_container_elem.classList.add('post--image_container');
|
||||||
|
@ -570,6 +514,49 @@ function linkToBoard(website_name, board_name, thread_id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function attachmentCanBeMarkedIllegal(attachment) {
|
||||||
|
return attachment.phash != null && !attachment.illegal;
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldDisplayMarkIllegalButton(post) {
|
||||||
|
let result = false;
|
||||||
|
|
||||||
|
for (let attachment of (post.known_spam_post_attachment || [])) {
|
||||||
|
result = result || attachmentCanBeMarkedIllegal(attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isIllegal(post) {
|
||||||
|
let result = false;
|
||||||
|
|
||||||
|
for (let attachment of (post.known_spam_post_attachment || [])) {
|
||||||
|
result = result || attachment.illegal;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onClickMarkIllegal(phashes, e) {
|
||||||
|
console.log('CLICK', phashes);
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const url = new URL('/illegal', window.location.origin);
|
||||||
|
phashes.forEach(function(p) {
|
||||||
|
console.log('onClickMarkIllegal', typeof p, p);
|
||||||
|
url.searchParams.append('phash', p);
|
||||||
|
});
|
||||||
|
|
||||||
|
await post(url.toString(), null, cancel)
|
||||||
|
.then(function() {
|
||||||
|
location.reload();
|
||||||
|
})
|
||||||
|
.catch(caught.bind(this, "Failed to mark post illegal because:"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function renderPostElem(post) {
|
function renderPostElem(post) {
|
||||||
const postContainer = div();
|
const postContainer = div();
|
||||||
postContainer.classList.add('post');
|
postContainer.classList.add('post');
|
||||||
|
@ -599,6 +586,34 @@ function renderPostElem(post) {
|
||||||
|
|
||||||
postHeader.appendChild(span(text((new Date(post.time_stamp).toUTCString()))));
|
postHeader.appendChild(span(text((new Date(post.time_stamp).toUTCString()))));
|
||||||
|
|
||||||
|
if (shouldDisplayMarkIllegalButton(post)) {
|
||||||
|
const mark_illegal = span()
|
||||||
|
mark_illegal.classList.add('post--mark_illegal');
|
||||||
|
const mark_illegal_a = document.createElement('a');
|
||||||
|
|
||||||
|
mark_illegal_a.appendChild(text('Mark Illegal'));
|
||||||
|
|
||||||
|
mark_illegal_a.setAttribute('href', '#');
|
||||||
|
mark_illegal_a.setAttribute('title', 'Permanently delete associated pictures and thumbnails but keep metadata for future matching');
|
||||||
|
mark_illegal.appendChild(text('['));
|
||||||
|
mark_illegal.appendChild(mark_illegal_a);
|
||||||
|
mark_illegal.appendChild(text(']'));
|
||||||
|
|
||||||
|
const phashes = (post.known_spam_post_attachment || [])
|
||||||
|
.map(function(p) {
|
||||||
|
return bufferToHex(unpackBytes(BigInt(p.phash)));
|
||||||
|
});
|
||||||
|
|
||||||
|
mark_illegal_a.addEventListener('click',
|
||||||
|
onClickMarkIllegal.bind(this, phashes));
|
||||||
|
|
||||||
|
postHeader.appendChild(mark_illegal);
|
||||||
|
} else if (isIllegal(post)) {
|
||||||
|
const mark_illegal = span(text('illegal'))
|
||||||
|
mark_illegal.classList.add('post--is_illegal');
|
||||||
|
postHeader.appendChild(mark_illegal);
|
||||||
|
}
|
||||||
|
|
||||||
postContainer.appendChild(postHeader);
|
postContainer.appendChild(postHeader);
|
||||||
|
|
||||||
const postElem = div();
|
const postElem = div();
|
||||||
|
@ -767,9 +782,13 @@ function loadKnownSpamPosts(params) {
|
||||||
json.forEach(function (post) {
|
json.forEach(function (post) {
|
||||||
var postElem = renderOverviewPost(post);
|
var postElem = renderOverviewPost(post);
|
||||||
|
|
||||||
postElem.addEventListener('click', function() {
|
postElem.addEventListener('click',
|
||||||
changeUrl('/spam_post/' + post.text_post_id, new URLSearchParams(), true);
|
changeUrl.bind(
|
||||||
});
|
this,
|
||||||
|
'/spam_post/' + post.text_post_id,
|
||||||
|
new URLSearchParams(),
|
||||||
|
true
|
||||||
|
));
|
||||||
|
|
||||||
mainElem.appendChild(postElem);
|
mainElem.appendChild(postElem);
|
||||||
});
|
});
|
||||||
|
|
14
style.css
14
style.css
|
@ -64,6 +64,20 @@ header {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.post--header span.post--mark_illegal {
|
||||||
|
flex-basis: fit-content;
|
||||||
|
flex-grow: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post--header span.post--is_illegal {
|
||||||
|
flex-basis: fit-content;
|
||||||
|
flex-grow: 0;
|
||||||
|
color: orange;
|
||||||
|
font-weight: bold;
|
||||||
|
font-family: monospace;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
nav a {
|
nav a {
|
||||||
margin: 1rem;
|
margin: 1rem;
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
|
|
Loading…
Reference in New Issue