This commit is contained in:
Koshin S Hegde 2024-08-26 18:37:38 +05:30
commit 4f75b0622b
122 changed files with 2270 additions and 0 deletions

0
.Trash-1000/files/a Normal file
View File

BIN
.Trash-1000/files/a.zip Normal file

Binary file not shown.

View File

@ -0,0 +1,3 @@
{
"liveServer.settings.port": 5501
}

View File

@ -0,0 +1,21 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script defer src="./index.js"></script>
</head>
<body>
<div className="w-full h-full">
<input
type="file"
id="fileInput"
webkitdirectory="true"
mozdirectory="true"
directory="true"
multiple
/>
<button id="uploadButton">Upload and Zip Files</button>
</div>
</body>
</html>

View File

@ -0,0 +1,31 @@
document.getElementById("uploadButton").addEventListener("click", async () => {
const fileInput = document.getElementById("fileInput");
const files = Array.from(fileInput.files);
if (files.length === 0) {
alert("Please select some files first.");
return;
}
const formData = new FormData();
files.forEach((file) => {
formData.append("files[]", file); // Append each file to FormData
});
try {
const response = await fetch("https://club.modo-dev.com/test", {
method: "POST",
body: formData,
});
if (!response.ok) {
throw new Error("Network response was not ok");
}
const data = await response.json();
console.log("Upload successful:", data);
} catch (error) {
console.error("Error uploading files:", error);
}
});

View File

@ -0,0 +1,3 @@
{
"liveServer.settings.port": 5501
}

View File

View File

@ -0,0 +1,140 @@
Legend:
Form data:
https://developer.mozilla.org/en-US/docs/Web/API/FormData
[something] : this something is optional
---------- USER HANDLING ----------
POST : /get-user-by-email
Form data:
email
return type:
{
"handle": "~",
"display_name": "~"
}
Errors:
422 : email missing in request
404 : email not found
POST : /get-user-by-id
Form data:
id
return type:
{
"handle": "~",
"display_name": "~"
}
Errors:
422 : id missing in request
404 : id not found
POST : /get-user-by-handle
Form Data:
handle
return type:
{
"handle": "~",
"display_name": "~"
}
Errors:
422 : handle missing in request
404 : handle not found
POST : /register
Form Data:
email
handle
password
[display_name]
[profile_picture]
Errors:
422 : something missing in request
409 : User exists (email or handle)
POST : /login
Form Data:
email
password
Errors:
422 : something missing in request
404 : User does not exist
409 : Wrong password
Cookies:
sets id
sets session_id
POST : /logout
Errors:
401 : Not logged in
Cookies:
deletes session_id
deletes id
POST : /change-user-profile-picture
Form Data:
image
Errors:
401 : Not logged in
403 : Invalid log in
422 : image is missing
Note:
Must be logged in
POST : /change-user-display-name
Form Data:
display_name
Errors:
401 : Not logged in
403 : Invalid log in
422 : display_name is missing
Note:
Must be logged in
GET : /profile-picture/<handle>
Errors:
404 : Handle not found
---------- BOUNTY HANDLING ----------
POST : /create-bounty
Form Data:
title
description
[field]
[language]
Errors:
422 : something missing in request
403 : Unknown language/ field
Note:
default language = "any"
default field = "other"
POST : /get-user-by-id
Form data:
id
return type:
{
"handle": "~",
"display_name": "~"
}
Errors:
422 : id missing in request
404 : id not found
POST : /create-session-for-bounty-get-random
Cookies:
sets bounty_session_id
POST : /bounty-get-random
Form data:
page_number
Note:
/create-session-for-bounty-get-random must be called before this
Errors:
422 : page no. missing in request
404 : /create-session-for-bounty-get-random not called

View File

@ -0,0 +1,4 @@
<form action='http://localhost:5000/test' method="POST" enctype="multipart/form-data">
<input type='file' name='file[]' multiple=''>
<input type='submit' value='upload'>
</form>

View File

@ -0,0 +1,6 @@
#include <stdio.h>
void main()
{
printf("Hello World\n");
}

View File

@ -0,0 +1,6 @@
#include <stdio.h>
void main()
{
printf("Hello World\n");
}

View File

@ -0,0 +1,3 @@
[Trash Info]
Path=src/a
DeletionDate=2024-07-24T17:11:19

View File

@ -0,0 +1,3 @@
[Trash Info]
Path=src/a.zip
DeletionDate=2024-07-24T19:40:20

View File

@ -0,0 +1,3 @@
[Trash Info]
Path=assets/apifiletest_.vscode_settings.json
DeletionDate=2024-07-24T20:03:05

View File

@ -0,0 +1,3 @@
[Trash Info]
Path=assets/apifiletest_index.html
DeletionDate=2024-07-24T20:02:59

View File

@ -0,0 +1,3 @@
[Trash Info]
Path=assets/apifiletest_index.js
DeletionDate=2024-07-24T20:03:05

View File

@ -0,0 +1,3 @@
[Trash Info]
Path=assets/apifiletest%7C.vscode%7Csettings.json
DeletionDate=2024-07-24T20:24:13

