Skip to content

Commit

Permalink
Merge pull request #165 from ufabc-next/feature/graduationStats
Browse files Browse the repository at this point in the history
Draft: Feature/graduation stats
  • Loading branch information
Joabesv authored Mar 27, 2024
2 parents dc429a3 + c1df306 commit f50b0ad
Show file tree
Hide file tree
Showing 5 changed files with 230 additions and 23 deletions.
48 changes: 48 additions & 0 deletions app/api/graduations/list/func.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
const app = require('@/app')

module.exports = async function func() {
const Graduation = await app.models.graduation
const graduations = await Graduation.find({}).lean()

const Subject = await app.models.subjects
const SubjectGraduations = await app.models.subjectGraduations

const populatedGraduations = await Promise.all(
graduations.map(async (graduation) => {
const subjectsGraduations = await SubjectGraduations.find({
graduation: graduation._id,
}).lean()

const subjects = (
await Promise.all(
subjectsGraduations.map(async (subjectGraduation) => {
const subject = await Subject.findOne({
_id: subjectGraduation.subject,
}).lean()
return {
...subjectGraduation,
subject,
}
})
)
).reduce((acc, subject) => {
const category = subject.category
if (!category) {
return acc
}
if (!acc[category]) {
acc[category] = []
}
acc[category].push(subject)
return acc
}, {})

return {
...graduation,
subjects,
}
})
)

return populatedGraduations
}
5 changes: 5 additions & 0 deletions app/api/graduations/list/route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const app = require('@/app')

module.exports = async (router) => {
router.get('/graduations', app.helpers.routes.func(require('./func.js')))
}
142 changes: 142 additions & 0 deletions app/api/graduations/stats/func.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
const app = require('@/app')

module.exports = async function func(context) {
const { ra } = context.user
if (!ra) {
return []
}
const graduationId = context.params.id
const Graduation = await app.models.graduation
const graduation = await Graduation.findOne({
_id: graduationId,
}).lean()

const Subject = await app.models.subjects
const SubjectGraduations = await app.models.subjectGraduations
const subjectsGraduations = await SubjectGraduations.find({
graduation: graduation._id,
}).lean()

const subjects = (
await Promise.all(
subjectsGraduations.map(async (subjectGraduation) => {
const subject = await Subject.findOne({
_id: subjectGraduation.subject,
}).lean()
return {
...subjectGraduation,
subject,
}
})
)
).reduce((acc, subject) => {
const category = subject.category
if (!category) {
return acc
}
if (!acc[category]) {
acc[category] = []
}
acc[category].push(subject)
return acc
}, {})

const populatedGraduation = {
...graduation,
subjects,
}

const enrollments = await app.models.enrollments
.find(
{
ra,
conceito: { $in: ['A', 'B', 'C', 'D', 'O', 'F'] },
},
{
conceito: 1,
subject: 1,
disciplina: 1,
pratica: 1,
teoria: 1,
year: 1,
quad: 1,
creditos: 1,
updatedAt: 1,
comments: 1,
}
)
.populate(['pratica', 'teoria', 'subject'])
.lean(true)

const mandatories = populatedGraduation.subjects.mandatory.filter(
(subject) => {
return enrollments.some((enrollment) => {
if (!enrollment.subject || !subject.subject) {
return false
}
return (
enrollment.subject._id.toString() === subject.subject._id.toString()
)
})
}
)

const limited = populatedGraduation.subjects.limited.filter((subject) => {
return enrollments.some((enrollment) => {
if (!enrollment.subject || !subject.subject) {
return false
}
return (
enrollment.subject._id.toString() === subject.subject._id.toString()
)
})
})

const invalidGrades = ['O', 'F']

return {
percentage: {
mandatories:
mandatories.length / populatedGraduation.subjects.mandatory.length,
limited: limited.length / populatedGraduation.subjects.limited.length,
},
credits: {
mandatories: {
done: mandatories.reduce((acc, subject) => {
return acc + subject.subject.creditos
}, 0),
total: populatedGraduation.subjects.mandatory.reduce((acc, subject) => {
return acc + subject.subject.creditos
}, 0),
},
limited: {
done: limited.reduce((acc, subject) => {
return acc + subject.subject.creditos
}, 0),
total: populatedGraduation.limited_credits_number,
},
},
missing: {
mandatories: populatedGraduation.subjects.mandatory.filter((subject) => {
return !mandatories.some((enrollment) => {
const completed = !invalidGrades.includes(enrollment.conceito)
if (!completed) return false

return (
enrollment.subject._id.toString() === subject.subject._id.toString()
)
})
}),
limited: populatedGraduation.subjects.limited.filter((subject) => {
return !limited.some((enrollment) => {
const completed = !invalidGrades.includes(enrollment.conceito)
if (!completed) return false

return (
enrollment.subject._id.toString() === subject.subject._id.toString()
)
})
}),
},
}
}
8 changes: 8 additions & 0 deletions app/api/graduations/stats/route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const app = require('@/app')

module.exports = async (router) => {
router.get(
'/graduations/stats/:id',
app.helpers.routes.func(require('./func.js'))
)
}
50 changes: 27 additions & 23 deletions app/setup/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,28 @@ module.exports = async (app) => {
}

// Authenticate user
api.use([
'/users/info',
'/users/complete',
'/users/me/resend',
'/users/me/grades',
'/users/me/delete',
'/users/me/devices',
'/enrollments',
'/comments',
'/reactions',
'/histories/courses',
'/users/me/relationships',
'/graduation',
'/subjectGraduations',
'/historiesGraduations',
'/students/aluno_id',
'/subjects'
], app.helpers.middlewares.auth)
api.use(
[
'/users/info',
'/users/complete',
'/users/me/resend',
'/users/me/grades',
'/users/me/delete',
'/users/me/devices',
'/enrollments',
'/comments',
'/reactions',
'/histories/courses',
'/users/me/relationships',
'/graduation',
'/graduations/stats',
'/subjectGraduations',
'/historiesGraduations',
'/students/aluno_id',
'/subjects',
],
app.helpers.middlewares.auth
)

// Protect Private routes
api.use('/private', app.helpers.middlewares.private)
Expand All @@ -46,7 +50,7 @@ module.exports = async (app) => {
let routerPaths = glob.sync('**/*route.js', { cwd })

// Require route files
let routers = routerPaths.map(file => require(path.join(cwd, file)))
let routers = routerPaths.map((file) => require(path.join(cwd, file)))

// user a temporary router to order
let tmpRoute = express()
Expand All @@ -60,13 +64,13 @@ module.exports = async (app) => {
app.helpers.routes.order(tmpRoute)

// get ordered router and apply on api
tmpRoute._router.stack.forEach(function (currentRoute){
tmpRoute._router.stack.forEach(function (currentRoute) {
let path = _.get(currentRoute, 'route.path')
let stack = _.get(currentRoute, 'route.stack', [])
let method = _.get(currentRoute, 'route.stack[0].method')
let functions = stack.map(s => s.handle)
let functions = stack.map((s) => s.handle)

if(method) {
if (method) {
api[method](path, ...functions)
}
})
Expand All @@ -75,7 +79,7 @@ module.exports = async (app) => {

// Locate express-restify-mongoose files
let restPaths = glob.sync('**/*rest.js', { cwd })
restPaths.map(file => require(path.join(cwd, file)))
restPaths.map((file) => require(path.join(cwd, file)))

// Add rest to api
api.use(app.router)
Expand Down

0 comments on commit f50b0ad

Please sign in to comment.