diff --git a/README.md b/README.md index 4c66f85..d13ed3e 100644 --- a/README.md +++ b/README.md @@ -13,3 +13,6 @@ python main ### zero downtime restarts: - launch new burgercat server - close previous server + +### contribution guidelines: +- please check that your PR does not break anything \ No newline at end of file diff --git a/main b/main index a5c1997..4dcc714 100644 --- a/main +++ b/main @@ -82,6 +82,16 @@ def get_comments(id): return post +def get_messages(chatroomid): + conn = get_db_connection() + post = conn.execute("SELECT * FROM chatmessages WHERE chatroom_id = ? ORDER BY created DESC;", + (chatroomid,)).fetchall() + conn.close() + if post is None: + return "error" + return post + + app.jinja_env.globals.update(getComments=get_comments) def get_post(id): @@ -138,6 +148,109 @@ def main(): else: return render_template("main.html", posts=posts) +@app.route("/chat", methods=("GET", "POST")) +def chat(): + usersession = request.cookies.get("session_DO_NOT_SHARE") + if usersession: + userCookie = get_session(usersession) + user = get_user(userCookie["id"]) + return render_template("chat.html", userdata=user) + else: + return render_template("chat.html") + +@app.route("/api/chat/listrooms") +def chatlistrooms(): + conn = get_db_connection() + rooms = conn.execute("SELECT * FROM chatrooms ORDER BY roomname ASC;").fetchall() + conn.close() + + template = [] + + for room in rooms: + roomtemplate = { + "id": room["id"], + "name": room["roomname"] + } + template.append(roomtemplate) + + return(template), 200 + +@app.route("/api/chat/getmessages/") +def chatget(roomid): + messages = get_messages(roomid) + + template = [] + + for message in messages: + creatorid = message["creator"] + + creatortemplate = { + "id": message["creator"], + "username": get_user(creatorid)["username"] + } + + messagetemplate = { + "id": message["id"], + "content": message["content"], + "creator": creatortemplate, + "created": message["created"] + } + template.append(messagetemplate) + + return(template), 200 + +burgerMessageUpdate = True +burgerMessageCache = "" + +@app.route("/api/chat/send/", methods=("GET", "POST")) +def chatsend(roomid): + usersession = request.cookies.get("session_DO_NOT_SHARE") + if usersession: + if request.method == "POST": + + data = request.get_json() + content = data["content"] + + print(content) + print(roomid) + + userCookie = get_session(usersession) + user = get_user(userCookie["id"]) + + if not user["banned"] == "0": + return { + "error": "banned" + }, 403 + + conn = get_db_connection() + conn.execute("INSERT INTO chatmessages (content, chatroom_id, creator, created) VALUES (?, ?, ?, ?)", + (content, roomid, userCookie["id"], str(time.time()))) + conn.commit() + conn.close() + + global burgerMessageCache + global burgerMessageUpdate + burgerMessageUpdate = True + burgerMessageCache = user["username"] + ": " + content + + return "success", 200 + + +@sock.route("/api/chat/listen") +def chatlisten(ws): + global burgerMessageCache + global burgerMessageUpdate + + while burgerMessageUpdate == True: + ws.send(burgerMessageCache) + burgerMessageUpdate = False + +@app.route("/erm", methods=("GET", "POST")) +def erm(): + print(burgerMessageCache) + print(burgerMessageUpdate) + + return "fart" @app.route("/@", methods=("GET", "POST")) def user(pageusername): @@ -290,7 +403,7 @@ def apilogin(): return { "key": randomCharacters - }, 100 + }, 200 else: return { "error": "https://http.cat/images/400.jpg" @@ -346,7 +459,7 @@ def apipost(): conn.commit() conn.close() - return "success", 100 + return "success", 200 @app.route("/apidocs", methods=("GET", "POST")) def apidocs(): @@ -445,7 +558,7 @@ def comment(): conn.commit() conn.close() - return "success", 100 + return "success", 200 else: return { @@ -581,7 +694,7 @@ def delete(): conn.execute("DELETE FROM posts WHERE id = ?", (postid,)) conn.commit() conn.close() - return "success", 100 + return "success", 200 else: return { "error": "https://http.cat/images/403.jpg" diff --git a/newchatroom b/newchatroom new file mode 100644 index 0000000..b446d1f --- /dev/null +++ b/newchatroom @@ -0,0 +1,18 @@ +#!/usr/bin/python3 +import sqlite3 +import time +import os + +chatroomname = input("Insert name: ") + +def get_db_connection(): + conn = sqlite3.connect("database.db") + conn.row_factory = sqlite3.Row + return conn + +conn = get_db_connection() +conn.execute("INSERT INTO chatrooms (roomname, creator, created) VALUES (?, ?, ?)", + (chatroomname, 1, str(time.time()))) +conn.commit() +conn.close() +print("Success!") \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index c9ec32e..79aec11 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ flask Flask-Limiter werkzeug -waitress \ No newline at end of file +waitress +requests \ No newline at end of file diff --git a/schema.sql b/schema.sql index f3409d8..d5b00b2 100644 --- a/schema.sql +++ b/schema.sql @@ -2,6 +2,8 @@ DROP TABLE IF EXISTS users; DROP TABLE IF EXISTS posts; DROP TABLE IF EXISTS comments; DROP TABLE IF EXISTS sessions; +DROP TABLE IF EXISTS chatrooms; +DROP TABLE IF EXISTS chatmessages; CREATE TABLE users ( id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -29,6 +31,21 @@ CREATE TABLE comments ( textstr TEXT NOT NULL ); +CREATE TABLE chatrooms ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + created TEXT NOT NULL, + creator TEXT NOT NULL, + roomname TEXT NOT NULL +); + +CREATE TABLE chatmessages ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + chatroom_id INTEGER NOT NULL, + created TEXT NOT NULL, + creator TEXT NOT NULL, + content TEXT NOT NULL +); + CREATE TABLE sessions ( session TEXT PRIMARY KEY NOT NULL, id INTEGER NOT NULL diff --git a/static/css/style.css b/static/css/style.css index e8d9cd8..7cbfcd9 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -16,20 +16,25 @@ body { background-color: white; width: 100%; position: fixed; + z-index: 2; } + .navbar .selected { border: solid; border-color: #f1b739; border-width: 0; border-bottom-width: 2px; } + .postDiv { padding-top: 120px; } + .profileDiv { padding-left: 10px; padding-right: 10px; } + .profileIFrame { border: solid; border-width: 0; @@ -38,6 +43,7 @@ body { width: 100%; height: calc(100vh - 295px); } + .profileDiv .badgeDiv p { background-color: black; border-radius: 99px; @@ -47,15 +53,18 @@ body { padding-right: 10px; display: inline; } + .editThing .htmlBox { width: calc(100% - 10px); height: 300px; text-align: top; } + .accountform { margin-left: 20%; margin-right: 20%; } + .accountform input { padding: 7px; border: solid; @@ -65,6 +74,7 @@ body { font-size: 16px; border-radius: 8px; } + .accountform .flash { padding: 7px; border: solid; @@ -74,6 +84,7 @@ body { font-size: 16px; border-radius: 8px; } + .accountform button { padding: 7px; border: solid; @@ -124,6 +135,7 @@ body { font-size: 16px; font-family: "Inter", sans-serif; } + .post button:hover { border-color: #f1b739; } @@ -138,11 +150,13 @@ body { margin-top: 5px; font-family: "Inter", sans-serif; } + .post hr { color: rgb(255, 255, 255); background-color: rgb(255, 255, 255); border-color: rgb(255, 255, 255); } + .post .commentsdiv { background-color: #f5f5f5; padding: 5px; @@ -163,6 +177,88 @@ body { text-decoration: none; } +.chatDiv { + width: 292vh; + margin-top: 2px; + height: calc(100vh - 121px); +} + +.channelDiv { + position: absolute; + width: 220px; + height: calc(100%); + left: 0; + background-color: rgb(245, 245, 245); +} + +.channelDiv .statusMessage { + position: absolute; + left: 10px; + bottom: 122.5px; +} + +.channelDiv button { + width: calc(100% - 20px); + margin: 10px; + margin-bottom: 0; + padding-left: 10px; + background-color: white; + border: none; + border-radius: 8px; + color: black; + font-size: 16px; + text-align: left; + height: 40px; +} + +.channelDiv .selected { + border: solid; + border-width: 1px; + border-color: #f1b739; +} + +.channelDiv button:hover { + background-color: rgb(249, 249, 249); + transition: background-color ease-in-out 100ms +} + +.messageDiv { + position: absolute; + width: calc(100% - 220px); + height: calc(100%); + padding-bottom: 50px; + right: 0; + margin-top: -180px; + display: flex; + flex-direction: column-reverse; +} + +.messageDiv p { + font-size: 16px; + margin-left: 10px; + line-height: 8px; + align-self: flex-start; +} + +.messageBar { + position: absolute; + width: calc(100% - 220px); + height: 50px; + right: 0; + bottom: 0; + background-color: rgb(228, 228, 228); +} + +.messageBar input { + width: calc(100% - 20px); + height: calc(100% - 15px); + border: none; + border-radius: 99px; + padding-left: 10px; + font-size: 15px; + margin: 5px; +} + .warning { width: 100%; background-color: #f1b739; diff --git a/static/js/chat.js b/static/js/chat.js new file mode 100644 index 0000000..a2eccdb --- /dev/null +++ b/static/js/chat.js @@ -0,0 +1,90 @@ +let channelDiv = document.getElementById("channelDiv") +let messageDiv = document.getElementById("messageDiv") +let messageBox = document.getElementById("messageBox") +let statusMessage = document.getElementById("statusMessage") + +let channelID = 0 + +async function updateMessages(id) { + try { + let response = await fetch("/api/chat/getmessages/" + id); + let messages = await response.json() + statusMessage.innerText = "" + document.querySelectorAll(".messageParagraph").forEach(el => el.remove()); + for (let i in messages) { + let messageParagraph = document.createElement("p") + messageParagraph.appendChild(document.createTextNode(messages[i]["creator"]["username"] + ": " + messages[i]["content"])) + messageParagraph.classList.add("messageParagraph") + messageParagraph.id = "messageParagraph" + messages[i]["id"] + messageDiv.append(messageParagraph) + } + } + catch { + statusMessage.innerText = "Not connected" + } +} + +function selectChannel(id) { + channelID = id + + let selectedButton = channelDiv.querySelector(".selected"); + if (selectedButton) { + selectedButton.classList.remove("selected"); + } + + let channelButton = document.getElementById("channelButton" + id) + if (channelButton) { + channelButton.classList.add("selected") + } + else { + console.log("channelButton not found") + } + + updateMessages(id) +} + +async function updateRooms() { + let response = await fetch("/api/chat/listrooms"); + let rooms = await response.json() + for (let i in rooms) { + let channelButton = document.createElement("button") + channelButton.appendChild(document.createTextNode(rooms[i]["name"])) + channelButton.id = "channelButton" + rooms[i]["id"] + channelButton.onclick = function () { selectChannel(rooms[i]["id"]) } + + channelDiv.append(channelButton) + } + + selectChannel(1) +} + +async function sendMessage(content, id) { + fetch("/api/chat/send/" + String(id), { + method: "POST", + body: JSON.stringify({ + content: content + }), + headers: { + "Content-Type": "application/json" + } + }) +} + +messageBox.addEventListener("keyup", function onEvent(event) { + if (event.key === "Enter") { + sendMessage(messageBox.value, channelID) + updateMessages(channelID) + messageBox.value = "" + } +}) + +function update() { + updateMessages(channelID) + + setTimeout(update, 1500); +} + +window.addEventListener("load", function () { + updateRooms() + update() +}) \ No newline at end of file diff --git a/templates/chat.html b/templates/chat.html new file mode 100644 index 0000000..5355c1a --- /dev/null +++ b/templates/chat.html @@ -0,0 +1,56 @@ + + + + + + + burgercat + + + + + + + + + +
+ {% if userdata %} + {% if userdata.banned == "0" %} + {% else %} +

Your account has been banned. Reason: "{{ userdata.banned }}". Log out

+ {% endif %} + {% endif %} + +
+
+

Connected

+
+
+
+
+ +
+
+
+ + + + + \ No newline at end of file diff --git a/templates/main.html b/templates/main.html index 7bd5c87..d09b766 100644 --- a/templates/main.html +++ b/templates/main.html @@ -13,6 +13,7 @@