View File

@ -0,0 +1,3 @@
[Trash Info]
Path=data/booking-site.db
DeletionDate=2024-07-17T19:27:01

View File

@ -0,0 +1,3 @@
[Trash Info]
Path=src/docs.fuck_discord
DeletionDate=2024-07-24T17:11:22

View File

@ -0,0 +1,3 @@
[Trash Info]
Path=src/test.html
DeletionDate=2024-07-24T20:25:59

View File

@ -0,0 +1,3 @@
[Trash Info]
Path=src/test
DeletionDate=2024-07-24T19:40:41

5
.vim/coc-settings.json Normal file
View File

@ -0,0 +1,5 @@
{
"cSpell.words": [
"Yash's"
]
}

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,30 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.w-full {
height: 90%;
width: 90%;
padding: 0%;
margin: 0%;
}
</style>
<script defer src="./index.js"></script>
</head>
<body>
<div>
<input
class="w-full"
type="file"
id="fileInput"
webkitdirectory="true"
mozdirectory="true"
directory="true"
multiple
/>
<button id="uploadButton">Upload and Zip Files</button>
</div>
</body>
</html>

View File

@ -0,0 +1,32 @@
document.getElementById("uploadButton").addEventListener("click", async () => {
const fileInput = document.getElementById("fileInput");
const files = Array.from(fileInput.files);
if (files.length === 0) {
alert("Please select some files first.");
return;
}
const formData = new FormData();
formData.append("bounty_id", 7);
files.forEach((file) => {
formData.append("files", file); // Append each file to FormData
});
try {
const response = await fetch("http://localhost:5000/submit-solution", {
method: "POST",
body: formData,
});
if (!response.ok) {
throw new Error("Network response was not ok");
}
const data = await response.json();
console.log("Upload successful:", data);
} catch (error) {
console.error("Error uploading files:", error);
}
});

BIN
assets/profile_pictures/1 Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
assets/profile_pictures/123 Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
assets/profile_pictures/I21 Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
assets/profile_pictures/N Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1 @@
{"cmd": "import os\nimport secrets\nimport sqlite3\nfrom user_handler import UserHandler\nfrom werkzeug.datastructures.file_storage import FileStorage\n\n\nclass SolutionHandler:\n connection: sqlite3.Connection = sqlite3.connect(\"../data/database.db\", check_same_thread=False)\n cursor: sqlite3.Cursor = connection.cursor()\n\n # Save solution\n @classmethod\n def submit_solution(cls, files: list[FileStorage], bounty_identifier: int, creator_identifier: int):\n solution_id = secrets.token_urlsafe(40)\n for file in files:\n if not file.filename:\n file.filename = secrets.token_urlsafe(5)\n file.filename = file.filename.replace(\"/\", r\"|\")\n os.mkdir(f\"../assets/solutions/{solution_id}\")\n file.save(f\"../assets/solutions/{solution_id}/{file.filename}\")\n\n cls.cursor.execute(\n f\"\"\"\n INSERT INTO bounty_solutions(creator_identifier, bounty_identifier, identifier)\n values(?, ?, ?)\n \"\"\",\n (creator_identifier, bounty_identifier, solution_id)\n )\n cls.connection.commit()\n\n @staticmethod\n def __format_solution(paths: list[str]):\n pass\n\n # Get solution by id\n @staticmethod\n def get_solution_by_id(solution_id: str):\n path = f\"../assets/solutions/{solution_id}/\"\n if not os.path.isdir(path):\n raise KeyError(\"Solution doesn't exist\")\n formated_solutions: dict[str, str | dict] = {}\n file_paths = os.listdir(path)\n for file_path in file_paths:\n current_folder = formated_solutions\n for folder in file_path.split(\"|\")[:-1]:\n current_folder[folder] = {}\n current_folder = current_folder[folder]\n file_name = file_path.split(\"|\")[-1]\n try:\n with open(path + file_path, \"r\") as file:\n current_folder[file_name] = file.read()\n except UnicodeDecodeError:\n current_folder[file_name] = \"<NOT-TEXT>\"\n\n print(formated_solutions)\n \n\n @classmethod\n def get_solution_list(cls, identifier: int) -> list[dict]:\n solutions = cls.cursor.execute(\n f\"\"\"\n SELECT creator_identifier, identifier FROM bounty_solutions\n WHERE bounty_identifier = ?;\n \"\"\",\n (identifier, )\n ).fetchall()\n return [\n {\n \"creator_id\": solution[0],\n \"creator_display_name\": UserHandler.get_display_name(solution[0]),\n \"solution_id\": solution[1],\n \"likes\": cls.get_likes(solution[1])\n } for solution in solutions\n ]\n\n @classmethod\n def like(cls, solution_id: int, user_id: int):\n cls.cursor.execute(\n f\"\"\"\n INSERT INTO solution_likes(user_id, solution_id) values(?, ?)\n \"\"\",\n (user_id, solution_id)\n )\n cls.connection.commit()\n\n @classmethod\n def unlike(cls, solution_id: int, user_id: int):\n cls.cursor.execute(\n f\"\"\"\n DELETE FROM solution_likes WHERE solution_id = ? AND user_id = ?\n \"\"\",\n (solution_id, user_id)\n )\n cls.connection.commit()\n\n @classmethod\n def get_likes(cls, solution_id: int) -> int:\n likes = cls.cursor.execute(\n f\"\"\"\n SELECT COUNT(*) FROM solution_likes WHERE solution_id = ?\n \"\"\",\n (solution_id, )\n ).fetchall()[0]\n return likes[0] if likes else 0\n\n @classmethod\n def has_user_liked(cls, solution_id: int, user_id: int) -> bool:\n\n likes = cls.cursor.execute(\n f\"\"\"\n SELECT 1 FROM solution_likes WHERE solution_id = ?\n \"\"\",\n (solution_id, )\n ).fetchall()\n return bool(likes)\n\nSolutionHandler.get_solution_by_id(\"NvFlP3tsfJbYDTAOD5dHt4hEp2rLlsVEYizWhC39WwstnJWDosPKyQ\")", "cmd_opts": " --cell_id=NONE -s", "import_complete": 1, "terminal": "kitty"}

