From a69711d838bc98bc1d04aa6ee751da8c6a5d1eb3 Mon Sep 17 00:00:00 2001 From: HF Date: Mon, 22 Jun 2020 20:23:55 +0200 Subject: [PATCH] add protection or rectangles without image to admintools --- src/components/Admintools.jsx | 144 +++++++++++++++++++++++++++++++++- src/core/Image.js | 3 + src/routes/admintools.js | 136 +++++++++++++++++++++++++++++--- 3 files changed, 268 insertions(+), 15 deletions(-) diff --git a/src/components/Admintools.jsx b/src/components/Admintools.jsx index 465ae5c..a052fb0 100644 --- a/src/components/Admintools.jsx +++ b/src/components/Admintools.jsx @@ -9,8 +9,13 @@ import { connect } from 'react-redux'; import type { State } from '../reducers'; +const keptState = { + coords: null, + tlcoords: null, + brcoords: null, +}; -async function submitAction( +async function submitImageAction( action, canvas, coords, @@ -32,6 +37,26 @@ async function submitAction( callback(await resp.text()); } +async function submitProtAction( + action, + canvas, + tlcoords, + brcoords, + callback, +) { + const data = new FormData(); + data.append('protaction', action); + data.append('canvasid', canvas); + data.append('ulcoor', tlcoords); + data.append('brcoor', brcoords); + const resp = await fetch('./admintools', { + credentials: 'include', + method: 'POST', + body: data, + }); + callback(await resp.text()); +} + async function submitIPAction( action, callback, @@ -56,8 +81,11 @@ function Admintools({ const [selectedCanvas, selectCanvas] = useState(canvasId); const [imageAction, selectImageAction] = useState('build'); const [iPAction, selectIPAction] = useState('ban'); + const [protAction, selectProtAction] = useState('protect'); + const [coords, selectCoords] = useState(keptState.coords); + const [tlcoords, selectTLCoords] = useState(keptState.tlcoords); + const [brcoords, selectBRCoords] = useState(keptState.brcoords); const [resp, setResp] = useState(null); - const [coords, selectCoords] = useState('X_Y'); const [submitting, setSubmitting] = useState(false); let descAction; @@ -156,8 +184,11 @@ function Admintools({ maxWidth: '15em', }} type="text" + placeholder="X_Y" onChange={(evt) => { - selectCoords(evt.target.value.trim()); + const co = evt.target.value.trim(); + selectCoords(co); + keptState.coords = co; }} />

@@ -168,7 +199,7 @@ function Admintools({ return; } setSubmitting(true); - submitAction( + submitImageAction( imageAction, selectedCanvas, coords, @@ -181,6 +212,111 @@ function Admintools({ > {(submitting) ? '...' : 'Submit'} + +
+
+

Pixel Protection

+

+ Set protection of areas  + (if you need finer grained control,  + use protect with image upload and alpha layers) +

+

Choose Canvas:  + +

+ +

+ Top-left corner (X_Y):  + { + const co = evt.target.value.trim(); + selectTLCoords(co); + keptState.tlcoords = co; + }} + /> +

+

+ Bottom-right corner (X_Y):  + { + const co = evt.target.value.trim(); + selectBRCoords(co); + keptState.brcoords = co; + }} + /> +

+ +

IP Actions

diff --git a/src/core/Image.js b/src/core/Image.js index 27de724..79ef920 100644 --- a/src/core/Image.js +++ b/src/core/Image.js @@ -200,6 +200,7 @@ export async function protectCanvasArea( y + height - 1, ); + let totalPxlCnt = 0; let chunk; for (let cx = ucx; cx <= lcx; cx += 1) { for (let cy = ucy; cy <= lcy; cy += 1) { @@ -234,10 +235,12 @@ export async function protectCanvasArea( if (ret) { // eslint-disable-next-line max-len logger.info(`Set protection for ${pxlCnt} pixels in chunk ${cx}, ${cy}.`); + totalPxlCnt += pxlCnt; } } chunk = null; } } logger.info('Setting protection for area done.'); + return totalPxlCnt; } diff --git a/src/routes/admintools.js b/src/routes/admintools.js index f61b50e..775f1d6 100644 --- a/src/routes/admintools.js +++ b/src/routes/admintools.js @@ -25,7 +25,10 @@ import { Blacklist, Whitelist } from '../data/models'; import { MINUTE } from '../core/constants'; // eslint-disable-next-line import/no-unresolved import canvases from './canvases.json'; -import { imageABGR2Canvas } from '../core/Image'; +import { + imageABGR2Canvas, + protectCanvasArea, +} from '../core/Image'; const router = express.Router(); @@ -147,7 +150,7 @@ async function executeIPAction(action: string, ips: string): boolean { * @param action what to do with the image * @param file imagefile * @param coords coord sin X_Y format - * @param canvasid numerical canvas id + * @param canvasid numerical canvas id as string * @return [ret, msg] http status code and message */ async function executeImageAction( @@ -156,12 +159,21 @@ async function executeImageAction( coords: string, canvasid: string, ) { + if (!coords) { + return [403, 'Coordinates not defined']; + } + if (!canvasid) { + return [403, 'canvasid not defined']; + } + const splitCoords = coords.trim().split('_'); if (splitCoords.length !== 2) { return [403, 'Invalid Coordinate Format']; } const [x, y] = splitCoords.map((z) => Math.floor(Number(z))); + const canvas = canvases[canvasid]; + let error = null; if (Number.isNaN(x)) { error = 'x is not a valid number'; @@ -169,21 +181,15 @@ async function executeImageAction( error = 'y is not a valid number'; } else if (!action) { error = 'No imageaction given'; - } else if (!canvasid) { - error = 'No canvas specified'; - } else if (!canvases[canvasid]) { + } else if (!canvas) { error = 'Invalid canvas selected'; + } else if (canvas.v) { + error = 'Can not upload Image to 3D canvas'; } if (error !== null) { return [403, error]; } - const canvas = canvases[canvasid]; - - if (canvas.v) { - return [403, 'Can not upload Image to 3D canvas']; - } - const canvasMaxXY = canvas.size / 2; const canvasMinXY = -canvasMaxXY; if (x < canvasMinXY || y < canvasMinXY @@ -208,6 +214,8 @@ async function executeImageAction( wipe, protect, ); + // eslint-disable-next-line max-len + logger.info(`ADMINTOOLS: Loaded image wth ${pxlCount} pixels to ${x}/${y}`); return [ 200, `Successfully loaded image wth ${pxlCount} pixels to ${x}/${y}`, @@ -217,6 +225,100 @@ async function executeImageAction( } } +/* + * Execute actions for protecting areas + * @param action what to do + * @param ulcoor coords of upper-left corner in X_Y format + * @param brcoord coords of bottom-right corner in X_Y format + * @param canvasid numerical canvas id as string + * @return [ret, msg] http status code and message + */ +async function executeProtAction( + action: string, + ulcoor: string, + brcoor: string, + canvasid: number, +) { + if (!ulcoor || !brcoor) { + return [403, 'Not all coordinates defined']; + } + if (!canvasid) { + return [403, 'canvasid not defined']; + } + + let splitCoords = ulcoor.trim().split('_'); + if (splitCoords.length !== 2) { + return [403, 'Invalid Coordinate Format for top-left corner']; + } + const [x, y] = splitCoords.map((z) => Math.floor(Number(z))); + splitCoords = brcoor.trim().split('_'); + if (splitCoords.length !== 2) { + return [403, 'Invalid Coordinate Format for bottom-right corner']; + } + const [u, v] = splitCoords.map((z) => Math.floor(Number(z))); + + const canvas = canvases[canvasid]; + + let error = null; + if (Number.isNaN(x)) { + error = 'x of top-left corner is not a valid number'; + } else if (Number.isNaN(y)) { + error = 'y of top-left corner is not a valid number'; + } else if (Number.isNaN(u)) { + error = 'x of bottom-right corner is not a valid number'; + } else if (Number.isNaN(v)) { + error = 'y of bottom-right corner is not a valid number'; + } else if (u < x || v < y) { + error = 'Corner coordinates are alligned wrong'; + } else if (!action) { + error = 'No imageaction given'; + } else if (!canvas) { + error = 'Invalid canvas selected'; + } else if (!canvases[canvasid]) { + error = 'Invalid canvas selected'; + } else if (action !== 'protect' && action !== 'unprotect') { + error = 'Invalid action (must be protect or unprotect)'; + } + if (error !== null) { + return [403, error]; + } + + const canvasMaxXY = canvas.size / 2; + const canvasMinXY = -canvasMaxXY; + if (x < canvasMinXY || y < canvasMinXY + || x >= canvasMaxXY || y >= canvasMaxXY) { + return [403, 'Coordinates of top-left corner are outside of canvas']; + } + if (u < canvasMinXY || v < canvasMinXY + || u >= canvasMaxXY || v >= canvasMaxXY) { + return [403, 'Coordinates of bottom-right corner are outside of canvas']; + } + + const width = u - x + 1; + const height = v - y + 1; + const protect = action === 'protect'; + const pxlCount = await protectCanvasArea( + canvasid, + x, + y, + width, + height, + protect, + ); + logger.info( + // eslint-disable-next-line max-len + `ADMINTOOLS: Set protect to ${protect} for ${pxlCount} pixels at ${x} / ${y} with dimension ${width}x${height}`, + ); + return [ + 200, + (protect) + // eslint-disable-next-line max-len + ? `Successfully protected ${pxlCount} pixels at ${x} / ${y} with dimension ${width}x${height}` + // eslint-disable-next-line max-len + : `Soccessfully unprotected ${pxlCount} pixels at ${x} / ${y} with dimension ${width}x${height}`, + ]; +} + /* * Check for POST parameters, @@ -237,6 +339,18 @@ router.post('/', upload.single('image'), async (req, res, next) => { const ret = await executeIPAction(req.body.ipaction, req.body.ip); res.status(200).send(ret); return; + } if (req.body.protaction) { + const { + protaction, ulcoor, brcoor, canvasid, + } = req.body; + const [ret, msg] = await executeProtAction( + protaction, + ulcoor, + brcoor, + canvasid, + ); + res.status(ret).send(msg); + return; } next();