Start work on role guard

manzilcheck
Casu Al Snek 6 months ago
parent cc39f23efd
commit 6b0840b0c0
  1. 44
      backend/app.py
  2. 8
      backend/db/model.py
  3. 39
      backend/utils/auth.py

@ -10,6 +10,7 @@ from flask import jsonify
import uuid import uuid
from datetime import datetime from datetime import datetime
from constants import UserRole from constants import UserRole
from utils.utils import random_string_generator, hash_string
from blueprints.profile import profile as profileBlueprint from blueprints.profile import profile as profileBlueprint
@ -24,9 +25,8 @@ app.register_blueprint(profileBlueprint, url_prefix='/api')
def homepage(): def homepage():
return {'message': 'Welcome back !'}, 200 return {'message': 'Welcome back !'}, 200
@app.route('/seedData', methods=['GET'])
@app.route('/seed-users', methods=['GET']) def seed_data():
def seed_users():
try: try:
# Drop and recreate schema (only for testing, not recommended in production) # Drop and recreate schema (only for testing, not recommended in production)
sql = text('DROP SCHEMA public CASCADE; CREATE SCHEMA public;') sql = text('DROP SCHEMA public CASCADE; CREATE SCHEMA public;')
@ -35,38 +35,18 @@ def seed_users():
db.create_all() # Recreate tables db.create_all() # Recreate tables
# Define roles and constants (ensure UserRole.USER is an integer or map it) # Define roles and constants (ensure UserRole.USER is an integer or map it)
default_role = UserRole.USER.value if hasattr(UserRole, 'USER') else 1
default_profile_file = "defaultUserBanner.png"
# Create seed users # Create seed users
users = [ users = [ User(
User( email=f"user{i}@example.com", firstName=f"FirstName{i}", lastName=f"LastName{i}",
email=f"user{i}@example.com", username=f"username{i}", hash_password=generate_password_hash("password123"),
firstName=f"FirstName{i}", activationKey=hash_string(random_string_generator(16)), pfpFilename=DEFAULT_PROFILE_FILE,
lastName=f"LastName{i}", joinedDate=datetime.utcnow(), lastOnline=datetime.utcnow(),
username=f"username{i}", bio=f"This is user{i}'s bio.", role=UserRole.ADMIN if i == 1 else UserRole.USER,
hash_password=generate_password_hash("password123"), isActivated=True, sessions=[], user_badges=[],
pfpFilename=default_profile_file, enrollments=[], quizzes=[], quiz_attempts=[], chats=[], notifications=[])
joinedDate=datetime.utcnow(), for i in range(1, 6) ]
lastOnline=datetime.utcnow(),
bio=f"This is user{i}'s bio.",
role=default_role,
isActivated=True,
sessions=[],
user_badges=[],
enrollments=[],
quizzes=[],
quiz_attempts=[],
chats=[],
notifications=[]
)
for i in range(1, 6)
]
# Add users to the database
db.session.add_all(users) db.session.add_all(users)
db.session.commit() db.session.commit()
return {"message": "Users seeded successfully!"}, 201 return {"message": "Users seeded successfully!"}, 201
except Exception as e: except Exception as e:
db.session.rollback() db.session.rollback()

@ -4,8 +4,8 @@ from sqlalchemy import types, text, String, DateTime, func, Boolean, ForeignKey,
from datetime import datetime from datetime import datetime
import uuid import uuid
from typing import List from typing import List
from config import * from ..config import *
from constants import UserRole, PublishedStatus from ..constants import UserRole, PublishedStatus
class Base(MappedAsDataclass, DeclarativeBase): class Base(MappedAsDataclass, DeclarativeBase):
pass pass
@ -20,13 +20,15 @@ class User(db.Model):
firstName: Mapped[str] = mapped_column(String(32), nullable=False) firstName: Mapped[str] = mapped_column(String(32), nullable=False)
lastName: Mapped[str] = mapped_column(String(32), nullable=False) lastName: Mapped[str] = mapped_column(String(32), nullable=False)
username: Mapped[str] = mapped_column(String(32), nullable=False) username: Mapped[str] = mapped_column(String(32), nullable=False)
hash_password: Mapped[str] = mapped_column(String(256), nullable=False) # Added field for hashed password hash_password: Mapped[str] = mapped_column(String(256), nullable=False)
activationKey: Mapped[str] = mapped_column(String(128), nullable=False)
sessions: Mapped[List["Session"]] = relationship(back_populates="user", cascade="all, delete-orphan") sessions: Mapped[List["Session"]] = relationship(back_populates="user", cascade="all, delete-orphan")
enrollments: Mapped[List["Enrollment"]] = relationship(back_populates="user", cascade="all, delete-orphan") enrollments: Mapped[List["Enrollment"]] = relationship(back_populates="user", cascade="all, delete-orphan")
quizzes: Mapped[List["Quiz"]] = relationship(back_populates="creatorUser", cascade="all, delete-orphan") quizzes: Mapped[List["Quiz"]] = relationship(back_populates="creatorUser", cascade="all, delete-orphan")
quiz_attempts: Mapped[List["QuizAttempt"]] = relationship(back_populates="user", cascade="all, delete-orphan") quiz_attempts: Mapped[List["QuizAttempt"]] = relationship(back_populates="user", cascade="all, delete-orphan")
chats: Mapped[List["Chat"]] = relationship(back_populates="user", cascade="all, delete-orphan") chats: Mapped[List["Chat"]] = relationship(back_populates="user", cascade="all, delete-orphan")
notifications: Mapped[List["Notification"]] = relationship(back_populates="user", cascade="all, delete-orphan") notifications: Mapped[List["Notification"]] = relationship(back_populates="user", cascade="all, delete-orphan")
dob: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.fromisocalendar(2002, 1, 1))
user_badges: Mapped[List["UserBadge"]] = relationship(back_populates="user", cascade="all, delete-orphan") user_badges: Mapped[List["UserBadge"]] = relationship(back_populates="user", cascade="all, delete-orphan")
pfpFilename: Mapped[str] = mapped_column(String(256), nullable=False, default=DEFAULT_PROFILE_FILE) pfpFilename: Mapped[str] = mapped_column(String(256), nullable=False, default=DEFAULT_PROFILE_FILE)
joinedDate: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=func.now()) joinedDate: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=func.now())

@ -0,0 +1,39 @@
from functools import wraps
from flask import request, jsonify
from sqlalchemy import select
from ..db.model import User, Session, db
def requires_role(roles=[]):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
auth_header = request.headers.get('Authorization')
if not auth_header:
return jsonify({'error': 'No authorization header sent'}), 401
try:
session_key = auth_header.split(' ')[1]
except IndexError:
return jsonify({'error': 'Invalid authorization header format'}), 401
session = db.session.execute(
)
if not session:
return jsonify({'error': 'Invalid or expired session'}), 401
user = User.query.get(session.userID)
if not user:
return jsonify({'error': 'User not found'}), 401
# If no roles specified, allow access
if not roles:
return f(*args, **kwargs)
# Check if user has any of the required roles
if user.role in roles:
return f(*args, **kwargs)
return jsonify({'error': 'Insufficient permissions'}), 403
return decorated_function
return decorator
Loading…
Cancel
Save