implement canvas freezing
This commit is contained in:
parent
93dc27b17a
commit
3dd4d7e0d0
|
@ -2,6 +2,7 @@ import { Button } from "@nextui-org/react";
|
|||
import { useAppContext } from "../../contexts/AppContext";
|
||||
import network from "../../lib/network";
|
||||
import { useEffect, useState } from "react";
|
||||
import { toast } from "react-toastify";
|
||||
|
||||
export const UndoButton = () => {
|
||||
const { undo, config } = useAppContext<true>();
|
||||
|
@ -34,7 +35,21 @@ export const UndoButton = () => {
|
|||
// ref-ify this?
|
||||
function execUndo() {
|
||||
network.socket.emitWithAck("undo").then((data) => {
|
||||
console.log("undo", data);
|
||||
if (data.success) {
|
||||
console.log("Undo pixel successful");
|
||||
} else {
|
||||
console.log("Undo pixel error", data);
|
||||
switch (data.error) {
|
||||
case "pixel_covered":
|
||||
toast.error("You cannot undo a covered pixel");
|
||||
break;
|
||||
case "unavailable":
|
||||
toast.error("You have no undo available");
|
||||
break;
|
||||
default:
|
||||
toast.error("Undo error: " + data.error);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ export interface ClientToServerEvents {
|
|||
ack: (
|
||||
_: PacketAck<
|
||||
Pixel,
|
||||
| "canvas_frozen"
|
||||
| "no_user"
|
||||
| "invalid_pixel"
|
||||
| "pixel_cooldown"
|
||||
|
@ -50,7 +51,12 @@ export interface ClientToServerEvents {
|
|||
) => void
|
||||
) => void;
|
||||
undo: (
|
||||
ack: (_: PacketAck<{}, "no_user" | "unavailable" | "pixel_covered">) => void
|
||||
ack: (
|
||||
_: PacketAck<
|
||||
{},
|
||||
"canvas_frozen" | "no_user" | "unavailable" | "pixel_covered"
|
||||
>
|
||||
) => void
|
||||
) => void;
|
||||
|
||||
subscribe: (topic: Subscription) => void;
|
||||
|
@ -141,6 +147,7 @@ export type PalleteColor = {
|
|||
|
||||
export type CanvasConfig = {
|
||||
size: [number, number];
|
||||
frozen: boolean;
|
||||
zoom: number;
|
||||
pixel: {
|
||||
maxStack: number;
|
||||
|
|
|
@ -136,6 +136,8 @@ Enum AuditLogAction {
|
|||
BAN_DELETE
|
||||
CANVAS_SIZE
|
||||
CANVAS_FILL
|
||||
CANVAS_FREEZE
|
||||
CANVAS_UNFREEZE
|
||||
}
|
||||
|
||||
Ref: Pixel.userId > User.sub
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
-- AlterEnum
|
||||
-- This migration adds more than one value to an enum.
|
||||
-- With PostgreSQL versions 11 and earlier, this is not possible
|
||||
-- in a single migration. This can be worked around by creating
|
||||
-- multiple migrations, each migration adding only one value to
|
||||
-- the enum.
|
||||
|
||||
|
||||
ALTER TYPE "AuditLogAction" ADD VALUE 'CANVAS_FREEZE';
|
||||
ALTER TYPE "AuditLogAction" ADD VALUE 'CANVAS_UNFREEZE';
|
|
@ -154,6 +154,8 @@ enum AuditLogAction {
|
|||
BAN_DELETE
|
||||
CANVAS_SIZE
|
||||
CANVAS_FILL
|
||||
CANVAS_FREEZE
|
||||
CANVAS_UNFREEZE
|
||||
}
|
||||
|
||||
model AuditLog {
|
||||
|
|
|
@ -96,6 +96,49 @@ app.post("/canvas/size", async (req, res) => {
|
|||
res.send({ success: true, auditLog });
|
||||
});
|
||||
|
||||
/**
|
||||
* Get canvas frozen status
|
||||
*/
|
||||
app.get("/canvas/freeze", async (req, res) => {
|
||||
res.send({ success: true, frozen: Canvas.frozen });
|
||||
});
|
||||
|
||||
/**
|
||||
* Freeze the canvas
|
||||
*
|
||||
* @header X-Audit
|
||||
*/
|
||||
app.post("/canvas/freeze", async (req, res) => {
|
||||
await Canvas.setFrozen(true);
|
||||
|
||||
const user = (await User.fromAuthSession(req.session.user!))!;
|
||||
const auditLog = AuditLog.Factory(user.sub)
|
||||
.doing("CANVAS_FREEZE")
|
||||
.reason(req.header("X-Audit") || null)
|
||||
.withComment(`Freezed the canvas`)
|
||||
.create();
|
||||
|
||||
res.send({ success: true, auditLog });
|
||||
});
|
||||
|
||||
/**
|
||||
* Unfreeze the canvas
|
||||
*
|
||||
* @header X-Audit
|
||||
*/
|
||||
app.delete("/canvas/freeze", async (req, res) => {
|
||||
await Canvas.setFrozen(false);
|
||||
|
||||
const user = (await User.fromAuthSession(req.session.user!))!;
|
||||
const auditLog = AuditLog.Factory(user.sub)
|
||||
.doing("CANVAS_UNFREEZE")
|
||||
.reason(req.header("X-Audit") || null)
|
||||
.withComment(`Un-Freezed the canvas`)
|
||||
.create();
|
||||
|
||||
res.send({ success: true, auditLog });
|
||||
});
|
||||
|
||||
app.put("/canvas/heatmap", async (req, res) => {
|
||||
try {
|
||||
await Canvas.generateHeatmap();
|
||||
|
|
|
@ -13,14 +13,17 @@ class Canvas {
|
|||
* Size of the canvas
|
||||
*/
|
||||
private canvasSize: [width: number, height: number];
|
||||
private isFrozen: boolean;
|
||||
|
||||
constructor() {
|
||||
this.canvasSize = [100, 100];
|
||||
this.isFrozen = false;
|
||||
}
|
||||
|
||||
getCanvasConfig(): CanvasConfig {
|
||||
return {
|
||||
size: this.canvasSize,
|
||||
frozen: this.isFrozen,
|
||||
zoom: 7,
|
||||
pixel: {
|
||||
cooldown: 10,
|
||||
|
@ -33,6 +36,34 @@ class Canvas {
|
|||
};
|
||||
}
|
||||
|
||||
get frozen() {
|
||||
return this.isFrozen;
|
||||
}
|
||||
|
||||
async setFrozen(frozen: boolean) {
|
||||
this.isFrozen = frozen;
|
||||
|
||||
await prisma.setting.upsert({
|
||||
where: { key: "canvas.frozen" },
|
||||
create: {
|
||||
key: "canvas.frozen",
|
||||
value: JSON.stringify(frozen),
|
||||
},
|
||||
update: {
|
||||
key: "canvas.frozen",
|
||||
value: JSON.stringify(frozen),
|
||||
},
|
||||
});
|
||||
|
||||
if (SocketServer.instance) {
|
||||
SocketServer.instance.broadcastConfig();
|
||||
} else {
|
||||
Logger.warn(
|
||||
"[Canvas#setFrozen] SocketServer is not instantiated, cannot broadcast config"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change size of the canvas
|
||||
*
|
||||
|
|
|
@ -26,6 +26,17 @@ export const loadSettings = async (frozen = false) => {
|
|||
Logger.warn("Setting canvas.size is not set, did you run init_settings?");
|
||||
}
|
||||
|
||||
// canvas frozen
|
||||
const canvasFrozen = await prisma.setting.findFirst({
|
||||
where: { key: "canvas.frozen" },
|
||||
});
|
||||
if (canvasFrozen) {
|
||||
const data = JSON.parse(canvasFrozen.value);
|
||||
Logger.info(`Canvas frozen loaded as ${data}`);
|
||||
|
||||
Canvas.setFrozen(data);
|
||||
}
|
||||
|
||||
Logger.info(
|
||||
"Settings loaded into memory, waiting for side effects to finish..."
|
||||
);
|
||||
|
|
|
@ -233,6 +233,11 @@ export class SocketServer {
|
|||
});
|
||||
|
||||
socket.on("place", async (pixel, bypassCooldown, ack) => {
|
||||
if (getClientConfig().canvas.frozen) {
|
||||
ack({ success: false, error: "canvas_frozen" });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
ack({ success: false, error: "no_user" });
|
||||
return;
|
||||
|
@ -317,6 +322,11 @@ export class SocketServer {
|
|||
});
|
||||
|
||||
socket.on("undo", async (ack) => {
|
||||
if (getClientConfig().canvas.frozen) {
|
||||
ack({ success: false, error: "canvas_frozen" });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
ack({ success: false, error: "no_user" });
|
||||
return;
|
||||
|
|
|
@ -14,6 +14,10 @@ async function main() {
|
|||
height: 100,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "canvas.frozen",
|
||||
defaultValue: false,
|
||||
},
|
||||
];
|
||||
|
||||
for (const setting of SETTINGS) {
|
||||
|
|
Loading…
Reference in New Issue