Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: Feature/graduation stats #165

Merged
merged 4 commits into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading