From f2cffc44009d48c854ee42455b93c9e71a9a962e Mon Sep 17 00:00:00 2001 From: Alfie King Date: Fri, 20 Jun 2025 09:48:20 +0100 Subject: [PATCH] 500&404 errors --- .gitignore | 4 +- dockerfile | 25 +++ requirements.txt | 4 + src/__pycache__/database.cpython-313.pyc | Bin 2755 -> 2938 bytes src/database.py | 4 +- src/main.py | 90 ++++++--- src/static/js/snake.js | 151 --------------- .../content/Irken-Like-AllCaps.woff | Bin {src/static => static}/content/background.png | Bin {src/static => static}/content/buttons.txt | 0 {src/static => static}/content/haj.gif | Bin {src/static => static}/content/icon.webp | Bin {src/static => static}/css/404.css | 38 +++- static/css/500.css | 8 + .../css/index.css => static/css/base.css | 0 {src/static => static}/css/cap.css | 0 static/favicon.ico | Bin 0 -> 246110 bytes src/static/js/index.js => static/js/base.js | 0 static/js/snake.js | 174 ++++++++++++++++++ {src/templates => static}/robots.txt | 0 {src/templates => static}/sitemap.xml | 0 {src/templates => templates}/404.html | 22 ++- templates/500.html | 17 ++ {src/templates => templates}/base.html | 9 +- {src/templates => templates}/index.html | 0 25 files changed, 353 insertions(+), 193 deletions(-) create mode 100644 dockerfile create mode 100644 requirements.txt delete mode 100644 src/static/js/snake.js rename {src/static => static}/content/Irken-Like-AllCaps.woff (100%) rename {src/static => static}/content/background.png (100%) rename {src/static => static}/content/buttons.txt (100%) rename {src/static => static}/content/haj.gif (100%) rename {src/static => static}/content/icon.webp (100%) rename {src/static => static}/css/404.css (67%) create mode 100644 static/css/500.css rename src/static/css/index.css => static/css/base.css (100%) rename {src/static => static}/css/cap.css (100%) create mode 100644 static/favicon.ico rename src/static/js/index.js => static/js/base.js (100%) create mode 100644 static/js/snake.js rename {src/templates => static}/robots.txt (100%) rename {src/templates => static}/sitemap.xml (100%) rename {src/templates => templates}/404.html (63%) create mode 100644 templates/500.html rename {src/templates => templates}/base.html (95%) rename {src/templates => templates}/index.html (100%) diff --git a/.gitignore b/.gitignore index c2eabec..cca1ed7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .venv -.env \ No newline at end of file +.env +db.sqlite +flask_session \ No newline at end of file diff --git a/dockerfile b/dockerfile new file mode 100644 index 0000000..145aa9e --- /dev/null +++ b/dockerfile @@ -0,0 +1,25 @@ +FROM python:alpine + +# Set the working directory +WORKDIR /app + +# Copy the requirements file into the container +COPY requirements.txt . + +# Install the required packages +RUN pip install --no-cache-dir -r requirements.txt +RUN pip install gunicorn + +# Copy the rest of the application code into the container +COPY src src +COPY templates templates +COPY static static + +# Expose the port the app runs on +EXPOSE 5000 + +# Set environment variables +ENV FLASK_APP=main.py + +# run the application +ENTRYPOINT [ "gunicorn", "-b", ":5000", "--access-logfile", "-", "--error-logfile", "-", "src.main:app" ] \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f87e99e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +python-dotenv +flask-session +requests +flask \ No newline at end of file diff --git a/src/__pycache__/database.cpython-313.pyc b/src/__pycache__/database.cpython-313.pyc index 1a92a2fdf3485fe703b2464d5028a1357805c1d8..7d2b6621a40e775de5476713204ba24140eb7f38 100644 GIT binary patch delta 509 zcmX>s`b&)OGcPX}0}vb&3eBiy-N={9!o>#UG6V7FSCea5)T5$7Y%mCB3}xhF2xbap z=3_8sF=d2^Dlj0aV1}w-LRAsUoCGvALfOiSfgus7FP$NjA&6yiA)D}I1x8_!V3r6W z6DCt8n1Mh^4v-`x_hdyzsmTGHtZJ-&Reb(ADGJ5O`9-M;Y57G8RZLb2ReXM_3TtrFXJyU^rQcU71mOvKza(iUQEaVmpYn96bHpo!r+sq%U$vUyw<- zkeq%YDf0?P*5>)_x{Qpflh1Oj6x9SOy~XE}Sdy5OSe&YtoReRisyVrvvsyq7C{rW} zBGf>H=43H0cUEpz#ZOX`leko*3_yZHAc7xA+~Tmw%}*)KNwq67oV$8- z22kNGK9|Ij#H7UHRK4V!{Nhyg$xd9=0 10000 or len(username) < 3 or len(username) > 20: + logging.error("Invalid score or username length: score=%s, username=%s", score, username) + return render_template('404.html', scores=scores, error='Invalid score or username length'), 400 cap_response = requests.post( env('CAP_VERIFY_URL', default='https:////siteverify'), json={ 'secret': env('CAP_SECRET', default=''), - 'response': cap, + 'response': token, } ) if cap_response.status_code != 200 or not cap_response.json().get('success', "false") != "true": logging.error("Captcha verification failed: %s", cap_response.json()) - return {'error': 'Captcha verification failed'}, 400 - - if not isinstance(name, str) or not isinstance(score, int): - logging.error("Invalid data types: name=%s, score=%s", type(name), type(score)) - return {'error': 'Invalid data types'}, 400 + return render_template('404.html', scores=scores, error='Captcha verification failed'), 400 - if not name or score <= 0 or score > 10000: - logging.error("Invalid name or score: name=%s, score=%s", name, score) - return {'error': 'Invalid name or score'}, 400 - - db.insert_snake(name, score) - logging.info("Snake submitted: name=%s, score=%d", name, score) - return {'success': True, 'message': 'Snake submitted successfully'}, 200 + db.insert_snake(name=username, score=int(score)) + logging.info("Snake submitted: name=%s, score=%d", username, score) - -@app.errorhandler(404) -def page_not_found(e): - logging.error("Page not found: %s", request.path) unformatted_scores = db.get_snake_scores() scores = [{'position': i + 1, 'name': score[1], 'score': score[2]} for i, score in enumerate(unformatted_scores)] - return render_template('404.html', scores=scores), 404 + return render_template('404.html', scores=scores, success='Score submitted successfully!') + + +@app.route('/500') +@app.errorhandler(500) +def internal_error(error="An internal server error occurred."): + logging.error("Internal server error: %s", error) + return render_template('500.html'), 500 if __name__ == '__main__': diff --git a/src/static/js/snake.js b/src/static/js/snake.js deleted file mode 100644 index 146a8e0..0000000 --- a/src/static/js/snake.js +++ /dev/null @@ -1,151 +0,0 @@ -const canvas = document.getElementById('snakeCanvas'); -const ctx = canvas.getContext('2d'); - -const gridSize = 15; -const scale = 200; -canvas.width = gridSize * scale; -canvas.height = gridSize * scale; - -let snake = [{ x: 10, y: 10 }]; -let direction = { x: 0, y: 0 }; -let food = { x: 5, y: 5 }; -let score = 0; -let gameOver = false; - -let token = null; - -function draw() { - ctx.clearRect(0, 0, canvas.width, canvas.height); - - // draw grid of checkerboard pattern - for (let x = 0; x < gridSize; x++) { - for (let y = 0; y < gridSize; y++) { - ctx.fillStyle = (x + y) % 2 === 0 ? 'darkgray' : 'grey'; - ctx.fillRect(x * scale, y * scale, scale, scale); - } - } - - // Draw snake - snake.forEach(segment => { - ctx.fillStyle = (snake.indexOf(segment) % 2 === 0) ? 'green' : 'darkgreen'; - ctx.fillRect(segment.x * scale, segment.y * scale, scale, scale); - }); - - // Draw food - ctx.fillStyle = 'red'; - ctx.fillRect(food.x * scale, food.y * scale, scale, scale); -} - -function update() { - if (gameOver) return; - - // Move snake - const head = { x: snake[0].x + direction.x, y: snake[0].y + direction.y }; - - // Add new head - snake.unshift(head); - - // Check for food collision - if (head.x === food.x && head.y === food.y) { - score += 10; // Increase score - placeFood(); - } else { - snake.pop(); // Remove tail if no food eaten - } - - // Check for wall collision - if (head.x < 0 || head.x >= gridSize || head.y < 0 || head.y >= gridSize) { - gameOver = true; - alert(`Game Over! Your score: ${score}`); - return; - } - - // Check for self collision - for (let i = 1; i < snake.length; i++) { - if (head.x === snake[i].x && head.y === snake[i].y) { - gameOver = true; - alert(`Game Over! Your score: ${score}`); - return; - } - } -} - -function placeFood() { - do { - food.x = Math.floor(Math.random() * gridSize); - food.y = Math.floor(Math.random() * gridSize); - } while (snake.some(segment => segment.x === food.x && segment.y === food.y)); -} - -function changeDirection(event) { - switch (event.key) { - case 'w': - if (direction.y === 0) direction = { x: 0, y: -1 }; - break; - case 's': - if (direction.y === 0) direction = { x: 0, y: 1 }; - break; - case 'a': - if (direction.x === 0) direction = { x: -1, y: 0 }; - break; - case 'd': - if (direction.x === 0) direction = { x: 1, y: 0 }; - break; - } -} - -function gameLoop() { - if (!gameOver) { - update(); - draw(); - setTimeout(gameLoop, 100); - } -} - -document.addEventListener('keydown', changeDirection); -// Start the game loop -gameLoop(); -// Initial draw -draw(); - - -const widget = document.querySelector("#cap"); - -widget.addEventListener("solve", function (e) { - token = e.detail.token; - console.log("Captcha solved, token:", token); -}); - -// Function to submit score to the server -document.getElementById("snakeForm").addEventListener('submit', function(event) { - event.preventDefault(); - - if (!token) { - alert('Please complete the CAPTCHA before submitting your score.'); - return; - } - - // post request to server with score - fetch('/snake/submit', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - score: score, - name: document.getElementById('name').value, - cap: token - }) - }).then(response => { - if (response.ok) { - alert('Score submitted successfully!'); - window.location.reload(); - } else { - alert('Failed to submit score, check console for details.'); - response.json().then(data => console.error(data)); - } - }).catch(error => { - console.error('Error submitting score:', error); - alert('Error submitting score, check console for details.'); - }); -}); \ No newline at end of file diff --git a/src/static/content/Irken-Like-AllCaps.woff b/static/content/Irken-Like-AllCaps.woff similarity index 100% rename from src/static/content/Irken-Like-AllCaps.woff rename to static/content/Irken-Like-AllCaps.woff diff --git a/src/static/content/background.png b/static/content/background.png similarity index 100% rename from src/static/content/background.png rename to static/content/background.png diff --git a/src/static/content/buttons.txt b/static/content/buttons.txt similarity index 100% rename from src/static/content/buttons.txt rename to static/content/buttons.txt diff --git a/src/static/content/haj.gif b/static/content/haj.gif similarity index 100% rename from src/static/content/haj.gif rename to static/content/haj.gif diff --git a/src/static/content/icon.webp b/static/content/icon.webp similarity index 100% rename from src/static/content/icon.webp rename to static/content/icon.webp diff --git a/src/static/css/404.css b/static/css/404.css similarity index 67% rename from src/static/css/404.css rename to static/css/404.css index d3e572f..ff24cf5 100644 --- a/src/static/css/404.css +++ b/static/css/404.css @@ -1,7 +1,8 @@ canvas#snakeCanvas { - padding: 15px; - width: 100%; + margin: 15px; box-sizing: border-box; + border: 2px solid var(--secondary-background-color); + border-radius: 10px; } form { @@ -76,4 +77,37 @@ form button[type="submit"] { #snakeLeaderboard li:nth-child(even) { background-color: var(--secondary-background-color); +} + +dialog { + width: 90%; + max-width: 500px; + padding: 20px; + background-color: var(--background-color); + color: var(--text-color); + border: 2px solid var(--secondary-background-color); + border-radius: 8px; +} + +dialog button { + padding: 10px; + width: 100%; + box-sizing: border-box; + border: 2px solid var(--secondary-background-color); + border-radius: 6px; + background-color: var(--secondary-background-color-but-slightly-transparent); + color: var(--text-color); + font-weight: bold; + cursor: pointer; + margin-top: 10px; +} + +dialog h2 { + margin: 0; + font-size: 1.5rem; +} + +dialog p { + margin: 0; + font-size: 1rem; } \ No newline at end of file diff --git a/static/css/500.css b/static/css/500.css new file mode 100644 index 0000000..2f74df6 --- /dev/null +++ b/static/css/500.css @@ -0,0 +1,8 @@ +.bluescreen { + background-color: #0077D6; + color: #fff; + padding:40px; + display: flex; + flex-direction: column; + gap: 20px; +} \ No newline at end of file diff --git a/src/static/css/index.css b/static/css/base.css similarity index 100% rename from src/static/css/index.css rename to static/css/base.css diff --git a/src/static/css/cap.css b/static/css/cap.css similarity index 100% rename from src/static/css/cap.css rename to static/css/cap.css diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..0d875dfd81a11ecdb0fd862c000f80337d9581a3 GIT binary patch literal 246110 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℞||LXTXFWsB2OZew}33~Hi^NtJr=jMH}nT>$_ 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 KI&!~V`}ziHlVIln literal 0 HcmV?d00001 diff --git a/src/static/js/index.js b/static/js/base.js similarity index 100% rename from src/static/js/index.js rename to static/js/base.js diff --git a/static/js/snake.js b/static/js/snake.js new file mode 100644 index 0000000..61a4edc --- /dev/null +++ b/static/js/snake.js @@ -0,0 +1,174 @@ +const canvas = document.getElementById('snakeCanvas'); +const ctx = canvas.getContext('2d'); + +const gridSize = 20; +const tileSize = 100; +const snakeSize = 60; +const foodSize = 80; +canvas.width = gridSize * tileSize; +canvas.height = gridSize * tileSize; + +let snake = [{ x: 10, y: 10 }, { x: 10, y: 11 }, { x: 10, y: 12 }]; +let direction = { x: 0, y: 0 }; +let food = { x: Math.floor(Math.random() * gridSize), y: Math.floor(Math.random() * gridSize) }; +let score = 0; +let gameOver = false; + +function draw() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + + // draw grid of checkerboard pattern + for (let x = 0; x < gridSize; x++) { + for (let y = 0; y < gridSize; y++) { + ctx.fillStyle = (x + y) % 2 === 0 ? + getComputedStyle(document.documentElement).getPropertyValue('--background-color') : + getComputedStyle(document.documentElement).getPropertyValue('--secondary-background-color'); + ctx.fillRect(x * tileSize, y * tileSize, tileSize, tileSize); + } + } + + // Draw snake + snake.forEach(segment => { + let nextVec = { x: 0, y: 0 }; + // if there is a segment after the current segment + if (snake.indexOf(segment) < snake.length - 1) { + const nextSegment = snake[snake.indexOf(segment) + 1]; + nextVec.x = nextSegment.x - segment.x; + nextVec.y = nextSegment.y - segment.y; + } + + ctx.fillStyle = getComputedStyle(document.documentElement).getPropertyValue('--primary-color'); + if (nextVec.x === 0 && nextVec.y === 0) { + ctx.fillRect( + segment.x * tileSize + (tileSize - snakeSize) / 2, + segment.y * tileSize + (tileSize - snakeSize) / 2, + snakeSize, + snakeSize + ); + } else if (nextVec.x > 0 || nextVec.y > 0) { + ctx.fillRect( + segment.x * tileSize + (tileSize - snakeSize) / 2, + segment.y * tileSize + (tileSize - snakeSize) / 2, + snakeSize + nextVec.x * (tileSize - snakeSize), + snakeSize + nextVec.y * (tileSize - snakeSize) + ); + } else { + ctx.fillRect( + segment.x * tileSize + (tileSize - snakeSize) / 2 + nextVec.x * (tileSize - snakeSize), + segment.y * tileSize + (tileSize - snakeSize) / 2 + nextVec.y * (tileSize - snakeSize), + snakeSize + Math.abs(nextVec.x) * (tileSize - snakeSize), + snakeSize + Math.abs(nextVec.y) * (tileSize - snakeSize) + ); + } + + }); + + // Draw food + ctx.fillStyle = '#ff4d4d'; + ctx.fillRect( + food.x * tileSize + (tileSize - foodSize) / 2, + food.y * tileSize + (tileSize - foodSize) / 2, + foodSize, + foodSize + ); +} + +function update() { + if (gameOver) return; + + // Move snake + const head = { x: snake[0].x + direction.x, y: snake[0].y + direction.y }; + + // Add new head + snake.unshift(head); + + // Check for food collision + if (head.x === food.x && head.y === food.y) { + score += 10; // Increase score + placeFood(); + } else { + snake.pop(); // Remove tail if no food eaten + } + + // Check for wall collision + if (head.x < 0 || head.x >= gridSize || head.y < 0 || head.y >= gridSize) { + gameOver = true; + return; + } + + // Check for self collision + for (let i = 1; i < snake.length; i++) { + if (head.x === snake[i].x && head.y === snake[i].y) { + gameOver = true; + return; + } + } +} + +function placeFood() { + do { + food.x = Math.floor(Math.random() * gridSize); + food.y = Math.floor(Math.random() * gridSize); + } while (snake.some(segment => segment.x === food.x && segment.y === food.y)); +} + +function changeDirection(event) { + switch (event.key) { + case 'w': + if (direction.y === 0) direction = { x: 0, y: -1 }; + break; + case 's': + if (direction.y === 0) direction = { x: 0, y: 1 }; + break; + case 'a': + if (direction.x === 0) direction = { x: -1, y: 0 }; + break; + case 'd': + if (direction.x === 0) direction = { x: 1, y: 0 }; + break; + } +} + +// Menu to start the game +function menu() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + + ctx.fillStyle = getComputedStyle(document.documentElement).getPropertyValue('--background-color'); + ctx.fillRect(0, 0, canvas.width, canvas.height); + + ctx.textAlign = 'center'; + ctx.fillStyle = getComputedStyle(document.documentElement).getPropertyValue('--text-color'); + ctx.font = '200px Arial'; + ctx.fillText('Snake Game', canvas.width / 2, canvas.height / 2); + ctx.font = '100px Arial'; + ctx.fillText('Press W/A/S/D to move', canvas.width / 2, canvas.height / 2 + 100); + ctx.fillText('Click to start', canvas.width / 2, canvas.height / 2 + 200); + + canvas.addEventListener('click', startGame); +} + +function gameLoop() { + if (!gameOver) { + update(); + draw(); + setTimeout(gameLoop, 100); + } else { + document.removeEventListener('keydown', changeDirection); + document.getElementById('snake-score').value = score; + alert(`Game Over! Your score: ${score}`); + menu(); + } +} + +function startGame() { + snake = [{ x: 10, y: 10 }, { x: 10, y: 11 }, { x: 10, y: 12 }]; + direction = { x: 1, y: 0 }; + food = { x: Math.floor(Math.random() * gridSize), y: Math.floor(Math.random() * gridSize) }; + score = 0; + gameOver = false; + canvas.removeEventListener('click', startGame); + document.addEventListener('keydown', changeDirection); + gameLoop(); +} + +menu(); \ No newline at end of file diff --git a/src/templates/robots.txt b/static/robots.txt similarity index 100% rename from src/templates/robots.txt rename to static/robots.txt diff --git a/src/templates/sitemap.xml b/static/sitemap.xml similarity index 100% rename from src/templates/sitemap.xml rename to static/sitemap.xml diff --git a/src/templates/404.html b/templates/404.html similarity index 63% rename from src/templates/404.html rename to templates/404.html index add651c..6ac41f9 100644 --- a/src/templates/404.html +++ b/templates/404.html @@ -14,16 +14,17 @@

