feat: admin dashboard and stats

main
Kushal Dotel 6 months ago
parent 6afb2a7cfb
commit 8016d489bd
  1. 1
      .gitignore
  2. 4
      backend/app.py
  3. 140
      backend/blueprints/admin/__init__.py
  4. 7
      backend/blueprints/profile/__init__.py

1
.gitignore vendored

@ -26,6 +26,7 @@ env/
.venv/ .venv/
__pypackages__/ __pypackages__/
**.env
# Node.js # Node.js
node_modules/ node_modules/

@ -15,6 +15,7 @@ from utils.utils import random_string_generator, hash_string
from blueprints.profile import profile as profileBlueprint from blueprints.profile import profile as profileBlueprint
from blueprints.session import session as sessionBlueprint from blueprints.session import session as sessionBlueprint
from blueprints.admin import admin as adminBlueprint
app = Flask(__name__) app = Flask(__name__)
# Set configuration directly on the app instance # Set configuration directly on the app instance
@ -26,6 +27,7 @@ db.init_app(app)
app.register_blueprint(profileBlueprint, url_prefix='/api/profile') app.register_blueprint(profileBlueprint, url_prefix='/api/profile')
app.register_blueprint(sessionBlueprint,url_prefix='/api/session') app.register_blueprint(sessionBlueprint,url_prefix='/api/session')
app.register_blueprint(adminBlueprint,url_prefix='/api/admin')
@app.route('/media/<string:filename>') @app.route('/media/<string:filename>')
def send_file(filename): def send_file(filename):
@ -53,7 +55,7 @@ def seed_data():
joinedDate=datetime.utcnow(), lastOnline=datetime.utcnow(), joinedDate=datetime.utcnow(), lastOnline=datetime.utcnow(),
bio=f"This is user{i}'s bio.", role=int(UserRole.USER), bio=f"This is user{i}'s bio.", role=int(UserRole.USER),
isActivated=True, sessions=[], user_badges=[], isActivated=True, sessions=[], user_badges=[],
enrollments=[], quizzes=[], quiz_attempts=[], chats=[], notifications=[]) enrollments=[], quizzes=[], quiz_attempts=[], chats=[], notifications=[],publications=[])
for i in range(1, 6) ] for i in range(1, 6) ]
db.session.add_all(users) db.session.add_all(users)
db.session.commit() db.session.commit()

@ -0,0 +1,140 @@
from utils .auth import auth_required, requires_role
from flask import Blueprint, jsonify, g
from db.model import User, Course, Enrollment, Chat, db
from sqlalchemy import select, func, desc, and_
from datetime import datetime, timedelta
from constants import UserRole
admin = Blueprint('admin', __name__)
@admin.route('/stats/users', methods=['GET'])
@auth_required()
@requires_role([UserRole.ADMIN])
def get_user_stats():
"""
Get total users and authors count.
Only accessible by admin users.
"""
try:
# Get total users
total_users = db.session.execute(
select(func.count()).select_from(User)
).scalar()
# Get authors (users who have created courses)
distinct_authors_count = db.session.execute(
select(func.count(func.distinct(Course.authorID)))
).scalar()
return jsonify({
'stats': {
'totalUsers': total_users,
'totalAuthors': distinct_authors_count
}
}), 200
except Exception as e:
return jsonify({'message': f'An error occurred: {str(e)}'}), 500
@admin.route('/stats/enrollments', methods=['GET'])
@auth_required()
@requires_role([UserRole.ADMIN])
def get_enrollment_stats():
"""
Get course enrollment and discussion statistics.
Only accessible by admin users.
"""
try:
# Get enrollment and user counts
enrollment_stats = db.session.execute(
select(
func.count(Enrollment.id).label('total_enrollments'),
func.count(func.distinct(Enrollment.userID)).label('enrolled_users')
)
.select_from(Enrollment)
).first()
# Get course-wise enrollment counts
course_stats = db.session.execute(
select(
Course.name,
func.count(Enrollment.id).label('enrollment_count')
)
.join(Course, Course.id == Enrollment.courseID)
.group_by(Course.id)
.order_by(desc('enrollment_count'))
).all()
return jsonify({
'stats': {
'totalEnrollments': enrollment_stats.total_enrollments,
'totalEnrolledUsers': enrollment_stats.enrolled_users,
'courseEnrollments': [{
'courseName': stat.name,
'enrollmentCount': stat.enrollment_count
} for stat in course_stats]
}
}), 200
except Exception as e:
return jsonify({'message': f'An error occurred: {str(e)}'}), 500
@admin.route('/stats/discussions', methods=['GET'])
@auth_required()
@requires_role([UserRole.ADMIN])
def get_discussion_stats():
"""
Get chat room activity statistics.
Only accessible by admin users.
"""
try:
# Get activity for last 24 hours
twenty_four_hours_ago = datetime.now() - timedelta(hours=24)
# Get active rooms and their stats
active_rooms = db.session.execute(
select(
Course.name,
func.count(Chat.id).label('message_count'),
func.count(func.distinct(Chat.userID)).label('active_users')
)
.join(Course, Course.id == Chat.courseID)
.where(Chat.chatDate >= twenty_four_hours_ago)
.group_by(Course.id)
.order_by(desc('message_count'))
).all()
# Get total active rooms
total_active_rooms = len(active_rooms)
# Get most active room
most_active_room = None
if active_rooms:
most_active = active_rooms[0]
most_active_room = {
'name': most_active.name,
'messageCount': most_active.message_count,
'activeUsers': most_active.active_users
}
# Get total active users across all rooms
total_active_users = db.session.execute(
select(func.count(func.distinct(Chat.userID)))
.where(Chat.chatDate >= twenty_four_hours_ago)
).scalar()
return jsonify({
'stats': {
'totalActiveRooms': total_active_rooms,
'totalActiveUsers': total_active_users,
'mostActiveRoom': most_active_room,
'activeRooms': [{
'roomName': room.name,
'messageCount': room.message_count,
'activeUsers': room.active_users
} for room in active_rooms]
}
}), 200
except Exception as e:
return jsonify({'message': f'An error occurred: {str(e)}'}), 500

@ -260,4 +260,9 @@ def change_password():
user.hash_password = generate_password_hash(new_password) user.hash_password = generate_password_hash(new_password)
db.session.commit() db.session.commit()
return jsonify({"message": "Password updated successfully"}), 200 return jsonify({"message": "Password updated successfully"}), 200
# @profile.route('/hello')
# @auth_required()
# @requires_role([UserRole.ADMIN])
Loading…
Cancel
Save