View File

@ -0,0 +1 @@
{"NONE": [{"output_type": "stream", "name": "stdout", "text": "{'GTXN1Una4AAvXHl.webp': '<NOT-TEXT>', 'test1': {'fdf.webp': 'Sfjdifjodi\\n'}, 'test2': {'test3': {'safdf.webp': 'fjidofjidfji\\n'}}}\n"}]}

View File

@ -0,0 +1 @@
{"NONE": [{"output_type": "stream", "name": "stdout", "text": "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mIntegrityError\u001b[0m Traceback (most recent call last)\nCell \u001b[0;32mIn[1], line 127\u001b[0m\n\u001b[1;32m 117\u001b[0m \u001b[38;5;28mcls\u001b[39m\u001b[38;5;241m.\u001b[39mget_user_by_handle(handle)\n\u001b[1;32m 118\u001b[0m \u001b[38;5;28mcls\u001b[39m\u001b[38;5;241m.\u001b[39mcursor\u001b[38;5;241m.\u001b[39mexecute(\n\u001b[1;32m 119\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\"\"\u001b[39m\n\u001b[1;32m 120\u001b[0m \u001b[38;5;124m UPDATE users\u001b[39m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 124\u001b[0m (display_name, handle )\n\u001b[1;32m 125\u001b[0m )\u001b[38;5;241m.\u001b[39mfetchall()\n\u001b[0;32m--> 127\u001b[0m \u001b[43mUserHandler\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcreate_user\u001b[49m\u001b[43m(\u001b[49m\u001b[43mUser\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mkos\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mkos\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mkos\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mkosh\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 128\u001b[0m UserHandler\u001b[38;5;241m.\u001b[39mchange_display_name(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mkos\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mkosh\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\nCell \u001b[0;32mIn[1], line 38\u001b[0m, in \u001b[0;36mUserHandler.create_user\u001b[0;34m(cls, user)\u001b[0m\n\u001b[1;32m 36\u001b[0m salt \u001b[38;5;241m=\u001b[39m bcrypt\u001b[38;5;241m.\u001b[39mgensalt()\n\u001b[1;32m 37\u001b[0m encrypted_password \u001b[38;5;241m=\u001b[39m bcrypt\u001b[38;5;241m.\u001b[39mhashpw(user\u001b[38;5;241m.\u001b[39mpassword\u001b[38;5;241m.\u001b[39mencode(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mutf-8\u001b[39m\u001b[38;5;124m\"\u001b[39m), salt)\n\u001b[0;32m---> 38\u001b[0m \u001b[38;5;28;43mcls\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcursor\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mexecute\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 39\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;124;43mf\u001b[39;49m\u001b[38;5;124;43m\"\"\"\u001b[39;49m\n\u001b[1;32m 40\u001b[0m \u001b[38;5;124;43m INSERT INTO users(handle, display_name, email, password)\u001b[39;49m\n\u001b[1;32m 41\u001b[0m \u001b[38;5;124;43m values(?, ?, ?, ?)\u001b[39;49m\n\u001b[1;32m 42\u001b[0m \u001b[38;5;124;43m \u001b[39;49m\u001b[38;5;124;43m\"\"\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 43\u001b[0m \u001b[43m \u001b[49m\u001b[43m(\u001b[49m\u001b[43muser\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mhandle\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43muser\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdisplay_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43muser\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43memail\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mencrypted_password\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 44\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 45\u001b[0m shutil\u001b[38;5;241m.\u001b[39mcopy(\n\u001b[1;32m 46\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m../assets/profile_pictures/default_profile_picture.jpg\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 47\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m../assets/profile_pictures/\u001b[39m\u001b[38;5;132;01m{\u001b[39;00muser\u001b[38;5;241m.\u001b[39mhandle\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 48\u001b[0m )\n\u001b[1;32m 49\u001b[0m \u001b[38;5;28mcls\u001b[39m\u001b[38;5;241m.\u001b[39mconnection\u001b[38;5;241m.\u001b[39mcommit()\n\n\u001b[0;31mIntegrityError\u001b[0m: UNIQUE constraint failed: users.handle\n"}]}

