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. 5
      backend/blueprints/profile/__init__.py

1
.gitignore vendored

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

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

@ -261,3 +261,8 @@ def change_password():
db.session.commit()
return jsonify({"message": "Password updated successfully"}), 200
# @profile.route('/hello')
# @auth_required()
# @requires_role([UserRole.ADMIN])
Loading…
Cancel
Save