diff --git a/apps/api/views/__init__.py b/apps/api/views/__init__.py index 3503bcd..eea387a 100644 --- a/apps/api/views/__init__.py +++ b/apps/api/views/__init__.py @@ -4,7 +4,7 @@ from .api_views import HomeView, CountryView, CommentListAPIView from .documentation import CustomAPIDocumentationView from .swagger_views import CustomSwaggerView, SwaggerTokenAuthView, clear_swagger_auth - +from .admin_dashboard import AdminDashboardStatsView __all__ = [ 'HomeView', 'CountryView', @@ -13,4 +13,5 @@ __all__ = [ 'CustomSwaggerView', 'SwaggerTokenAuthView', 'clear_swagger_auth', + 'AdminDashboardStatsView' ] diff --git a/apps/api/views/admin_dashboard.py b/apps/api/views/admin_dashboard.py new file mode 100644 index 0000000..75149bf --- /dev/null +++ b/apps/api/views/admin_dashboard.py @@ -0,0 +1,65 @@ +from rest_framework.views import APIView +from rest_framework.response import Response +from rest_framework.permissions import IsAuthenticated, IsAdminUser +from django.utils import timezone +from datetime import timedelta +from django.db.models import Count + +from apps.account.models import User +from apps.course.models import Course, Participant +from apps.blog.models import Blog +from apps.certificate.models import Certificate +# Import your Transaction model here + +class AdminDashboardStatsView(APIView): + permission_classes = [IsAuthenticated, IsAdminUser] + + def get(self, request): + now = timezone.now() + thirty_days_ago = now - timedelta(days=30) + + # 1. Basic Counts + active_students = User.objects.filter(groups__name="Student Group", is_active=True).count() + professors = User.objects.filter(groups__name="Professor Group", is_active=True).count() + active_courses = Course.objects.filter(status=Course.StatusChoices.ONGOING).count() + total_blogs = Blog.objects.count() + pending_certificates = Certificate.objects.filter(status='pending').count() + + # 2. Revenue (Mocked - replace with your actual Transaction logic) + # revenue_30d = Transaction.objects.filter(status='success', created_at__gte=thirty_days_ago).aggregate(Sum('amount'))['amount__sum'] or 0 + revenue_30d = 12500.00 # Dummy data + + # 3. Transaction Chart Data (Mocked - replace with actual grouped query) + transactions_data = [ + {"name": "Success", "value": 450, "fill": "var(--color-success)"}, + {"name": "Pending", "value": 85, "fill": "var(--color-pending)"}, + {"name": "Waiting", "value": 40, "fill": "var(--color-waiting)"}, + {"name": "Failed", "value": 25, "fill": "var(--color-failed)"}, + ] + + # 4. Top 5 Popular Courses + top_courses = Course.objects.annotate( + participant_count=Count('participants') + ).order_by('-participant_count')[:5] + + top_courses_data = [ + { + "id": c.id, + "title": c.title, + "professor": c.professor.fullname if c.professor else "Unknown", + "participants": c.participant_count + } for c in top_courses + ] + + return Response({ + "cards": { + "active_students": active_students, + "professors": professors, + "active_courses": active_courses, + "total_blogs": total_blogs, + "revenue_30d": revenue_30d, + "pending_certificates": pending_certificates + }, + "transactions_chart": transactions_data, + "top_courses": top_courses_data + }) \ No newline at end of file diff --git a/config/urls.py b/config/urls.py index 105860d..f22b709 100644 --- a/config/urls.py +++ b/config/urls.py @@ -38,7 +38,7 @@ import requests from filer import views # Import custom API views -from apps.api.views import CustomAPIDocumentationView, CustomSwaggerView, SwaggerTokenAuthView, clear_swagger_auth +from apps.api.views import CustomAPIDocumentationView, CustomSwaggerView, SwaggerTokenAuthView, clear_swagger_auth ,admin_dashboard from apps.api.permissions import IsAdminOrSwaggerToken from apps.api.decorators import swagger_auth_required @@ -84,6 +84,7 @@ api_patterns = [ path('bookmarks/', include('apps.bookmark.urls')), path('calendar/', include('apps.dobodbi_calendar.urls')), path('blog/', include('apps.blog.urls')), + path('admin/dashboard-stats/' , admin_dashboard.AdminDashboardStatsView.as_view()), path('settings/', include('dynamic_preferences.urls')),