View File

@ -0,0 +1,147 @@
from dataclasses import dataclass
import sqlite3
@dataclass
class Bounty:
bounty_id: int
user_id: int
title: str
description: str
languages: str
field: str
def __init__(
self,
bounty_id: int,
user_id: int,
title: str,
description: str,
languages: str,
field: str,
) -> None:
self.bounty_id = bounty_id
self.user_id = user_id
self.title = title
self.description = description
self.languages = languages
self.field = field
class BountyHandler:
connection: sqlite3.Connection = sqlite3.connect("../data/database.db", check_same_thread=False)
cursor: sqlite3.Cursor = connection.cursor()
# Create Bounty
@classmethod
def create_bounty(
cls,
bounty: Bounty
) -> None:
bounty.languages.removeprefix(",")
bounty.languages.removesuffix(",")
print(bounty.languages)
assert set(bounty.languages.split(",")).issubset(
{"c", "cpp", "c#", "css", "go", "html", "java", "js", "python", "ruby", "rust", "other", "any"}
)
assert set(bounty.field.split(",")).issubset(
{"dsa", "ai", "web", "app", "other"}
)
cls.cursor.execute(
f"""
INSERT INTO bounties(user_id, title, description, languages, field)
values(?, ?, ?, ?, ?)
""",
(bounty.bounty_id, bounty.title, bounty.description, bounty.languages, bounty.field)
)
cls.connection.commit()
# Get Bounty
@classmethod
def get_bounty_by_id(cls, bounty_id: int) -> Bounty:
bounties = cls.cursor.execute(
f"""
SELECT user_id, title, description, languages, field
FROM bounties WHERE bounty_id = ?;
""",
(bounty_id, )
).fetchall()
if not bounties:
raise KeyError(f"{bounty_id} does not exist!")
bounty = bounties[0]
return Bounty(
bounty_id=bounty_id,
user_id=bounty[0],
title=bounty[1],
description=bounty[2],
languages=bounty[3],
field=bounty[4],
)
# Get random bounties
@classmethod
def get_randomized_bounty_list(cls):
responses = cls.cursor.execute(
f"""
SELECT bounty_id, user_id, title, description, languages, field FROM bounties ORDER BY RANDOM();
"""
).fetchall()
bounties: list[Bounty] = []
for response in responses:
bounties.append(Bounty(
bounty_id=response[0],
user_id=response[1],
title=response[2],
description=response[3],
languages=response[4],
field=response[5],
))
return bounties
# Rate
@classmethod
def rate(cls, bounty_id: int, user_id: int, rating: int) -> None:
cls.cursor.execute(
f"""
INSERT INTO bounty_ratings(bounty_id, user_id, rating)
values(?, ?, ?)
""",
(bounty_id, user_id, rating)
)
cls.connection.commit()
# Get Rating
@classmethod
def get_sum_of_ratings(cls, bounty_id: int) -> int:
sum_of_ratings: int = cls.cursor.execute(
f"""
SELECT SUM(rating)
FROM bounty_ratings WHERE bounty_id = ?;
""",
(bounty_id,)
).fetchall()[0][0]
return sum_of_ratings if sum_of_ratings else 0
# Get number of Rating
@classmethod
def get_number_of_ratings(cls, bounty_id: int) -> int:
sum_of_ratings: int = cls.cursor.execute(
f"""
SELECT COUNT()
FROM bounty_ratings WHERE bounty_id = ?;
""",
(bounty_id,)
).fetchall()[0][0]
return sum_of_ratings if sum_of_ratings else -1
# Get rater's Rating
@classmethod
def get_rating_of_user(cls, user_id: int, bounty_id: int) -> int:
sum_of_ratings: int = cls.cursor.execute(
f"""
SELECT SUM(rating)
FROM bounty_ratings WHERE bounty_id = ? AND user_id = ?;
""",
(bounty_id, user_id)
).fetchall()[0][0]
return sum_of_ratings if sum_of_ratings else -2

View File

