1+ // controllers/dashboardController.js
2+ const {
3+ Feedback,
4+ Achievement,
5+ UserSkill,
6+ Skill,
7+ Event,
8+ PositionHolder,
9+ Position,
10+ OrganizationalUnit,
11+ } = require ( "../models/schema" ) ;
12+
13+ const ROLES = {
14+ PRESIDENT : "PRESIDENT" ,
15+ GENSEC_SCITECH : "GENSEC_SCITECH" ,
16+ GENSEC_ACADEMIC : "GENSEC_ACADEMIC" ,
17+ GENSEC_CULTURAL : "GENSEC_CULTURAL" ,
18+ GENSEC_SPORTS : "GENSEC_SPORTS" ,
19+ CLUB_COORDINATOR : "CLUB_COORDINATOR" ,
20+ STUDENT : "STUDENT" ,
21+ } ;
22+
23+ const roleToCategoryMap = {
24+ [ ROLES . GENSEC_SCITECH ] : "scitech" ,
25+ [ ROLES . GENSEC_ACADEMIC ] : "academic" ,
26+ [ ROLES . GENSEC_CULTURAL ] : "cultural" ,
27+ [ ROLES . GENSEC_SPORTS ] : "sports" ,
28+ } ;
29+
30+
31+ exports . getDashboardStats = async ( req , res ) => {
32+ const { _id : userId , username, role } = req . user ;
33+ const email = username ;
34+ let stats = { } ;
35+
36+ try {
37+ switch ( role . toUpperCase ( ) ) {
38+
39+ // STUDENT
40+ case ROLES . STUDENT : {
41+ const [ totalSkills , totalFeedbacksGiven , totalAchievements , totalPORs ] =
42+ await Promise . all ( [
43+ UserSkill . countDocuments ( { user_id : userId } ) ,
44+ Feedback . countDocuments ( { feedback_by : userId } ) ,
45+ Achievement . countDocuments ( { user_id : userId } ) ,
46+ PositionHolder . countDocuments ( { user_id : userId , status : "active" } ) ,
47+ ] ) ;
48+
49+ stats = {
50+ totalSkills,
51+ totalFeedbacksGiven,
52+ totalAchievements,
53+ totalPORs,
54+ } ;
55+ break ;
56+ }
57+
58+ // ALL GENSECS (SciTech, Cultural, etc.)
59+ case ROLES . GENSEC_SCITECH :
60+ case ROLES . GENSEC_ACADEMIC :
61+ case ROLES . GENSEC_CULTURAL :
62+ case ROLES . GENSEC_SPORTS : {
63+ const roleCategory = roleToCategoryMap [ role ] ;
64+ if ( ! roleCategory ) {
65+ return res . status ( 400 ) . json ( { msg : "Invalid GenSec role category." } ) ;
66+ }
67+
68+ // Find the GenSec's organizational unit (Council) by their email
69+ const orgUnit = await OrganizationalUnit . findOne ( { "contact_info.email" : email } ) ;
70+ if ( ! orgUnit ) {
71+ console . error ( "Organizational Unit for GenSec not found." ) ;
72+ return res . status ( 404 ) . json ( { msg : "Organizational Unit for GenSec not found." } ) ;
73+ }
74+
75+ // Query for pending user skills of the correct category using aggregation
76+ const pendingUserSkillsAggregation = await UserSkill . aggregate ( [
77+ { $match : { is_endorsed : false } } , // Find un-endorsed user skills
78+ {
79+ $lookup : {
80+ from : "skills" ,
81+ localField : "skill_id" ,
82+ foreignField : "_id" ,
83+ as : "skillDoc" ,
84+ } ,
85+ } ,
86+ { $unwind : "$skillDoc" } ,
87+ { $match : { "skillDoc.type" : roleCategory } } ,
88+ { $count : "count" } ,
89+ ] ) ;
90+
91+ const [ childClubsCount , pendingSkills , pendingAchievements ] =
92+ await Promise . all ( [
93+
94+ OrganizationalUnit . countDocuments ( { parent_unit_id : orgUnit . _id } ) ,
95+ Skill . countDocuments ( { is_endorsed : false , type : roleCategory } ) ,
96+ Achievement . countDocuments ( { verified : false } ) ,
97+ ] ) ;
98+
99+ stats = {
100+ budget : {
101+ used : orgUnit . budget_info . spent_amount ,
102+ total : orgUnit . budget_info . allocated_budget ,
103+ } ,
104+ parentOfClubs : childClubsCount ,
105+ pendingSkillsEndorsement : pendingSkills ,
106+ pendingUserSkillsEndorsement : ( pendingUserSkillsAggregation . length > 0 ? pendingUserSkillsAggregation [ 0 ] . count : 0 ) ,
107+ pendingAchievementEndorsement : pendingAchievements ,
108+ } ;
109+ break ;
110+ }
111+
112+ // CLUB COORDINATOR
113+
114+ case ROLES . CLUB_COORDINATOR : {
115+ const clubUnit = await OrganizationalUnit . findOne ( { "contact_info.email" : email } ) ;
116+ if ( ! clubUnit ) {
117+ console . error ( "Club unit for Coordinator not found." ) ;
118+ console . log ( email ) ;
119+ return res . status ( 404 ) . json ( { msg : "Club unit for Coordinator not found." } ) ;
120+ }
121+
122+ // Find all positions associated with this club
123+ const positionsInClub = await Position . find ( { unit_id : clubUnit . _id } ) . select ( '_id' ) ;
124+ const positionIds = positionsInClub . map ( p => p . _id ) ;
125+
126+ // Find all active members holding those positions
127+ const activeMembers = await PositionHolder . find ( {
128+ position_id : { $in : positionIds } ,
129+ status : 'active'
130+ } ) ;
131+ const memberUserIds = activeMembers . map ( m => m . user_id ) ;
132+
133+ const [ totalEvents , pendingReviews ] = await Promise . all ( [
134+ Event . countDocuments ( { organizing_unit_id : clubUnit . _id } ) ,
135+ Achievement . countDocuments ( { user_id : { $in : memberUserIds } , verified : false } ) ,
136+ ] ) ;
137+
138+ stats = {
139+ budget : {
140+ used : clubUnit . budget_info . spent_amount ,
141+ total : clubUnit . budget_info . allocated_budget ,
142+ } ,
143+ totalEvents,
144+ totalActiveMembers : activeMembers . length ,
145+ pendingReviews,
146+ } ;
147+ break ;
148+ }
149+
150+
151+ // PRESIDENT
152+ case ROLES . PRESIDENT : {
153+ const budgetAggregation = await OrganizationalUnit . aggregate ( [
154+ { $group : {
155+ _id : null ,
156+ totalBudget : { $sum : "$budget_info.allocated_budget" } ,
157+ usedBudget : { $sum : "$budget_info.spent_amount" }
158+ } }
159+ ] ) ;
160+
161+ const [ pendingRoomRequests , totalOrgUnits ] = await Promise . all ( [
162+ Event . countDocuments ( { "room_requests.status" : "Pending" } ) ,
163+ OrganizationalUnit . countDocuments ( )
164+ ] ) ;
165+
166+ stats = {
167+ pendingRoomRequests,
168+ totalOrgUnits,
169+ budget : {
170+ used : ( budgetAggregation [ 0 ] && budgetAggregation [ 0 ] . usedBudget ) || 0 ,
171+ total : ( budgetAggregation [ 0 ] && budgetAggregation [ 0 ] . totalBudget ) || 0 ,
172+ }
173+ } ;
174+ break ;
175+ }
176+
177+ default :
178+ return res . status ( 400 ) . json ( { msg : "Invalid user role for stats." } ) ;
179+ }
180+
181+ res . status ( 200 ) . json ( stats ) ;
182+
183+ } catch ( error ) {
184+ console . error ( "Error fetching dashboard stats:" , error ) ;
185+ res . status ( 500 ) . send ( "Server Error" ) ;
186+ }
187+ } ;
0 commit comments