|
|
|
from flask import Blueprint, request, jsonify, g
|
|
|
|
from werkzeug.datastructures import MultiDict
|
|
|
|
import os
|
|
|
|
import uuid
|
|
|
|
from sqlalchemy import select
|
|
|
|
from config import DEFAULT_BADGE_ICON, USER_UPLOADS_DIR
|
|
|
|
from db.model import db, Badge, User
|
|
|
|
from utils.utils import random_string_generator
|
|
|
|
from utils.auth import auth_required, requires_role
|
|
|
|
from constants import UserRole
|
|
|
|
|
|
|
|
badge = Blueprint('badge', __name__)
|
|
|
|
|
|
|
|
@badge.route('/create', methods=['POST'])
|
|
|
|
@auth_required()
|
|
|
|
@requires_role([UserRole.ADMIN])
|
|
|
|
def create_badge():
|
|
|
|
"""
|
|
|
|
Create a new badge. Only accessible by admin users.
|
|
|
|
Requires: badge_name, description
|
|
|
|
Optional: icon_image, can_claim
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
form_data: dict = request.form
|
|
|
|
badge_uploaded_icon: MultiDict|None = request.files.get('icon_image', None)
|
|
|
|
|
|
|
|
# Validate required fields
|
|
|
|
try:
|
|
|
|
badge_name: str = form_data['badge_name']
|
|
|
|
if len(badge_name) > 16:
|
|
|
|
return jsonify({'message': 'Badge name cannot exceed 16 characters'}), 400
|
|
|
|
except KeyError:
|
|
|
|
return jsonify({'message': 'Badge name cannot be empty'}), 400
|
|
|
|
|
|
|
|
# Handle icon upload
|
|
|
|
icon_file_name: str = DEFAULT_BADGE_ICON
|
|
|
|
if badge_uploaded_icon is not None:
|
|
|
|
icon_file_name = f"{random_string_generator(32)}.{badge_uploaded_icon.filename.split('.')[-1]}"
|
|
|
|
badge_uploaded_icon.save(os.path.join(USER_UPLOADS_DIR, icon_file_name))
|
|
|
|
|
|
|
|
# Get optional fields
|
|
|
|
badge_description: str = form_data.get('description', '')
|
|
|
|
can_claim: bool = form_data.get('can_claim', 'false').lower() == 'true'
|
|
|
|
|
|
|
|
# Create new badge
|
|
|
|
new_badge: Badge = Badge(
|
|
|
|
name=badge_name,
|
|
|
|
description=badge_description,
|
|
|
|
icon=icon_file_name,
|
|
|
|
canClaim=can_claim,
|
|
|
|
user_badges=[]
|
|
|
|
)
|
|
|
|
|
|
|
|
db.session.add(new_badge)
|
|
|
|
db.session.commit()
|
|
|
|
|
|
|
|
return jsonify({
|
|
|
|
'message': 'Badge was created successfully.',
|
|
|
|
'badge': {
|
|
|
|
'id': str(new_badge.id),
|
|
|
|
'name': new_badge.name,
|
|
|
|
'description': new_badge.description,
|
|
|
|
'icon': new_badge.icon,
|
|
|
|
'canClaim': new_badge.canClaim
|
|
|
|
}
|
|
|
|
}), 200
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
db.session.rollback()
|
|
|
|
return jsonify({'message': f'An error occurred: {str(e)}'}), 500
|
|
|
|
|
|
|
|
@badge.route('/update/<badge_id>', methods=['PUT'])
|
|
|
|
@auth_required()
|
|
|
|
@requires_role([UserRole.ADMIN])
|
|
|
|
def update_badge(badge_id):
|
|
|
|
"""
|
|
|
|
Update an existing badge. Only accessible by admin users.
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
badge_to_update = db.session.get(Badge, uuid.UUID(badge_id))
|
|
|
|
if not badge_to_update:
|
|
|
|
return jsonify({'message': 'Badge not found'}), 404
|
|
|
|
|
|
|
|
form_data: dict = request.form
|
|
|
|
badge_uploaded_icon: MultiDict|None = request.files.get('icon_image', None)
|
|
|
|
|
|
|
|
# Update icon if provided
|
|
|
|
if badge_uploaded_icon is not None:
|
|
|
|
new_icon_name = f"{random_string_generator(32)}.{badge_uploaded_icon.filename.split('.')[-1]}"
|
|
|
|
badge_uploaded_icon.save(os.path.join(USER_UPLOADS_DIR, new_icon_name))
|
|
|
|
# Remove old icon if it's not the default
|
|
|
|
if badge_to_update.icon != DEFAULT_BADGE_ICON:
|
|
|
|
try:
|
|
|
|
os.remove(os.path.join(USER_UPLOADS_DIR, badge_to_update.icon))
|
|
|
|
except OSError:
|
|
|
|
pass # File might not exist
|
|
|
|
badge_to_update.icon = new_icon_name
|
|
|
|
|
|
|
|
# Update other fields if provided
|
|
|
|
if 'badge_name' in form_data:
|
|
|
|
if len(form_data['badge_name']) > 16:
|
|
|
|
return jsonify({'message': 'Badge name cannot exceed 16 characters'}), 400
|
|
|
|
badge_to_update.name = form_data['badge_name']
|
|
|
|
|
|
|
|
if 'description' in form_data:
|
|
|
|
badge_to_update.description = form_data['description']
|
|
|
|
|
|
|
|
if 'can_claim' in form_data:
|
|
|
|
badge_to_update.canClaim = form_data['can_claim'].lower() == 'true'
|
|
|
|
|
|
|
|
db.session.commit()
|
|
|
|
|
|
|
|
return jsonify({
|
|
|
|
'message': 'Badge was updated successfully.',
|
|
|
|
'badge': {
|
|
|
|
'id': str(badge_to_update.id),
|
|
|
|
'name': badge_to_update.name,
|
|
|
|
'description': badge_to_update.description,
|
|
|
|
'icon': badge_to_update.icon,
|
|
|
|
'canClaim': badge_to_update.canClaim
|
|
|
|
}
|
|
|
|
}), 200
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
db.session.rollback()
|
|
|
|
return jsonify({'message': f'An error occurred: {str(e)}'}), 500
|
|
|
|
|
|
|
|
@badge.route('/list', methods=['GET'])
|
|
|
|
@auth_required()
|
|
|
|
def list_badges():
|
|
|
|
"""
|
|
|
|
List all badges. Accessible by all authenticated users.
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
badges = db.session.execute(
|
|
|
|
select(Badge)
|
|
|
|
.order_by(Badge.createDate.desc())
|
|
|
|
).scalars().all()
|
|
|
|
|
|
|
|
return jsonify({
|
|
|
|
'badges': [{
|
|
|
|
'id': str(badge.id),
|
|
|
|
'name': badge.name,
|
|
|
|
'description': badge.description,
|
|
|
|
'icon': badge.icon,
|
|
|
|
'canClaim': badge.canClaim,
|
|
|
|
'createDate': badge.createDate.isoformat()
|
|
|
|
} for badge in badges]
|
|
|
|
}), 200
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
return jsonify({'message': f'An error occurred: {str(e)}'}), 500
|