@ -0,0 +1,140 @@
Legend:
Form data:
https://developer.mozilla.org/en-US/docs/Web/API/FormData
[something] : this something is optional
---------- USER HANDLING ----------
POST : /get-user-by-email
Form data:
email
return type:
{
"handle": "~",
"display_name": "~"
}
Errors:
422 : email missing in request
404 : email not found
POST : /get-user-by-id
Form data:
id
return type:
{
"handle": "~",
"display_name": "~"
}
Errors:
422 : id missing in request
404 : id not found
POST : /get-user-by-handle
Form Data:
handle
return type:
{
"handle": "~",
"display_name": "~"
}
Errors:
422 : handle missing in request
404 : handle not found
POST : /register
Form Data:
email
handle
password
[display_name]
[profile_picture]
Errors:
422 : something missing in request
409 : User exists (email or handle)
POST : /login
Form Data:
email
password
Errors:
422 : something missing in request
404 : User does not exist
409 : Wrong password
Cookies:
sets id
sets session_id
POST : /logout
Errors:
401 : Not logged in
Cookies:
deletes session_id
deletes id
POST : /change-user-profile-picture
Form Data:
image
Errors:
401 : Not logged in
403 : Invalid log in
422 : image is missing
Note:
Must be logged in
POST : /change-user-display-name
Form Data:
display_name
Errors:
401 : Not logged in
403 : Invalid log in
422 : display_name is missing
Note:
Must be logged in
GET : /profile-picture/<handle>
Errors:
404 : Handle not found
---------- BOUNTY HANDLING ----------
POST : /create-bounty
Form Data:
title
description
[field]
[language]
Errors:
422 : something missing in request
403 : Unknown language/ field
Note:
default language = "any"
default field = "other"
POST : /get-user-by-id
Form data:
id
return type:
{
"handle": "~",
"display_name": "~"
}
Errors:
422 : id missing in request
404 : id not found
POST : /create-session-for-bounty-get-random
Cookies:
sets bounty_session_id
POST : /bounty-get-random
Form data:
page_number
Note:
/create-session-for-bounty-get-random must be called before this
Errors:
422 : page no. missing in request
404 : /create-session-for-bounty-get-random not called

View File

