diff --git a/delivery1/server/app.py b/delivery1/server/app.py index 0bcbb7e..832351a 100644 --- a/delivery1/server/app.py +++ b/delivery1/server/app.py @@ -1,7 +1,7 @@ from flask import Flask from routes import org_bp, user_bp, file_bp from database import db_connection -from models import Organization, User, File +from models import Organization, User, File, Session app = Flask(__name__) app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///database.db" @@ -16,5 +16,12 @@ app.register_blueprint(org_bp, url_prefix="/org") app.register_blueprint(user_bp, url_prefix="/user") app.register_blueprint(file_bp, url_prefix="/file") +@app.route("/reset") +def reset(): + with app.app_context(): + db_connection.drop_all() + db_connection.create_all() + return "Database reset" + if __name__ == "__main__": app.run(debug=True) \ No newline at end of file diff --git a/delivery1/server/models/__init__.py b/delivery1/server/models/__init__.py index d5b6a1b..91a825f 100644 --- a/delivery1/server/models/__init__.py +++ b/delivery1/server/models/__init__.py @@ -1,3 +1,4 @@ from .user import * from .org import * -from .file import * \ No newline at end of file +from .file import * +from .session import * \ No newline at end of file diff --git a/delivery1/server/models/session.py b/delivery1/server/models/session.py new file mode 100644 index 0000000..5f128ab --- /dev/null +++ b/delivery1/server/models/session.py @@ -0,0 +1,21 @@ +from database import db_connection + +class Session(db_connection.Model): + __tablename__ = 'sessions' + + id = db_connection.Column(db_connection.Integer, primary_key=True) + user_id = db_connection.Column(db_connection.Integer, db_connection.ForeignKey('users.id')) + org_id = db_connection.Column(db_connection.Integer, db_connection.ForeignKey('organizations.id')) + token = db_connection.Column(db_connection.String(255), unique=True) + created_at = db_connection.Column(db_connection.DateTime, server_default=db_connection.func.now()) + updated_at = db_connection.Column(db_connection.DateTime, server_default=db_connection.func.now(), server_onupdate=db_connection.func.now()) + + def to_dict(self): + return { + "id": self.id, + "user_id": self.user_id, + "org_id": self.org_id, + "token": self.token, + "created_at": self.created_at, + "updated_at": self.updated_at + } diff --git a/delivery1/server/models/user.py b/delivery1/server/models/user.py index 13b9a0e..499856b 100644 --- a/delivery1/server/models/user.py +++ b/delivery1/server/models/user.py @@ -1,3 +1,4 @@ +from flask_sqlalchemy import SQLAlchemy from database import db_connection @@ -8,7 +9,7 @@ class User(db_connection.Model): username = db_connection.Column(db_connection.String, unique=True, index=True, nullable=False) full_name = db_connection.Column(db_connection.String, nullable=False) email = db_connection.Column(db_connection.String, unique=True, index=True, nullable=False) - public_key = db_connection.Column(db_connection.String, nullable=False) + public_keys = db_connection.Column(db_connection.JSON, nullable=False, default=dict) orgs = db_connection.relationship('Organization', back_populates='owner') files = db_connection.relationship('File', back_populates='creator') @@ -18,7 +19,7 @@ class User(db_connection.Model): "username": self.username, "full_name": self.full_name, "email": self.email, - "public_key": self.public_key, + "public_keys": [{"org_id": org_id, "key": public_key} for org_id, public_key in self.public_keys.items()], "orgs": [{"id": org.id, "name": org.name} for org in self.orgs], "files": [{"id": file.id, "name": file.name, "file_handle": file.file_handle} for file in self.files] } \ No newline at end of file diff --git a/delivery1/server/routes/org.py b/delivery1/server/routes/org.py index db8d3dc..88e4ba0 100644 --- a/delivery1/server/routes/org.py +++ b/delivery1/server/routes/org.py @@ -4,8 +4,15 @@ from services import OrganizationService org_bp = Blueprint("org", __name__) @org_bp.route("/create", methods=["POST"]) -def create(): +def org_create(): data = request.json + if "name" not in data or "username" not in data or "full_name" not in data or "email" not in data or "public_key" not in data: + return jsonify({"error": "Missing required fields"}), 400 + + existing_org = OrganizationService.get_organization_by_name(data["name"]) + if existing_org: + return jsonify({"error": "Organization already exists"}), 400 + org = OrganizationService.create_organization( name=data["name"], username=data["username"], @@ -13,4 +20,10 @@ def create(): email=data["email"], public_key=data["public_key"] ) + return jsonify(org.to_dict()), 201 + +@org_bp.route("/list", methods=["GET"]) +def org_list(): + orgs = OrganizationService.list_organizations() + return jsonify([org.to_dict() for org in orgs]) diff --git a/delivery1/server/routes/user.py b/delivery1/server/routes/user.py index 2db0730..3df87ae 100644 --- a/delivery1/server/routes/user.py +++ b/delivery1/server/routes/user.py @@ -1,4 +1,25 @@ from flask import Blueprint, request, jsonify -from services import UserService +from services import UserService, SessionService, OrganizationService user_bp = Blueprint("user", __name__) + +@user_bp.route("/login", methods=["POST"]) +def user_login(): + data = request.json + user = UserService.get_user_by_username(data["username"]) + if not user: + return jsonify({"error": "User not found"}), 404 + + org = OrganizationService.get_organization_by_name(data["org"]) + if not org: + return jsonify({"error": "Organization not found"}), 404 + + id_str = str(org.id) + if id_str not in user.public_keys: + return jsonify({"error": "User not associated with organization"}), 403 + + if user.public_keys[id_str] != data["public_key"]: + return jsonify({"error": "Invalid public key"}), 403 + + session = SessionService.create_session(user, org) + return jsonify(session.to_dict()), 201 diff --git a/delivery1/server/services/__init__.py b/delivery1/server/services/__init__.py index 6412401..7ab51d7 100644 --- a/delivery1/server/services/__init__.py +++ b/delivery1/server/services/__init__.py @@ -1,3 +1,4 @@ from .orgs import OrganizationService from .users import UserService -from .files import FileService \ No newline at end of file +from .files import FileService +from .sessions import SessionService \ No newline at end of file diff --git a/delivery1/server/services/orgs.py b/delivery1/server/services/orgs.py index deae293..d6f1ea4 100644 --- a/delivery1/server/services/orgs.py +++ b/delivery1/server/services/orgs.py @@ -28,6 +28,7 @@ class OrganizationService: db.refresh(organization) UserService().add_org_to_user(user, organization) + UserService().add_public_key_to_user(user, organization, public_key) return organization diff --git a/delivery1/server/services/sessions.py b/delivery1/server/services/sessions.py new file mode 100644 index 0000000..797f2e3 --- /dev/null +++ b/delivery1/server/services/sessions.py @@ -0,0 +1,26 @@ +import secrets +from database import db +from models import Session, User, Organization + + +class SessionService: + @staticmethod + def create_session(user: User, org: Organization) -> Session: + session = Session( + user_id=user.id, + org_id=org.id, + token=secrets.token_hex(128) + ) + db.add(session) + db.commit() + db.refresh(session) + return session + + @staticmethod + def get_session_by_token(token: str) -> Session | None: + return db.query(Session).filter(Session.token == token).first() + + @staticmethod + def delete_session(session: Session) -> None: + db.delete(session) + db.commit() \ No newline at end of file diff --git a/delivery1/server/services/users.py b/delivery1/server/services/users.py index 9f4e734..59f298a 100644 --- a/delivery1/server/services/users.py +++ b/delivery1/server/services/users.py @@ -9,7 +9,7 @@ class UserService: username=username, full_name=full_name, email=email, - public_key=public_key, + public_keys={org.id: public_key} if org else {}, orgs=[org] if org else [] ) db.add(user) @@ -30,4 +30,13 @@ class UserService: user.orgs.append(org) db.commit() db.refresh(user) + return user + + @staticmethod + def add_public_key_to_user(user: User, org: Organization, public_key: str) -> User: + public_keys = user.public_keys.copy() + public_keys[org.id] = public_key + user.public_keys = public_keys + db.commit() + db.refresh(user) return user \ No newline at end of file