updated db schema for attachments + add create user api endpoint
This commit is contained in:
1 parent
e6d3f5c7b7
commit
af7d682a38
8 files changed
+91
-9
No files matched your search
+10
@@ -3,6 +3,7 @@ CREATE TABLE IF NOT EXISTS "messages" (
|
|||||||
"user" INTEGER NOT NULL,
|
"user" INTEGER NOT NULL,
|
||||||
"thread" INTEGER NOT NULL,
|
"thread" INTEGER NOT NULL,
|
||||||
"content" TEXT NOT NULL,
|
"content" TEXT NOT NULL,
|
||||||
|
"time" INTEGER NOT NULL,
|
||||||
PRIMARY KEY("id"),
|
PRIMARY KEY("id"),
|
||||||
FOREIGN KEY ("user") REFERENCES "users"("id")
|
FOREIGN KEY ("user") REFERENCES "users"("id")
|
||||||
ON UPDATE NO ACTION ON DELETE NO ACTION,
|
ON UPDATE NO ACTION ON DELETE NO ACTION,
|
||||||
@@ -13,6 +14,7 @@ CREATE TABLE IF NOT EXISTS "messages" (
|
|||||||
CREATE TABLE IF NOT EXISTS "users" (
|
CREATE TABLE IF NOT EXISTS "users" (
|
||||||
"id" INTEGER NOT NULL UNIQUE,
|
"id" INTEGER NOT NULL UNIQUE,
|
||||||
"name" TEXT NOT NULL,
|
"name" TEXT NOT NULL,
|
||||||
|
"passhash" TEXT NOT NULL,
|
||||||
PRIMARY KEY("id")
|
PRIMARY KEY("id")
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -41,3 +43,11 @@ CREATE TABLE IF NOT EXISTS "threads" (
|
|||||||
ON UPDATE NO ACTION ON DELETE NO ACTION
|
ON UPDATE NO ACTION ON DELETE NO ACTION
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "attachments" (
|
||||||
|
"id" INTEGER NOT NULL UNIQUE,
|
||||||
|
"message_id" INTEGER NOT NULL,
|
||||||
|
"file_path" TEXT NOT NULL,
|
||||||
|
PRIMARY KEY("id"),
|
||||||
|
FOREIGN KEY ("message_id") REFERENCES "messages"("id")
|
||||||
|
ON UPDATE NO ACTION ON DELETE NO ACTION
|
||||||
|
);
|
||||||
@@ -26,10 +26,10 @@ def send_message() -> tuple[str, int]:
|
|||||||
if any([not p in data for p in ['content', 'thread']]):
|
if any([not p in data for p in ['content', 'thread']]):
|
||||||
return '', 400
|
return '', 400
|
||||||
|
|
||||||
new_message = database.MessageORM(
|
new_message = database.MessageDTO(
|
||||||
user=flask_login.current_user.get_id(),
|
user_id=flask_login.current_user.get_id(),
|
||||||
content=data['content'],
|
content=data['content'],
|
||||||
thread=data['thread'],
|
thread_id=data['thread'],
|
||||||
time=int(time.time())
|
time=int(time.time())
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -23,3 +23,43 @@ def get_user_forums() -> tuple[flask.Response, int]:
|
|||||||
forums_dict = {"forums" : [dataclasses.asdict(forum) for forum in forums]}
|
forums_dict = {"forums" : [dataclasses.asdict(forum) for forum in forums]}
|
||||||
|
|
||||||
return flask.jsonify(forums_dict), 200
|
return flask.jsonify(forums_dict), 200
|
||||||
|
|
||||||
|
|
||||||
|
@user.route('/create', methods=['POST'])
|
||||||
|
def create_user() -> tuple[flask.Response, int]:
|
||||||
|
"""
|
||||||
|
Create a new user account.
|
||||||
|
Expects JSON with 'username' and 'password' fields.
|
||||||
|
"""
|
||||||
|
data = flask.request.get_json()
|
||||||
|
|
||||||
|
if not data:
|
||||||
|
return flask.jsonify({"error": "No JSON data provided"}), 400
|
||||||
|
|
||||||
|
username = data.get('username')
|
||||||
|
password = data.get('password')
|
||||||
|
|
||||||
|
if not username or not password:
|
||||||
|
return flask.jsonify({"error": "Username and password are required"}), 400
|
||||||
|
|
||||||
|
# Validate username length and characters
|
||||||
|
if len(username.strip()) == 0:
|
||||||
|
return flask.jsonify({"error": "Username cannot be empty"}), 400
|
||||||
|
|
||||||
|
if len(password) < 6:
|
||||||
|
return flask.jsonify({"error": "Password must be at least 6 characters long"}), 400
|
||||||
|
|
||||||
|
# Attempt to create the user
|
||||||
|
new_user = database.create_user(username.strip(), password)
|
||||||
|
|
||||||
|
if new_user is None:
|
||||||
|
return flask.jsonify({"error": "Username already exists or creation failed"}), 409
|
||||||
|
|
||||||
|
# Return the created user (without sensitive data)
|
||||||
|
user_dict = {
|
||||||
|
"id": new_user.id,
|
||||||
|
"name": new_user.name,
|
||||||
|
"message": "User created successfully"
|
||||||
|
}
|
||||||
|
|
||||||
|
return flask.jsonify(user_dict), 201
|
||||||
+32
-5
@@ -7,7 +7,7 @@ import flask_login
|
|||||||
|
|
||||||
import mgU
|
import mgU
|
||||||
|
|
||||||
DATABASE = "./main2.db"
|
DATABASE = "./main.db"
|
||||||
|
|
||||||
ph = argon2.PasswordHasher()
|
ph = argon2.PasswordHasher()
|
||||||
|
|
||||||
@@ -46,21 +46,48 @@ class UserDTO:
|
|||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class MessageDTO:
|
class MessageDTO:
|
||||||
user: UserDTO
|
user_id: UserDTO
|
||||||
content: str
|
content: str
|
||||||
time: int
|
time: int
|
||||||
thread_id: int
|
thread_id: int
|
||||||
id: int | None = None
|
id: int | None = None
|
||||||
|
|
||||||
def insert_message(message: mgU.Message) -> None:
|
def create_user(username: str, password: str) -> mgU.User | None:
|
||||||
|
"""
|
||||||
|
Create a new user with the given username and password.
|
||||||
|
Returns the created User object with id, or None if creation fails.
|
||||||
|
"""
|
||||||
|
# Hash the password
|
||||||
|
passhash = ph.hash(password)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with Opener() as (conn, cur):
|
||||||
|
q = load_query("insert_user")
|
||||||
|
cur.execute(q, [username, passhash])
|
||||||
|
user_id = cur.lastrowid
|
||||||
|
|
||||||
|
return mgU.User(name=username, id=user_id)
|
||||||
|
except sqlite3.IntegrityError:
|
||||||
|
# Username already exists or other constraint violation
|
||||||
|
return None
|
||||||
|
|
||||||
|
def insert_message(message: mgU.Message | MessageDTO) -> None:
|
||||||
"""
|
"""
|
||||||
Insert a new message (from mgU.Message dataclass) and return a new mgU.Message with id, or None on failure.
|
Insert a new message (from mgU.Message dataclass) and return a new mgU.Message with id, or None on failure.
|
||||||
"""
|
"""
|
||||||
|
if type(message) == mgU.Message:
|
||||||
|
thread_id = message.thread
|
||||||
|
user_id = message.user.id
|
||||||
|
elif type(message) == MessageDTO:
|
||||||
|
thread_id = message.thread_id
|
||||||
|
user_id = message.user_id
|
||||||
|
|
||||||
|
|
||||||
with Opener() as (conn, cur):
|
with Opener() as (conn, cur):
|
||||||
q = load_query("insert_message")
|
q = load_query("insert_message")
|
||||||
cur.execute(q, [
|
cur.execute(q, [
|
||||||
message.user,
|
user_id,
|
||||||
message.thread,
|
thread_id,
|
||||||
message.content,
|
message.content,
|
||||||
message.time
|
message.time
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"username" : "johndoe",
|
||||||
|
"password" : "securepassword123"
|
||||||
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
import typing
|
|
||||||
import dataclasses
|
import dataclasses
|
||||||
|
|
||||||
@dataclasses.dataclass(kw_only=True)
|
@dataclasses.dataclass(kw_only=True)
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
INSERT INTO users (name, passhash)
|
||||||
|
VALUES (?, ?);
|
||||||
Reference in new issue
Block a user