@ -0,0 +1,419 @@
import json
import flask
import sqlite3
from werkzeug.datastructures.file_storage import FileStorage
from solution_handler import SolutionHandler
from user_handler import UserHandler, User
from bounty_handler import BountyHandler, Bounty
app = flask.Flask(__name__)
app.secret_key = "few`3r9i3r"
app.config['SESSION_TYPE'] = 'filesystem'
@app.get("/")
def a():
return flask.send_file("../assets/apifiletest/index.html")
# ---------- USER ----------
@app.get("/index.js")
def an():
return flask.send_file("../assets/apifiletest/index.js")
#@app.post("/get-user-by-email")
#def get_user_by_email() -> flask.Response:
# request_data = dict(flask.request.form)
# if "email" not in request_data:
# return flask.Response("email or password missing", status=422)
# try:
# user = UserHandler.get_user_by_email(
# request_data["email"],
# )
# except KeyError:
# return flask.Response("User does not exist", status=404)
# return flask.Response(
# response=json.dumps({
# "handle": user.handle,
# "display_name": user.display_name,
# }),
# status=200,
# mimetype='application/json'
# )
#
#
@app.post("/get-user-by-id")
def get_user_by_id() -> flask.Response:
request_data = dict(flask.request.form)
try:
user_id = int(request_data["user_id"])
except KeyError:
return flask.Response("user_id missing", status=422)
except ValueError:
return flask.Response("user_id wasn't int", status=422)
try:
user = UserHandler.get_user_by_id(user_id)
except KeyError:
return flask.Response("User does not exist", status=404)
return flask.Response(
response=json.dumps({
"handle": user.handle,
"display_name": user.display_name,
}),
status=200,
mimetype='application/json'
)
@app.post("/get-user-by-handle")
def get_user_by_handle() -> flask.Response:
request_data = dict(flask.request.form)
try:
handle = request_data["handle"]
except KeyError:
return flask.Response("handle or password missing", status=422)
try:
user = UserHandler.get_user_by_handle(handle)
except KeyError:
return flask.Response("User does not exist", status=404)
return flask.Response(
response=json.dumps({
"handle": user.handle,
"display_name": user.display_name,
}),
status=200,
mimetype='application/json'
)
@app.post("/register")
def register() -> flask.Response:
request_data = dict(flask.request.form)
try:
email = request_data["email"]
handle = request_data["handle"]
password = request_data["password"]
except KeyError:
return flask.Response("email, handle or password missing", status=422)
if "display_name" not in request_data:
request_data["display_name"] = request_data["handle"]
try:
UserHandler.create_user(
User(
-1,
email,
request_data["handle"],
request_data["password"],
request_data["display_name"],
)
)
except sqlite3.IntegrityError as error:
if "handle" in str(error):
return flask.Response("Handle exists", status=409)
else:
return flask.Response("Email exists", status=409)
if "profile_picture" in flask.request.files:
flask.request.files["profile_picture"].save(f"../assets/profile_pictures/{request_data['handle']}")
return flask.Response(status=200)
@app.post("/validate-login")
def validate_login():
if "user_id" not in flask.session:
return flask.Response("Authentication error", status=401)
if not isinstance(flask.session["user_id"], int):
return flask.Response("Authentication error", status=401)
return flask.Response(status=200)
@app.post("/login")
def login() -> flask.Response:
request_data = dict(flask.request.form)
try:
email = request_data["email"]
password = request_data["password"]
except KeyError:
return flask.Response("email or password missing", status=422)
try:
assert UserHandler.verify_password_by_email(email, password)
except KeyError:
return flask.Response("User does not exist", status=404)
except AssertionError:
return flask.Response("Wrong password", status=409)
user = UserHandler.get_user_by_email(request_data["email"])
flask.session["user_id"] = user.user_id
return flask.Response(status=200)
@app.post("/logout")
def logout() -> flask.Response:
if "user_id" not in flask.session:
return flask.Response("Authentication error", status=401)
flask.session.pop("user_id")
return flask.Response(status=200)
@app.post("/change-user-profile-picture")
def change_user_profile_picture() -> flask.Response:
login_validation = validate_login()
if login_validation.status_code != 200:
return login_validation
try:
image = flask.request.files["image"]
except KeyError:
return flask.Response("image is missing", status=422)
image_name = UserHandler.get_user_by_id(flask.session["user_id"]).handle
image.save(
f"../assets/profile_pictures/{image_name}"
)
return flask.Response(status=200)
@app.post("/change-user-display-name")
def change_user_display_name():
login_validation = validate_login()
if login_validation.status_code != 200:
return login_validation
request_data = dict(flask.request.form)
if "display_name" not in request_data:
return flask.Response("display_name is missing", status=422)
UserHandler.change_display_name(flask.session["user_id"], request_data["display_name"])
return flask.Response(status=200)
@app.get("/profile-picture/<handle>")
def get_profile_picture(handle: str) -> flask.Response:
try:
return flask.send_file(f"../assets/profile_pictures/{handle}")
except FileNotFoundError:
return flask.Response(f"{handle} does not exist", 404)
# ---------- BOUNTY ----------
@app.post("/create-bounty")
def create_bounty() -> flask.Response:
request_data = dict(flask.request.form)
login_validation = validate_login()
if login_validation.status_code != 200:
return login_validation
if "title" not in request_data or \
"description" not in request_data:
return flask.Response("title or description is missing", status=422)
if "field" not in request_data:
request_data["field"] = "other"
if "languages" not in request_data:
request_data["language"] = "any"
try:
BountyHandler.create_bounty(Bounty(
-1,
flask.session["user_id"],
request_data["title"],
request_data["description"],
languages=request_data["languages"],
field=request_data["field"]
))
return flask.Response(status=200)
except AssertionError:
return flask.Response("Unknown language/ field", status=403)
@app.post("/get-bounty-by-id")
def bounty_get_by_id() -> flask.Response:
login_validation = validate_login()
user_id = -1
if login_validation.status_code == 200:
user_id = flask.session["user_id"]
request_data = dict(flask.request.form)
if "bounty_id" not in request_data:
return flask.Response("bounty_id is missing", status=422)
try:
bounty_id = int(request_data["bounty_id"])
except ValueError:
return flask.Response("user_id wasn't int", status=422)
try:
bounty = BountyHandler.get_bounty_by_id(bounty_id)
except KeyError:
return flask.Response("Doesn't exist", status=404)
number_of_ratings: int = BountyHandler.get_number_of_ratings(bounty_id)
return flask.Response(
response=json.dumps({
"title": bounty.title,
"description": bounty.description,
"languages": bounty.languages,
"field": bounty.field,
"average_rating": BountyHandler.get_sum_of_ratings(bounty_id) / number_of_ratings,
"number_of_ratings": number_of_ratings,
"users_rating": BountyHandler.get_rating_of_user(user_id, bounty.bounty_id),
}),
status=200,
mimetype='application/json'
)
@app.post("/create-session-for-bounty-get-random")
def create_session_for_bounty_get_random() -> flask.Response:
login_validation = validate_login()
rater_id = -1
if login_validation.status_code == 200:
rater_id = flask.session["user_id"]
bounties = BountyHandler.get_randomized_bounty_list()
bounties = [
{
"id": bounty.bounty_id,
"creator_identifie": bounty.user_id,
"title": bounty.title,
"description": bounty.description,
"languages": bounty.languages,
"field": bounty.field,
"average_rating": BountyHandler.get_sum_of_ratings(bounty.bounty_id) /\
BountyHandler.get_number_of_ratings(bounty.bounty_id),
"number_of_ratings": BountyHandler.get_number_of_ratings(bounty.bounty_id),
"users_rating": BountyHandler.get_rating_of_user(rater_id, bounty.bounty_id),
} for bounty in bounties
]
flask.session["bounties"] = bounties
response = flask.Response(status=200)
return response
@app.post("/bounty-get-random")
def bounty_get_random() -> flask.Response:
request_data = dict(flask.request.form)
if "bounties" not in flask.session:
return flask.Response("/create-session-for-bounty-get-random not called", status=401)
try:
page_number = int(request_data["page_number"])
except KeyError:
return flask.Response("page_number is missing", status=422)
except ValueError:
return flask.Response("page_number wasn't int", status=422)
return flask.Response(
response=json.dumps(
flask.session["bounties"][page_number * 20 : (page_number + 1) * 20]
),
status=200,
mimetype='application/json'
)
@app.post("/bounty-rate")
def bounty_rate() -> flask.Response:
request_data = dict(flask.request.form)
login_validation = validate_login()
if login_validation.status_code != 200:
return login_validation
try:
BountyHandler.rate(
int(request_data["bounty_id"]),
flask.session["user_id"],
int(request_data["rating"]),
)
except sqlite3.IntegrityError:
return flask.Response("Rating gotta be between 1 and 10", status=403)
except ValueError:
return flask.Response("bounty_id or rating wasn't int", status=422)
except KeyError:
return flask.Response("bounty_id or rating missing", status=422)
return flask.Response(status=200)
# ---------- SOLUTIONS ----------
@app.post("/test")
def test():
files = flask.request.files.getlist("files")
for file in files:
if file.filename:
file.filename = file.filename.replace("/", r"|")
file.save(f"../assets/{file.filename}")
else:
return flask.Response(status=400)
return flask.Response()
@app.post("/submit-solution")
def submit_answer() -> flask.Response:
request_data = dict(flask.request.form)
login_validation = validate_login()
if login_validation.status_code != 200:
return login_validation
user_id = flask.session["user_id"]
try:
bounty_id = int(request_data["bounty_id"])
except KeyError:
return flask.Response("Bounty id missing", status=422)
except ValueError:
return flask.Response("bounty_id wasn't int", status=422)
files : list[FileStorage]= flask.request.files.getlist("files")
if not files:
return flask.Response("files missing", status=422)
SolutionHandler.submit_solution(files, bounty_id, user_id)
return flask.Response()
@app.post("/get-solution-by-id")
def get_solution_by_id() -> flask.Response:
request_data = dict(flask.request.form)
try:
solution_id = request_data["solution_id"]
except KeyError:
return flask.Response("Solution id missing", status=422)
try:
return flask.jsonify(SolutionHandler.get_solution_by_id(solution_id))
except KeyError:
return flask.Response("Solution doesn't exist", status=404)
@app.post("/get-solution-list")
def get_solution_list() -> flask.Response:
request_data = dict(flask.request.form)
try:
solution_id = int(request_data["bounty_id"])
except KeyError:
return flask.Response("Bounty id missing", status=422)
except ValueError:
return flask.Response("bounty_id wasn't int", status=422)
return flask.jsonify(SolutionHandler.get_solution_list(solution_id))
@app.post("/like-solution")
def like_solution() -> flask.Response:
request_data = dict(flask.request.form)
login_validation = validate_login()
if login_validation.status_code != 200:
return login_validation
try:
solution_id = request_data["solution_id"]
user_id = flask.session["user_id"]
except KeyError:
return flask.Response("Solution id missing", status=422)
SolutionHandler.like(solution_id=solution_id, user_id=user_id)
return flask.Response(status=200)
@app.post("/unlike-solution")
def unlike_solution() -> flask.Response:
request_data = dict(flask.request.form)
login_validation = validate_login()
if login_validation.status_code != 200:
return login_validation
try:
solution_id = request_data["solution_id"]
user_id = flask.session["user_id"]
except KeyError:
return flask.Response("Solution id missing", status=422)
SolutionHandler.unlike(solution_id=solution_id, user_id=user_id)
return flask.Response(status=200)
@app.post("/has-user-liked")
def has_user_liked() -> flask.Response:
request_data = dict(flask.request.form)
login_validation = validate_login()
if login_validation.status_code != 200:
return login_validation
try:
solution_id = request_data["solution_id"]
user_id = flask.session["user_id"]
except KeyError:
return flask.Response("Solution id missing", status=422)
return flask.jsonify(SolutionHandler.has_user_liked(user_id=user_id, solution_id=solution_id))

