xd Merge branch 'main' into prod

This commit is contained in:
y-syo
2025-10-25 11:18:09 +02:00
7 changed files with 46 additions and 64 deletions

View File

@ -229,7 +229,7 @@ export default async function(fastify, options) {
return pMatchHistory(request, reply, fastify, getUserInfo, addMatch, incWinsPong, incLossesPong, incWinsTetris, incLossesTetris);
});
fastify.post('/users/:userId/avatar', { bodyLimit: 5242880, preHandler: [fastify.authenticate] }, async (request, reply) => {
return pAvatar(request, reply, fastify, getUserInfo, setAvatarId, postImage);
return pAvatar(request, reply, fastify, getUserInfo, getAvatarId, setAvatarId, deleteAvatarId, postImage, deleteImage);
});
fastify.post('/ping', { preHandler: [fastify.authenticate] }, async (request, reply) => {
return pPing(request, reply, fastify, setActivityTime);

View File

@ -5,7 +5,7 @@ import sharp from 'sharp';
* @param {import('fastify').FastifyReply} reply
* @param {import('fastify').FastifyInstance} fastify
*/
export async function pAvatar(request, reply, fastify, getUserInfo, setAvatarId, postImage) {
export async function pAvatar(request, reply, fastify, getUserInfo, getAvatarId, setAvatarId, deleteAvatarId, postImage, deleteImage) {
try {
const userId = request.params.userId;
if (request.user !== userId && request.user !== 'admin') {
@ -35,6 +35,12 @@ export async function pAvatar(request, reply, fastify, getUserInfo, setAvatarId,
const fileName = `avatar_${userId}.webp`;
const imageId = postImage.run(fileName, mimeType, webpBuffer);
const oldImageId = getAvatarId.get(userId);
if (oldImageId.avatarId !== -1) {
deleteImage.run(oldImageId.avatarId);
deleteAvatarId.run(userId);
}
setAvatarId.run(imageId.lastInsertRowid, userId);
return reply.code(200).send({ msg: "Avatar uploaded successfully" });

View File

@ -39,7 +39,7 @@
<div class="border-t-2 border-neutral-300 dark:border-neutral-800 sticky bottom-0">
<nav class="bg-neutral-200 dark:bg-neutral-900 shadow-md border-t-2 border-neutral-400 dark:border-neutral-700 flex justify-between h-12 items-center content-center space-x-6 font-[Kubasta]">
<div class="flex px-4 items-center content-center space-x-2">
<button id="profile-button" class="taskbar-button flex flex-row justify-center items-center"><img id="start-img" class="object-scale-down mr-2 h-5 w-5" src="https://api.kanel.ovh/id?id=65" /> start</button>
<button id="profile-button" class="taskbar-button flex flex-row justify-center items-center"><img id="start-img" class="mr-2 h-5 w-5" src="https://api.kanel.ovh/id?id=65" /> start</button>
<div class="text-neutral-700 dark:text-neutral-400">|</div>
<a target="_blank" class="taskbar-button" href="https://rusty.42angouleme.fr/">rusty</a>
<a target="_blank" class="taskbar-button" href="https://dn720004.ca.archive.org/0/items/2009-tetris-variant-concepts_202201/2009%20Tetris%20Design%20Guideline.pdf">tetris-guideline.pdf</a>

View File

@ -58,6 +58,18 @@
;
}
.red-button {
@apply shadow-2x1
bg-neutral-200 hover:bg-neutral-300 active:bg-neutral-300 dark:bg-neutral-800 dark:hover:bg-neutral-700 dark:active:bg-neutral-700
text-red-700 dark:text-red-500
px-4 py-2
delay-0 duration-150 transition-colors
border-2 border-t-neutral-100 dark:border-t-neutral-500 border-l-neutral-100 dark:border-l-neutral-500 border-r-neutral-400 dark:border-r-neutral-700 border-b-neutral-400 dark:border-b-neutral-700
active:border-t-neutral-400 dark:active:border-t-neutral-700 active:border-l-neutral-400 dark:active:border-l-neutral-700 active:border-r-neutral-100 dark:active:border-r-neutral-500 active:border-b-neutral-100 dark:active:border-b-neutral-500
;
}
.taskbar-button {
@apply shadow-2x1
bg-neutral-200 hover:bg-neutral-300 active:bg-neutral-300 dark:bg-neutral-800 dark:hover:bg-neutral-700 dark:active:bg-neutral-700

View File

@ -29,18 +29,20 @@ export default class extends Aview {
<input type="text" id="displayName-input" class="bg-white text-neutral-900 px-4 py-2 input-border" required></input>
<button id="displayName-button" type="submit" class="default-button w-full">change display name</button>
</div>
<div id="upload" class="flex flex-row items-center place-items-center space-x-8">
<div id="upload-preview" class="hidden flex flex-col items-center place-items-center space-y-4">
<div class="reverse-border">
<div id="upload" class="flex flex-row items-center place-items-center space-x-8 p-4">
<div id="upload-preview" class="hidden flex flex-col items-center place-items-center space-y-4">
<img id="upload-preview-img" class="w-20 h-20" />
<button id="upload-submit" type="submit" class="default-button">change avatar</button>
</div>
<label for="upload-file" class="default-button">select an avatar...</label><input type="file" id="upload-file" class="hidden" accept="image/*" />
</div>
<button id="deleteAccount-button" type="submit" class="default-button w-full">delete your account</button>
<div class="flex justify-center">
<hr class="w-50 reverse-border">
<label for="upload-file" class="default-button">select an avatar...</label><input type="file" id="upload-file" class="hidden" accept="image/*" />
</div>
</div>
<button id="2fa-button" type="submit" class="default-button w-full">2fa</button>
<div class="flex justify-center py-4">
<hr class="w-50 reverse-border">
</div>
<button id="deleteAccount-button" type="submit" class="red-button w-full" >delete your account</button>
</div>
</div>
`;

View File

@ -358,6 +358,7 @@ export default class extends Aview {
hold() {
if (!this.canHold) return;
this.isLocking = false;
[this.piece, this.holdPiece] = [this.holdPiece, this.piece];
if (!this.piece) this.spawnPiece();
if (!this.piece) return;
@ -410,6 +411,8 @@ export default class extends Aview {
lockPiece() {
if (!this.piece) return;
this.canHold = false;
this.isLocking = false;
let isValid: boolean = false;
for (const cell of this.piece.getCells()) {
@ -442,7 +445,7 @@ export default class extends Aview {
const newLevel = Math.floor(this.lines / 10) + 1;
if (newLevel > this.level) {
this.level = newLevel;
this.dropInterval = Math.max(100, 1000 - (this.level - 1) * 75);
this.dropInterval = Math.max(100, 1000 - (this.level - 1) * 250);
}
}
}
@ -512,50 +515,6 @@ export default class extends Aview {
}
}
removeListeners() {
window.removeEventListener("keydown", (e) => {
this.keys[e.key] = true;
if (this.isGameOver) return;
if (e.key === "p" || e.key === "P" || e.key === "Escape")
this.isPaused = !this.isPaused;
if (this.isPaused) return;
if (e.key === "ArrowLeft")
{
this.inputTimestamp = Date.now();
this.direction = -1;//this.movePiece(-1, 0);
this.move = true;
}
else if (e.key === "ArrowRight")
{
this.inputTimestamp = Date.now();
this.direction = 1;//this.movePiece(1, 0);
this.move = true;
}
else if (e.key === "ArrowDown") this.softDrop();
else if (e.code === "Space") {
e.preventDefault();
this.hardDrop();
} else if (e.key === "Shift" || e.key === "c" || e.key === "C") {
e.preventDefault();
this.hold();
} else if (e.key === "x" || e.key === "X" || e.key === "ArrowUp") {
e.preventDefault();
this.rotatePiece("cw");
} else if (e.key === "z" || e.key === "Z" || e.key === "Control") {
e.preventDefault();
this.rotatePiece("ccw");
}
});
document.removeEventListener("keyup", (e) => {
this.keys[e.key] = false;
});
}
registerListeners() {
window.addEventListener("keydown", (e) => {
this.keys[e.key] = true;
@ -606,9 +565,6 @@ export default class extends Aview {
this.inputManager();
if (this.isLocking ? timestamp - this.lastDrop > 500 : timestamp - this.lastDrop > this.dropInterval)
{
if (this.isLocking && this.lockRotationCount == this.lockLastRotationCount)
this.lockPiece();
this.lockLastRotationCount = this.lockRotationCount;
if (!this.movePiece(0, 1))
{
if (!this.isLocking)
@ -619,8 +575,11 @@ export default class extends Aview {
}
}
else if (this.isLocking)
this.lockRotationCount = 0;
this.isLocking = false;
this.lastDrop = timestamp;
if (this.isLocking && this.lockRotationCount == this.lockLastRotationCount)
this.lockPiece();
this.lockLastRotationCount = this.lockRotationCount;
}
}
this.draw();

View File

@ -388,6 +388,7 @@ export default class extends Aview {
hold() {
if (!this.canHold) return;
this.isLocking = false;
[this.piece, this.holdPiece] = [this.holdPiece, this.piece];
if (!this.piece) this.spawnPiece();
if (!this.piece) return;
@ -441,6 +442,8 @@ export default class extends Aview {
lockPiece() {
if (!this.piece) return;
this.canHold = false;
this.isLocking = false;
let isValid: boolean = false;
for (const cell of this.piece.getCells()) {
@ -494,7 +497,7 @@ export default class extends Aview {
const newLevel = Math.floor(this.lines / 10) + 1;
if (newLevel > this.level) {
this.level = newLevel;
this.dropInterval = Math.max(100, 1000 - (this.level - 1) * 75);
this.dropInterval = Math.max(100, 1000 - (this.level - 1) * 250);
}
if (this.garbage)
@ -636,9 +639,6 @@ export default class extends Aview {
this.inputManager();
if (this.isLocking ? timestamp - this.lastDrop > 500 : timestamp - this.lastDrop > this.dropInterval)
{
if (this.isLocking && this.lockRotationCount == this.lockLastRotationCount)
this.lockPiece();
this.lockLastRotationCount = this.lockRotationCount;
if (!this.movePiece(0, 1))
{
if (!this.isLocking)
@ -649,8 +649,11 @@ export default class extends Aview {
}
}
else if (this.isLocking)
this.lockRotationCount = 0;
this.isLocking = false;
this.lastDrop = timestamp;
if (this.isLocking && this.lockRotationCount == this.lockLastRotationCount)
this.lockPiece();
this.lockLastRotationCount = this.lockRotationCount;
}
}
this.draw();