156 lines
5.7 KiB
Python
156 lines
5.7 KiB
Python
from django.shortcuts import render
|
|
from .models import Board, RestrictedIP
|
|
from datetime import datetime
|
|
from django.http import HttpResponse
|
|
from django.core.exceptions import ObjectDoesNotExist
|
|
from colour import Color
|
|
from pytz import UTC
|
|
# Change these for your board
|
|
BOARD_X = 64
|
|
BOARD_Y = 32
|
|
|
|
# Options for implementation of board update:
|
|
# 1) Serve at a special url which is a OTC generated by the server and the client (Hard-ish)
|
|
# 2) Serve at all times and have the client decide when it has changed(Easy)
|
|
|
|
|
|
|
|
# Internal validation
|
|
def validateBoard(x:int, y:int, board:dict, ip) -> bool:
|
|
try:
|
|
ip = RestrictedIP.objects.get(ip=ip)
|
|
return "RESTRICTED"
|
|
except ObjectDoesNotExist:
|
|
pass
|
|
key_counter = 0 # Not using len for optimization purposes
|
|
|
|
for row in board:
|
|
# Check if datatype is list
|
|
if not isinstance(board[row], list):
|
|
return "WRONG Y"
|
|
|
|
# If length of list is not equal to given width of matrix, it is incorrect
|
|
length = len(board[row])
|
|
if length != x:
|
|
return "WRONG LENGTH"
|
|
|
|
key_counter += 1
|
|
|
|
# Check if the keys are the same number as y
|
|
if key_counter != y:
|
|
return "WRONG X"
|
|
return "SUCCESS"
|
|
|
|
def restrict_or_unrestrict(ip):
|
|
try:
|
|
ip = RestrictedIP.objects.get(ip=ip)
|
|
timedelta = datetime.utcnow().replace(tzinfo=UTC) - ip.time_added
|
|
# if banned for more than 1 minute, unban
|
|
if timedelta.seconds > 60:
|
|
ip.delete()
|
|
return "ALLOWED"
|
|
return "STILL RESTRICTED"
|
|
except ObjectDoesNotExist:
|
|
instance = RestrictedIP(ip=ip, time_added=datetime.now())
|
|
instance.save()
|
|
return "RESTRICTION"
|
|
|
|
# Internal board class
|
|
class localBoard:
|
|
def __init__(self) -> None:
|
|
try:
|
|
self.board = Board.objects.latest("update_time")
|
|
except ObjectDoesNotExist:
|
|
# Create a blank board
|
|
blank_config = {int(i): [-1 for _ in range(64)] for i in range(32)}
|
|
|
|
# Time in YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format
|
|
time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
instance = Board(update_time=time, configuration=blank_config)
|
|
instance.save()
|
|
self.board = Board.objects.latest("update_time")
|
|
|
|
def getBoard(self) -> dict:
|
|
return dict(self.board.configuration)
|
|
|
|
def setBoard(self, new_configuration:dict, ip) -> bool:
|
|
# Validate the board
|
|
if err := validateBoard(x=BOARD_X, y=BOARD_Y, board=new_configuration, ip=ip) != "SUCCESS":
|
|
return err
|
|
|
|
# Save the board
|
|
instance = Board(update_time=datetime.now(), configuration=new_configuration)
|
|
instance.save()
|
|
self.board = Board.objects.latest("update_time")
|
|
return "SUCCESS"
|
|
|
|
def HTML(self) -> str:
|
|
board = self.getBoard()
|
|
style = """
|
|
<style>
|
|
table { border-collapse: collapse; width: 100%; height: 90vh; border: 1px solid white;}
|
|
td { width: 10px; height: 10px; border: 1px solid gray; }
|
|
td:onclick { border: 2px solid white; }
|
|
td:hover { border: 2px solid white; }
|
|
.color {
|
|
display: flex;
|
|
width: 100%;
|
|
justify-content: space-between;
|
|
}
|
|
</style>
|
|
"""
|
|
|
|
selected_pixel = """
|
|
<script>
|
|
async function selected_pixel(element) {
|
|
var color = document.getElementById("color_picker").value;
|
|
|
|
var arr = element.id.split("x")[1].split("y");
|
|
var x = arr[0];
|
|
var y = arr[1];
|
|
|
|
var url = "http://127.0.0.1:8000/board/" + x + "/" + y + "/" + color.replace("#", "%23");
|
|
let response = await fetch(url);
|
|
let result = await response.text();
|
|
console.log(result);
|
|
if (result != "RESTRICTED") {
|
|
element.style.backgroundColor = color;
|
|
}
|
|
else {
|
|
alert("You have placed your pixel. Please wait.");
|
|
}
|
|
}
|
|
</script>
|
|
"""
|
|
|
|
html = f"<html><head><title>Ballin</title></head>{style}<body>{selected_pixel}<table><form>"
|
|
for row in board:
|
|
html += "<tr>"
|
|
x = 0
|
|
for col in board[row]:
|
|
html += f"<td style='background-color:{col};' id={'x'+ str(x) + 'y'+ str(row)} onclick=selected_pixel(this)></td>"
|
|
x += 1
|
|
html += "</tr>"
|
|
html += "</table><div class='color'><input type='color' id='color_picker'><p color='white' ><------ pick ur color</p></div></body></html>"
|
|
return html
|
|
|
|
# Publicly visible functions
|
|
def update_board(request, x, y, color):
|
|
board = localBoard().getBoard()
|
|
try:
|
|
color = Color(color).hex
|
|
except Exception as e:
|
|
return HttpResponse(e)
|
|
board[str(y)][int(x)] = color
|
|
|
|
ip = restrict_or_unrestrict(request.META["REMOTE_ADDR"])
|
|
if ip == "STILL RESTRICTED":
|
|
return HttpResponse("RESTRICTED")
|
|
res = localBoard().setBoard(board, request.META["REMOTE_ADDR"])
|
|
return HttpResponse(f"board: {str(res)}, ip: {ip}")
|
|
|
|
def current_config(request):
|
|
html = localBoard().HTML()
|
|
return HttpResponse(html)
|
|
|