View File

@ -0,0 +1,116 @@
import os
import secrets
import sqlite3
from user_handler import UserHandler
from werkzeug.datastructures.file_storage import FileStorage
import re
class SolutionHandler:
connection: sqlite3.Connection = sqlite3.connect("../data/database.db", check_same_thread=False)
cursor: sqlite3.Cursor = connection.cursor()
# Save solution
@classmethod
def submit_solution(cls, files: list[FileStorage], bounty_identifier: int, creator_identifier: int):
solution_id = secrets.token_urlsafe(40)
os.mkdir(f"../assets/solutions/{solution_id}/")
for file in files:
print(file.filename)
if not file.filename:
file.filename = secrets.token_urlsafe(5)
file.filename = "".join(re.findall("[a-zA-Z 0-9-./]", file.filename))
file.filename = file.filename.replace("/", r"|")
file.save(f"../assets/solutions/{solution_id}/{file.filename}")
cls.cursor.execute(
f"""
INSERT INTO solutions(user_id, bounty_id, solution_id)
values(?, ?, ?)
""",
(creator_identifier, bounty_identifier, solution_id)
)
cls.connection.commit()
# Get solution by id
@staticmethod
def get_solution_by_id(solution_id: str):
path = f"../assets/solutions/{solution_id}/"
if not os.path.isdir(path):
raise KeyError("Solution doesn't exist")
formated_solutions: dict[str, str | dict] = {}
file_paths = os.listdir(path)
for file_path in file_paths:
current_folder = formated_solutions
for folder in file_path.split("|")[:-1]:
print(folder)
current_folder[folder] = {}
current_folder: dict = current_folder[folder]
file_name = file_path.split("|")[-1]
try:
with open(path + file_path, "r") as file:
current_folder[file_name] = file.read()
except UnicodeDecodeError:
current_folder[file_name] = "<NOT-TEXT>"
return formated_solutions
@classmethod
def get_solution_list(cls, identifier: int) -> list[dict]:
solutions = cls.cursor.execute(
f"""
SELECT user_id, solution_id FROM solutions
WHERE bounty_id = ?;
""",
(identifier, )
).fetchall()
return [
{
"user_id": solution[0],
"creator_display_name": UserHandler.get_display_name(solution[0]),
"solution_id": solution[1],
"likes": cls.get_likes(solution[1])
} for solution in solutions
]
@classmethod
def like(cls, solution_id: int, user_id: int):
cls.cursor.execute(
f"""
INSERT INTO solution_likes(user_id, solution_id) values(?, ?)
""",
(user_id, solution_id)
)
cls.connection.commit()
@classmethod
def unlike(cls, solution_id: int, user_id: int):
cls.cursor.execute(
f"""
DELETE FROM solution_likes WHERE solution_id = ? AND user_id = ?
""",
(solution_id, user_id)
)
cls.connection.commit()
@classmethod
def get_likes(cls, solution_id: int) -> int:
likes = cls.cursor.execute(
f"""
SELECT COUNT(*) FROM solution_likes WHERE solution_id = ?
""",
(solution_id, )
).fetchall()[0]
return likes[0] if likes else 0
@classmethod
def has_user_liked(cls, solution_id: int, user_id: int) -> bool:
likes = cls.cursor.execute(
f"""
SELECT 1 FROM solution_likes WHERE solution_id = ?
""",
(solution_id, )
).fetchall()
return bool(likes)

