feat: Add user management endpoints for listing, updating, activating, and deactivating users
This commit is contained in:
@@ -37,3 +37,151 @@ def manual_credit_refill() -> dict:
|
||||
return scheduler_service.trigger_credit_refill_now()
|
||||
|
||||
|
||||
@bp.route("/users")
|
||||
@require_auth
|
||||
@require_role("admin")
|
||||
def list_users() -> dict:
|
||||
"""List all users (admin only)."""
|
||||
from app.models.user import User
|
||||
|
||||
users = User.query.order_by(User.created_at.desc()).all()
|
||||
return {
|
||||
"users": [user.to_dict() for user in users],
|
||||
"total": len(users)
|
||||
}
|
||||
|
||||
|
||||
@bp.route("/users/<int:user_id>", methods=["PATCH"])
|
||||
@require_auth
|
||||
@require_role("admin")
|
||||
def update_user(user_id: int) -> dict:
|
||||
"""Update user information (admin only)."""
|
||||
from flask import request
|
||||
from app.database import db
|
||||
from app.models.user import User
|
||||
from app.models.plan import Plan
|
||||
|
||||
data = request.get_json()
|
||||
if not data:
|
||||
return {"error": "No data provided"}, 400
|
||||
|
||||
user = User.query.get(user_id)
|
||||
if not user:
|
||||
return {"error": "User not found"}, 404
|
||||
|
||||
# Validate and update fields
|
||||
try:
|
||||
if "name" in data:
|
||||
name = data["name"].strip()
|
||||
if not name:
|
||||
return {"error": "Name cannot be empty"}, 400
|
||||
if len(name) > 100:
|
||||
return {"error": "Name too long (max 100 characters)"}, 400
|
||||
user.name = name
|
||||
|
||||
if "credits" in data:
|
||||
credits = data["credits"]
|
||||
if not isinstance(credits, int) or credits < 0:
|
||||
return {"error": "Credits must be a non-negative integer"}, 400
|
||||
user.credits = credits
|
||||
|
||||
if "plan_id" in data:
|
||||
plan_id = data["plan_id"]
|
||||
if not isinstance(plan_id, int):
|
||||
return {"error": "Plan ID must be an integer"}, 400
|
||||
|
||||
plan = Plan.query.get(plan_id)
|
||||
if not plan:
|
||||
return {"error": "Plan not found"}, 404
|
||||
|
||||
user.plan_id = plan_id
|
||||
|
||||
if "is_active" in data:
|
||||
is_active = data["is_active"]
|
||||
if not isinstance(is_active, bool):
|
||||
return {"error": "is_active must be a boolean"}, 400
|
||||
user.is_active = is_active
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return {
|
||||
"message": "User updated successfully",
|
||||
"user": user.to_dict()
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
return {"error": f"Failed to update user: {str(e)}"}, 500
|
||||
|
||||
|
||||
@bp.route("/users/<int:user_id>/deactivate", methods=["POST"])
|
||||
@require_auth
|
||||
@require_role("admin")
|
||||
def deactivate_user(user_id: int) -> dict:
|
||||
"""Deactivate a user (admin only)."""
|
||||
from app.database import db
|
||||
from app.models.user import User
|
||||
|
||||
user = User.query.get(user_id)
|
||||
if not user:
|
||||
return {"error": "User not found"}, 404
|
||||
|
||||
# Prevent admin from deactivating themselves
|
||||
current_user = get_current_user()
|
||||
if str(user.id) == current_user["id"]:
|
||||
return {"error": "Cannot deactivate your own account"}, 400
|
||||
|
||||
try:
|
||||
user.deactivate()
|
||||
db.session.commit()
|
||||
|
||||
return {
|
||||
"message": "User deactivated successfully",
|
||||
"user": user.to_dict()
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
return {"error": f"Failed to deactivate user: {str(e)}"}, 500
|
||||
|
||||
|
||||
@bp.route("/users/<int:user_id>/activate", methods=["POST"])
|
||||
@require_auth
|
||||
@require_role("admin")
|
||||
def activate_user(user_id: int) -> dict:
|
||||
"""Activate a user (admin only)."""
|
||||
from app.database import db
|
||||
from app.models.user import User
|
||||
|
||||
user = User.query.get(user_id)
|
||||
if not user:
|
||||
return {"error": "User not found"}, 404
|
||||
|
||||
try:
|
||||
user.activate()
|
||||
db.session.commit()
|
||||
|
||||
return {
|
||||
"message": "User activated successfully",
|
||||
"user": user.to_dict()
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
return {"error": f"Failed to activate user: {str(e)}"}, 500
|
||||
|
||||
|
||||
@bp.route("/plans")
|
||||
@require_auth
|
||||
@require_role("admin")
|
||||
def list_plans() -> dict:
|
||||
"""List all available plans (admin only)."""
|
||||
from app.models.plan import Plan
|
||||
|
||||
plans = Plan.query.order_by(Plan.id).all()
|
||||
return {
|
||||
"plans": [plan.to_dict() for plan in plans],
|
||||
"total": len(plans)
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user