It seems like the thing you are looking for is not here :[

- while you're here, why not play some snake? (use wasd to move, not mobile compatable :<) + while you're here, why not play some snake?

Submit score

-
- - + + + +
@@ -40,6 +41,19 @@
+{% if error %} + +

Error

+

{{ error }}

+ +
+ +{% endif %} {% endblock %} {% block scripts %} diff --git a/templates/500.html b/templates/500.html new file mode 100644 index 0000000..ab6dfe4 --- /dev/null +++ b/templates/500.html @@ -0,0 +1,17 @@ +{% extends "base.html" %} + +{% block title %}500 - Internal Server Error{% endblock %} +{% block description %}An unexpected error occurred on the server.{% endblock %} + +{% block head %} + +{% endblock %} + +{% block content %} +
+

:(

+

+ Oopsie Woopsie! Uwu We made a fucky wucky!! A wittle fucko boingo! The code monkeys at our headquarters are working VEWY HAWD to fix this! +

+
+{% endblock %} \ No newline at end of file diff --git a/src/templates/base.html b/templates/base.html similarity index 95% rename from src/templates/base.html rename to templates/base.html index 956d598..dbe782e 100644 --- a/src/templates/base.html +++ b/templates/base.html @@ -5,7 +5,7 @@ {% block title %}Alfie's basement{% endblock %} - + @@ -26,7 +26,7 @@
@@ -60,7 +61,7 @@
      |\      _,,,---,,_
ZZZzz /,`.-'`' -. ;-;;,_
|,4- ) )-,_. ,\ ( `'-'
'---''(_/--' `-'\_)
- haj + haj
@@ -92,6 +93,6 @@
{% block scripts %}{% endblock %} - + diff --git a/src/templates/index.html b/templates/index.html similarity index 100% rename from src/templates/index.html rename to templates/index.html

Things to see :3