View File

@ -0,0 +1,154 @@
import bcrypt
import shutil
from dataclasses import dataclass
import sqlite3
@dataclass
class User:
user_id: int
email: str
handle: str
password: str
display_name: str
def __init__(
self,
user_id: int,
email: str,
handle: str,
password: str = "",
display_name: str = "",
) -> None:
self.user_id: int = user_id
self.handle = handle
self.password = password
self.display_name = display_name if display_name else handle
self.email = email
class UserHandler:
connection: sqlite3.Connection = sqlite3.connect("../data/database.db", check_same_thread=False)
cursor: sqlite3.Cursor = connection.cursor()
@classmethod
def create_user(
cls,
user: User
) -> None:
salt = bcrypt.gensalt()
encrypted_password = bcrypt.hashpw(user.password.encode("utf-8"), salt)
cls.cursor.execute(
f"""
INSERT INTO users(handle, display_name, email, password)
values(?, ?, ?, ?)
""",
(user.handle, user.display_name, user.email, encrypted_password)
)
cls.connection.commit()
shutil.copy(
"../assets/profile_pictures/default_profile_picture.jpg",
f"../assets/profile_pictures/{user.handle}"
)
@classmethod
def get_user_by_id(cls, user_id: int) -> User:
users = cls.cursor.execute(
f"""
SELECT handle, display_name
FROM users WHERE user_id = ?;
""",
(user_id, )
).fetchall()
if not users:
raise KeyError(f"{user_id} does not exist!")
user = users[0]
return User(
user_id=user_id,
handle=user[0],
display_name=user[1],
email="",
password=""
)
@classmethod
def get_user_by_handle(cls, handle: str) -> User:
users = cls.cursor.execute(
f"""
SELECT user_id, handle, display_name
FROM users WHERE handle = ?;
""",
(handle, )
).fetchall()
if not users:
raise KeyError(f"{handle} does not exist!")
users = users[0]
return User(
user_id=users[0],
handle=users[1],
display_name=users[2],
email="",
password=""
)
@classmethod
def get_user_by_email(cls, email: str) -> User:
users = cls.cursor.execute(
f"""
SELECT user_id, handle, display_name
FROM users WHERE email = ?;
""",
(email, )
).fetchall()
if not users:
raise KeyError(f"{email} does not exist!")
users = users[0]
return User(
user_id=users[0],
handle=users[1],
display_name=users[2],
email=email,
password="",
)
#@classmethod
#def verify_password_by_handle(cls, handle: str, password: str) -> bool:
# users = cls.cursor.execute(
# f"""
# SELECT password
# FROM users WHERE handle = ?;
# """,
# (handle, )
# ).fetchall()
# if not users:
# raise KeyError(f"{handle} does not exist!")
# real_password = users[0][0]
# return bcrypt.checkpw(password.encode("utf-8"), real_password)
@classmethod
def verify_password_by_email(cls, email: str, password: str) -> bool:
users = cls.cursor.execute(
f"""
SELECT password
FROM users WHERE email = ?;
""",
(email, )
).fetchall()
if not users:
raise KeyError(f"{email} does not exist!")
return bcrypt.checkpw(password.encode("utf-8"), users[0][0])
@classmethod
def change_display_name(cls, user_id: int, display_name: str):
cls.cursor.execute(
f"""
UPDATE users
SET display_name = ?
WHERE user_id = ?;
""",
(display_name, user_id)
).fetchall()
@classmethod
def get_display_name(cls, user_id: int) -> str:
return cls.get_user_by_id(user_id).display_name

Some files were not shown because too many files have changed in this diff Show More