From 2520dc3cce98bca24c37ae2de86d7d7d986c1655 Mon Sep 17 00:00:00 2001 From: Casu Al Snek Date: Sat, 11 Jan 2025 22:44:08 +0545 Subject: [PATCH 1/2] Fix course updates and deletes --- backend/blueprints/course/__init__.py | 73 +++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 3 deletions(-) diff --git a/backend/blueprints/course/__init__.py b/backend/blueprints/course/__init__.py index 0524eba..2f5a9ea 100644 --- a/backend/blueprints/course/__init__.py +++ b/backend/blueprints/course/__init__.py @@ -1,9 +1,10 @@ from flask import Blueprint, request, jsonify, g +from sqlalchemy import select, and_ from werkzeug.datastructures import MultiDict import os import uuid from config import DEFAULT_COURSE_COVER -from db.model import db, Course, Category, User, Chat +from ...db.model import db, Course, Category, User, Chat from utils.utils import random_string_generator from utils.auth import auth_required, requires_role from constants import * @@ -18,7 +19,6 @@ def create_course(): form_data: dict = request.form course_uploaded_cover_image: MultiDict|None = request.files.get('cover_image', None) course_uploaded_pdf: MultiDict|None = request.files.get('course_pdf', None) - cover_file_name: str = DEFAULT_COURSE_COVER pdf_file_name: str = '' if course_uploaded_cover_image is not None: @@ -50,7 +50,74 @@ def create_course(): quizzes=[], chats=[] ) + # chat: Chat = Chat(courseID=new_course.id) TODO: Add a welcome chat for this course db.session.add_all(new_course) db.session.commit() - return jsonify({'message': 'Course was created successfully.'}), 200 \ No newline at end of file + return jsonify({'message': 'Course was created successfully.'}), 200 + +@course.route('/update', methods=['UPDATE', 'DELETE']) +@auth_required() +def update_course(): + form_data = request.form + course_id: uuid.UUID = uuid.UUID(form_data['course_id']) + selected_course: Course|None = None + if g.current_user.role == int(UserRole.ADMIN): + selected_course: Course = db.session.execute(select(Course).where(and_( + Course.id == course_id + ))).scalar() + else: + selected_course: Course = db.session.execute(select(Course).where(and_( + Course.id == course_id, Course.publishedStatus != int(PublishedStatus.BANNED) + ))).scalar() + if not selected_course: + return jsonify({'message': 'The course could not be found'}), 404 + if request.method == 'DELETE': + if selected_course.authorID == g.current_user.id or g.current_user.role == int(UserRole.ADMIN): + db.session.delete(selected_course) + db.session.commit() + return jsonify({'message': 'Course was deleted successfully'}), 200 + else: + return jsonify({'message': 'Unauthorized for this change'}), 401 + else: + # Update the data + if selected_course.authorID == g.current_user.id or g.current_user.role == int(UserRole.ADMIN): + if form_data.get('course_name'): + selected_course.name = form_data.get('course_name') + if form_data.get('course_description'): + selected_course.description = form_data.get('course_description') + if form_data.get('category_uuid'): + selected_course.categoryID = uuid.UUID(form_data.get('category_uuid')) + if form_data.get('isActive'): + selected_course.isActive = bool(int(form_data.get('active'))) + + # Admin Guarded + if form_data.get('published_status'): + if g.current_user.role != int(UserRole.ADMIN): + return jsonify({'message': 'Unauthorized'}), 401 + valid_states: list[int] = [ + int(e) for e in + [PublishedStatus.APPROVED, + PublishedStatus.PENDING, + PublishedStatus.DECLINED, + PublishedStatus.REVOKED, + PublishedStatus.BANNED, + PublishedStatus.DRAFT] + ] + if int(form_data.get('published_status')) not in valid_states: + return jsonify({'message': 'Invalid state to update'}), 401 + selected_course.publishedStatus = int(form_data.get('published_status')) + if request.files.get('cover_image'): + cover_file_name: str = random_string_generator(32) + request.files.get('cover_image').filename.split('.')[-1] + request.files.get('cover_image').save(os.path.join(USER_UPLOADS_DIR, cover_file_name)) + selected_course.coverImage = cover_file_name + if request.files.get('course_pdf'): + pdf_file_name: str = random_string_generator(32) + request.files.get('course_pdf').filename.split('.')[1] + request.files.get('course_pdf').save(os.path.join(USER_UPLOADS_DIR, pdf_file_name)) + selected_course.serverFilename = pdf_file_name + if g.current_user.role != int(UserRole.ADMIN): + selected_course.publishedStatus = int(PublishedStatus.PENDING) + db.session.commit() + return jsonify({'message': 'Course info updated'}), 200 + else: + return jsonify({'message': 'Unauthorized for this change'}), 401 \ No newline at end of file From e70d869b76f0e0c10db0a5d04ad22ead6658439e Mon Sep 17 00:00:00 2001 From: Casu Al Snek Date: Sat, 11 Jan 2025 23:14:35 +0545 Subject: [PATCH 2/2] Allow int casting of enums --- backend/blueprints/course/__init__.py | 8 ++++++-- backend/constants/__init__.py | 6 +++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/backend/blueprints/course/__init__.py b/backend/blueprints/course/__init__.py index 2f5a9ea..5c9782b 100644 --- a/backend/blueprints/course/__init__.py +++ b/backend/blueprints/course/__init__.py @@ -4,7 +4,7 @@ from werkzeug.datastructures import MultiDict import os import uuid from config import DEFAULT_COURSE_COVER -from ...db.model import db, Course, Category, User, Chat +from db.model import db, Course, Category, User, Chat from utils.utils import random_string_generator from utils.auth import auth_required, requires_role from constants import * @@ -120,4 +120,8 @@ def update_course(): db.session.commit() return jsonify({'message': 'Course info updated'}), 200 else: - return jsonify({'message': 'Unauthorized for this change'}), 401 \ No newline at end of file + return jsonify({'message': 'Unauthorized for this change'}), 401 + +@course.route('/info/') +def course_info(course_uuid): + pass \ No newline at end of file diff --git a/backend/constants/__init__.py b/backend/constants/__init__.py index 1ec55d3..3e2a32e 100644 --- a/backend/constants/__init__.py +++ b/backend/constants/__init__.py @@ -15,10 +15,14 @@ class PublishedStatus(Enum): REVOKED = 3 BANNED = 4 DRAFT = 5 + def __int__(self): + return self.value class NotificationTypes(Enum): MENTION = 0 COURSE_PUBLISH_STATUS_UPDATE = 1 NEW_BADGE = 2 TEXT_WITH_URL = 3 - PLAINTEXT_NOTICE = 4 \ No newline at end of file + PLAINTEXT_NOTICE = 4 + def __int__(self): + return self.value