add protection or rectangles without image to admintools
This commit is contained in:
parent
1d081991ba
commit
a69711d838
|
@ -9,8 +9,13 @@ import { connect } from 'react-redux';
|
||||||
|
|
||||||
import type { State } from '../reducers';
|
import type { State } from '../reducers';
|
||||||
|
|
||||||
|
const keptState = {
|
||||||
|
coords: null,
|
||||||
|
tlcoords: null,
|
||||||
|
brcoords: null,
|
||||||
|
};
|
||||||
|
|
||||||
async function submitAction(
|
async function submitImageAction(
|
||||||
action,
|
action,
|
||||||
canvas,
|
canvas,
|
||||||
coords,
|
coords,
|
||||||
|
@ -32,6 +37,26 @@ async function submitAction(
|
||||||
callback(await resp.text());
|
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(
|
async function submitIPAction(
|
||||||
action,
|
action,
|
||||||
callback,
|
callback,
|
||||||
|
@ -56,8 +81,11 @@ function Admintools({
|
||||||
const [selectedCanvas, selectCanvas] = useState(canvasId);
|
const [selectedCanvas, selectCanvas] = useState(canvasId);
|
||||||
const [imageAction, selectImageAction] = useState('build');
|
const [imageAction, selectImageAction] = useState('build');
|
||||||
const [iPAction, selectIPAction] = useState('ban');
|
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 [resp, setResp] = useState(null);
|
||||||
const [coords, selectCoords] = useState('X_Y');
|
|
||||||
const [submitting, setSubmitting] = useState(false);
|
const [submitting, setSubmitting] = useState(false);
|
||||||
|
|
||||||
let descAction;
|
let descAction;
|
||||||
|
@ -156,8 +184,11 @@ function Admintools({
|
||||||
maxWidth: '15em',
|
maxWidth: '15em',
|
||||||
}}
|
}}
|
||||||
type="text"
|
type="text"
|
||||||
|
placeholder="X_Y"
|
||||||
onChange={(evt) => {
|
onChange={(evt) => {
|
||||||
selectCoords(evt.target.value.trim());
|
const co = evt.target.value.trim();
|
||||||
|
selectCoords(co);
|
||||||
|
keptState.coords = co;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
|
@ -168,7 +199,7 @@ function Admintools({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
submitAction(
|
submitImageAction(
|
||||||
imageAction,
|
imageAction,
|
||||||
selectedCanvas,
|
selectedCanvas,
|
||||||
coords,
|
coords,
|
||||||
|
@ -181,6 +212,111 @@ function Admintools({
|
||||||
>
|
>
|
||||||
{(submitting) ? '...' : 'Submit'}
|
{(submitting) ? '...' : 'Submit'}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<div className="modaldivider" />
|
||||||
|
<h3 className="modaltitle">Pixel Protection</h3>
|
||||||
|
<p className="modalcotext">
|
||||||
|
Set protection of areas
|
||||||
|
(if you need finer grained control,
|
||||||
|
use protect with image upload and alpha layers)
|
||||||
|
</p>
|
||||||
|
<p className="modalcotext">Choose Canvas:
|
||||||
|
<select
|
||||||
|
onChange={(e) => {
|
||||||
|
const sel = e.target;
|
||||||
|
selectCanvas(sel.options[sel.selectedIndex].value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
Object.keys(canvases).map((canvas) => ((canvases[canvas].v)
|
||||||
|
? null
|
||||||
|
: (
|
||||||
|
<option
|
||||||
|
selected={canvas === selectedCanvas}
|
||||||
|
value={canvas}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
canvases[canvas].title
|
||||||
|
}
|
||||||
|
</option>
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</p>
|
||||||
|
<select
|
||||||
|
onChange={(e) => {
|
||||||
|
const sel = e.target;
|
||||||
|
selectProtAction(sel.options[sel.selectedIndex].value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{['protect', 'unprotect'].map((opt) => (
|
||||||
|
<option
|
||||||
|
value={opt}
|
||||||
|
selected={protAction === opt}
|
||||||
|
>
|
||||||
|
{opt}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
<p className="modalcotext">
|
||||||
|
Top-left corner (X_Y):
|
||||||
|
<input
|
||||||
|
value={tlcoords}
|
||||||
|
style={{
|
||||||
|
display: 'inline-block',
|
||||||
|
width: '100%',
|
||||||
|
maxWidth: '15em',
|
||||||
|
}}
|
||||||
|
type="text"
|
||||||
|
placeholder="X_Y"
|
||||||
|
onChange={(evt) => {
|
||||||
|
const co = evt.target.value.trim();
|
||||||
|
selectTLCoords(co);
|
||||||
|
keptState.tlcoords = co;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<p className="modalcotext">
|
||||||
|
Bottom-right corner (X_Y):
|
||||||
|
<input
|
||||||
|
value={brcoords}
|
||||||
|
style={{
|
||||||
|
display: 'inline-block',
|
||||||
|
width: '100%',
|
||||||
|
maxWidth: '15em',
|
||||||
|
}}
|
||||||
|
type="text"
|
||||||
|
placeholder="X_Y"
|
||||||
|
onChange={(evt) => {
|
||||||
|
const co = evt.target.value.trim();
|
||||||
|
selectBRCoords(co);
|
||||||
|
keptState.brcoords = co;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
if (submitting) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setSubmitting(true);
|
||||||
|
submitProtAction(
|
||||||
|
protAction,
|
||||||
|
selectedCanvas,
|
||||||
|
tlcoords,
|
||||||
|
brcoords,
|
||||||
|
(ret) => {
|
||||||
|
setSubmitting(false);
|
||||||
|
setResp(ret);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{(submitting) ? '...' : 'Submit'}
|
||||||
|
</button>
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
<div className="modaldivider" />
|
<div className="modaldivider" />
|
||||||
<h3 className="modaltitle">IP Actions</h3>
|
<h3 className="modaltitle">IP Actions</h3>
|
||||||
|
|
|
@ -200,6 +200,7 @@ export async function protectCanvasArea(
|
||||||
y + height - 1,
|
y + height - 1,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let totalPxlCnt = 0;
|
||||||
let chunk;
|
let chunk;
|
||||||
for (let cx = ucx; cx <= lcx; cx += 1) {
|
for (let cx = ucx; cx <= lcx; cx += 1) {
|
||||||
for (let cy = ucy; cy <= lcy; cy += 1) {
|
for (let cy = ucy; cy <= lcy; cy += 1) {
|
||||||
|
@ -234,10 +235,12 @@ export async function protectCanvasArea(
|
||||||
if (ret) {
|
if (ret) {
|
||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
logger.info(`Set protection for ${pxlCnt} pixels in chunk ${cx}, ${cy}.`);
|
logger.info(`Set protection for ${pxlCnt} pixels in chunk ${cx}, ${cy}.`);
|
||||||
|
totalPxlCnt += pxlCnt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chunk = null;
|
chunk = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.info('Setting protection for area done.');
|
logger.info('Setting protection for area done.');
|
||||||
|
return totalPxlCnt;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,10 @@ import { Blacklist, Whitelist } from '../data/models';
|
||||||
import { MINUTE } from '../core/constants';
|
import { MINUTE } from '../core/constants';
|
||||||
// eslint-disable-next-line import/no-unresolved
|
// eslint-disable-next-line import/no-unresolved
|
||||||
import canvases from './canvases.json';
|
import canvases from './canvases.json';
|
||||||
import { imageABGR2Canvas } from '../core/Image';
|
import {
|
||||||
|
imageABGR2Canvas,
|
||||||
|
protectCanvasArea,
|
||||||
|
} from '../core/Image';
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
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 action what to do with the image
|
||||||
* @param file imagefile
|
* @param file imagefile
|
||||||
* @param coords coord sin X_Y format
|
* @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
|
* @return [ret, msg] http status code and message
|
||||||
*/
|
*/
|
||||||
async function executeImageAction(
|
async function executeImageAction(
|
||||||
|
@ -156,12 +159,21 @@ async function executeImageAction(
|
||||||
coords: string,
|
coords: string,
|
||||||
canvasid: string,
|
canvasid: string,
|
||||||
) {
|
) {
|
||||||
|
if (!coords) {
|
||||||
|
return [403, 'Coordinates not defined'];
|
||||||
|
}
|
||||||
|
if (!canvasid) {
|
||||||
|
return [403, 'canvasid not defined'];
|
||||||
|
}
|
||||||
|
|
||||||
const splitCoords = coords.trim().split('_');
|
const splitCoords = coords.trim().split('_');
|
||||||
if (splitCoords.length !== 2) {
|
if (splitCoords.length !== 2) {
|
||||||
return [403, 'Invalid Coordinate Format'];
|
return [403, 'Invalid Coordinate Format'];
|
||||||
}
|
}
|
||||||
const [x, y] = splitCoords.map((z) => Math.floor(Number(z)));
|
const [x, y] = splitCoords.map((z) => Math.floor(Number(z)));
|
||||||
|
|
||||||
|
const canvas = canvases[canvasid];
|
||||||
|
|
||||||
let error = null;
|
let error = null;
|
||||||
if (Number.isNaN(x)) {
|
if (Number.isNaN(x)) {
|
||||||
error = 'x is not a valid number';
|
error = 'x is not a valid number';
|
||||||
|
@ -169,21 +181,15 @@ async function executeImageAction(
|
||||||
error = 'y is not a valid number';
|
error = 'y is not a valid number';
|
||||||
} else if (!action) {
|
} else if (!action) {
|
||||||
error = 'No imageaction given';
|
error = 'No imageaction given';
|
||||||
} else if (!canvasid) {
|
} else if (!canvas) {
|
||||||
error = 'No canvas specified';
|
|
||||||
} else if (!canvases[canvasid]) {
|
|
||||||
error = 'Invalid canvas selected';
|
error = 'Invalid canvas selected';
|
||||||
|
} else if (canvas.v) {
|
||||||
|
error = 'Can not upload Image to 3D canvas';
|
||||||
}
|
}
|
||||||
if (error !== null) {
|
if (error !== null) {
|
||||||
return [403, error];
|
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 canvasMaxXY = canvas.size / 2;
|
||||||
const canvasMinXY = -canvasMaxXY;
|
const canvasMinXY = -canvasMaxXY;
|
||||||
if (x < canvasMinXY || y < canvasMinXY
|
if (x < canvasMinXY || y < canvasMinXY
|
||||||
|
@ -208,6 +214,8 @@ async function executeImageAction(
|
||||||
wipe, protect,
|
wipe, protect,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
logger.info(`ADMINTOOLS: Loaded image wth ${pxlCount} pixels to ${x}/${y}`);
|
||||||
return [
|
return [
|
||||||
200,
|
200,
|
||||||
`Successfully loaded image wth ${pxlCount} pixels to ${x}/${y}`,
|
`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,
|
* 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);
|
const ret = await executeIPAction(req.body.ipaction, req.body.ip);
|
||||||
res.status(200).send(ret);
|
res.status(200).send(ret);
|
||||||
return;
|
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();
|
next();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user