...
 
Commits (5)
API para el Sistema de Consejerías de la Universidad de Cuenca como parte del proyecto LALA
Pasos a seguir para ejecutar el API:
1. Instalar Nodejs (url: https://nodejs.org/es/download/)
2. Instalar git (url: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git).
3. Clonar el proyecto ejecutando la siguiente línea: git clone https://git.cti.espol.edu.ec/LALA-Project/UCUENCA.git
4. Dirigirse a la carpeta del proyecto API-Sistema de Consejerias.
5. Ejecutar dentro de la carpeta del proyecto el comando: npm install
6. Ejecutar dentro de la carpeta del proyecto el comando: npm start
7. El proyecto se ejecuta en: localhost:3000.
\ No newline at end of file
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var db = require('./server/models');
var crudOperations = require('./crud')(db);
var apiV1 = require('./routes/api/v1/')(crudOperations,db);
var index = require('./routes');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(function(req, res, next) {
var oneof = false;
if(req.headers.origin) {
res.header('Access-Control-Allow-Origin', req.headers.origin);
oneof = true;
}
if(req.headers['access-control-request-method']) {
res.header('Access-Control-Allow-Methods', req.headers['access-control-request-method']);
oneof = true;
}
if(req.headers['access-control-request-headers']) {
res.header('Access-Control-Allow-Headers', req.headers['access-control-request-headers']);
oneof = true;
}
if(oneof) {
res.header('Access-Control-Max-Age', 60 * 60 * 24 * 365);
}
// intercept OPTIONS method
if (oneof && req.method == 'OPTIONS') {
res.send(200);
}
else {
next();
}
});
app.use(express.static(path.join(__dirname, 'public')));
app.use('/api', index);
app.use('/api/v1',apiV1);
var apiOptions = {
context: '/api2',
logger:{ file: 'mochaTest.log', level: 'debug' },
discover: { path: 'discover', secure: true },
// proto: { path: 'proto', secure: true }
}
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
#!/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('api:server');
var http = require('http');
var https = require('https');
var fs = require("fs");
/*var options = {
key: fs.readFileSync("cert/selfsigned.key"),
cert: fs.readFileSync("cert/selfsigned.crt")
};
*/
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
* Create HTTP server.
*/
//var server = https.createServer(options,app);
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
Aquí se colocaran los archivos necesarios para una implementación bajo https
const request = require('request-promise')
const btoa = require('btoa')
const ISSUER = 'https://dev-878998.oktapreview.com/oauth2/ausj08qk5vYaB8HWc0h7';
const TEST_CLIENT_ID = '0oaj19qfa1c2F66WD0h7';
const TEST_CLIENT_SECRET = 'LxhIkvex-1Z1JAx7vhW9LL4VhSYb-yuSlvUGUPlp';
const DEFAULT_SCOPE = '';
//const ENDPOINT = 'http://localhost:3000/api/v1/students/00918df7-5843-c53e-eec9-1595af6fdcd9?program=223';
//const ENDPOINT = 'http://localhost:3000/api/v1/students/E26?program=1';
//const ENDPOINT = 'http://localhost:3000/api/v1/students2/'; //toda la malla
//const ENDPOINT = 'http://localhost:3000/api/v1/studentacademicsbycurriculum/?studentid=1&curriculumid=1'; //el historico academico del estudiante
const ENDPOINT = 'http://localhost:3000/api/v1/studentpartners/?studentid=1&curriculumid=1&courseid=14&termid=3&group=A'; //los companeros de aula que aprobaron
const test = async () => {
const token = btoa(`${TEST_CLIENT_ID}:${TEST_CLIENT_SECRET}`)
try {
const { token_type, access_token } = await request({
uri: `${ISSUER}/v1/token`,
json: true,
method: 'POST',
headers: {
authorization: `Basic ${token}`,
},
form: {
grant_type: 'client_credentials',
scope: DEFAULT_SCOPE,
},
})
const response = await request({
uri: ENDPOINT,
json: true,
rejectUnauthorized: false,
headers: {
authorization: [token_type, access_token].join(' '),
},
})
//console.log(response[0].student_curriculums[0].curriculum.program_terms[0].program_courses[0].me);
console.log(response);
//console.log(JSON.parse(response).student_curriculum.curriculum.program_term.program_course,access_token);
//console.log(response[0].student_curriculum[0].curriculum.program_term[0].program_course);
//console.log(JSON.parse(JSON.parse(response).student_curriculum));
//console.log(JSON.parse(response).student_curriculum);
//console.log(JSON.parse(response)[0].student_curriculum[0].curriculum.program_term[0].program_course);
} catch (error) {
console.log(`Error: ${error.message}`)
}
}
test()
var Sequelize = require('sequelize');
const Op = Sequelize.Op;
module.exports = (db) => {
return {
/**
* Summary. Get a Program with a specific Curriculum.
*
* Description. Get a Program with a specific Curriculum.
*
* @param {int} id The id of the Program.
* @param {int} year The year of the Curriculum.
*
* @return {Object} The response object.
*/
getProgram : async(id,year)=>{
const data = await db.curriculum.findOne({
where:{
"$program.id$":id,
"$program.state$":'active',
year:year,
state:'active'
},
include:[{model:db.program}]
});
return data;
},
/**
* Summary. Get an Array of ProgramTerms with their Courses from a specific Curriculum.
*
* Description. Get an Array of ProgramTerms with their Courses from a specific Curriculum.
*
* @param {int} curriculum_id The id of the Curriculum.
*
* @return {Object} The response object.
*/
getProgramTerms: async(curriculum_id) =>{
const terms = await db.program_term.findAll({
order:[
['position','ASC']
],
where:{
curriculum_id:curriculum_id,
[Op.or]: [{"$program_courses.state$":'active'},{"$program_courses.state$":null}]
},
include:[
{
model:db.program_course,
include:[
{
model:db.course,
where:{
state:'active'
}
}
]
}
]
});
return terms;
},
/**
* Summary. Get a Student academic from a program.
*
* Description. Get a Student academic from a program.
*
* @param {string} studentId The id of the Student.
* @param {int} programId The id of the Program.
*
* @return {Object} The response object.
*/
getStudentsAcademics: async(studentId,programId) => {
const student = await db.student.findOne({
order:[
// If I want to order for attributes belonging in other tables
[db.student_curriculum,db.curriculum,'year','DESC']
],
where:{
id:studentId,
state:'active'
},
include:[
{
model:db.student_curriculum,
include:[
{
model:db.curriculum,
where:{
state:'active'
},
include:{
model:db.program,
where:{
id:programId,
state:'active'
}
}
}
]
},
{
model:db.student_dropout
}
]
});
return student;
},
/**
* Summary. Get the history academic of a student from an specific Curriculum.
*
* Description. Get the history academic of a student from an specific Curriculum.
*
* @param {string} studentId The id of the Student.
* @param {int} curriculumId The id of the Curriculum.
* @param {int} cohortYear The cohort year of the student. This parameter for the statistics cohort
*
* @return {Object} The response object.
*/
getHistoryAcademicStudentByCurriculum: async(curriculumId,studentId,cohortYear) => {//Cohort year for the statistics cohort
const historyAcademics = await db.history_academic_course.findAll({
order:[
['year','ASC'],
['semester','ASC']
],
where:{
student_id:studentId
},
include:[
{
model:db.statistic_student_term,
/*on:{
col1: Sequelize.where(Sequelize.col("history_academic_course.year"), "=", Sequelize.col("statistic_student_term.year")),
col2: Sequelize.where(Sequelize.col("history_academic_course.semester"), "=", Sequelize.col("statistic_student_term.semester")),
col3: Sequelize.where(Sequelize.col("statistic_student_term.student_id"), "=", studentId)
}*/
},
{
model:db.course,
where:{
curriculum_id:curriculumId,
state:'active'
},
include:[
{
model:db.statisticTerm,
on: {
col1: Sequelize.where(Sequelize.col("course.code"), "=", Sequelize.col("course->statisticTerms.course_code")),
col2: Sequelize.where(Sequelize.col("history_academic_course.year"), "=", Sequelize.col("course->statisticTerms.year")),
col3: Sequelize.where(Sequelize.col("history_academic_course.semester"), "=", Sequelize.col("course->statisticTerms.semester"))
}
},
{
model:db.statistic
},
{
model:db.statisticCohort,
// La restriccion del año la coloco aqui debido a que
// where me produciria un inner join
// lefth join on a.course_id = b.course_id and a.year = cohorte
on: {
col1: Sequelize.where(Sequelize.col("course.id"), "=", Sequelize.col("course->statisticCohorts.course_id")),
col21: Sequelize.where(Sequelize.col("course->statisticCohorts.year"), "=",cohortYear)
}
}
]
}
]
});
return historyAcademics;
},
getCourseAcademics: async (courseId) => {
const statisticTerms = await db.statisticTerm.findAll({
order:[
[db.term,'year','DESC'],
[db.term,'semester','ASC']
],
where:{
course_code:courseId
},
include:[
{
model:db.term,
}
]
});
return statisticTerms;
},
/**
* Summary. Get the las date when the data were loaded in the database.
*
* Description. Get the las date when the data were loaded in the database.
*
* @return {Object} The response object.
*/
getLoadingDate: async () => {
const loadingDate = await db.parameter.findAll({
order:[
['loading_date','DESC']
]
});
return loadingDate.length === 0 ? null : loadingDate[0].loading_date;
},
/**
*
*Obtiene el listado de todos los estudiantes
*
*/
getAllStudents: async () => {
const allStudents = await db.student.findAll({
order: [
['name', 'DESC']
]
});
return allStudents;
},
/**
*
* Query para extraer todas las materias a las que pertenece el estudiante con tal nombre
*/
getCurriculum: async (studentId) => {
const terms = await db.student.findAll({
logging: console.log,
// order: [
// [{model: db.program_course, as: "program_courses"}, "course_id", "ASC"]
// ],
// order: [
// ["student_curriculums.curriculum.program_terms.program_courses.course_id", 'asc']
// ],
where :{
anonid:studentId
},
/*include:[
{
model:db.history_academic_course,
//required: true
}
*/
include: [
{
model:db.student_curriculum,
include:[
{
model:db.curriculum,
include: [
{
model:db.program
},
{
model:db.program_term,
include:[
{
model:db.program_course,
}
]
}
]
}
]
}
],
order: [
//con esta linea ordeno por id del curso que se encuentra en la tabla program course, pero a sequelize debo hacerle saber donde
//se encuentra esta tabla, es decir, en que nivel de jerarquia, por lo cual debo poner el nivel de jerarquia
[db.student_curriculum, db.curriculum, db.program_term, db.program_course, 'course_id', 'ASC']
]
// {
// model:db.student_curriculum
// }
/* order:[
['position','ASC']
],
where:{
curriculum_id:1,
[Op.or]: [{"$program_courses.state$":'ACTIVO'},{"$program_courses.state$":null}]
},
include:[
{
model:db.program_course,
include:[
{
model:db.course,
where:{
state:'active'
}
}
]
},
{
model:db.curriculum,
include: [
{
model:db.program
}
]
}
]*/
});
return terms;
},
getCorsesAndProgramCourse: async (program_term_id) =>{
const coursesPC= db.program_course.findAll({
// logging: console.log,
order: [
["program_term_id", "ASC"]
],
where: {
program_term_id:program_term_id
},
include: [{
model:db.course
}]
});
return coursesPC;
},
//Para extraer el historial academico de un estudiante a traves de su id
getHistoryAcademicStudentByCurriculumId : async (studentId, curriculumId) => {
const historyAcademics = await db.history_academic_course.findAll({
//logging: console.log,
order: [['term_id', 'ASC']],
where: {
student_id: studentId,
curriculum_id: curriculumId
},
include:[{
model: db.term
}]
});
return historyAcademics;
},
//Para extraer a todos los companeros de aula que aprobaron la asignatura dada
getPartnersOfCourse : async (curriculum_id, course_id, term_id, group) => {
const partners = await db.student.findAll({
include: {
model: db.history_academic_course,
where: {
curriculum_id: curriculum_id,
course_id: course_id,
term_id: term_id,
group: group,
state: 'APROBADO'
}
}
});
return partners;
},
//Para extraer a todos los companeros de aula que reprobaron la asignatura dada
getPartnersOfCourseReprobados: async (curriculum_id, course_id, term_id, group, arrayAprobados) => {
const Op = Sequelize.Op;//con este se guardan todos los operadores de sequalizer en OP (Op.notIn, Op.and, Op.or, etc, ver mas en http://docs.sequelizejs.com/manual/tutorial/querying.html#operators)
const partnersLose= await db.student.findAll({
//logging: console.log,
include: {
model: db.history_academic_course,
where: {
curriculum_id: curriculum_id,
course_id: course_id,
term_id: term_id,
group: group,
student_id: { [Op.notIn]: arrayAprobados }//indico que todos los datos que extraiga deben cumplir con la condicion de que los datos que extraiga, mediante el student_id no deben estar en los datos del array
}
}
});
return partnersLose;
},
//para extraer el historial de las sesiones de consegerias del estudiante
getMeetingHistory: async (student_id) => {
const history = await db.meeting.findAll({
order: [
["date", "DESC"]
],
where: {
student_id: student_id
},
include: {
model: db.counselor
}
});
return history;
},
addMeeting: async (studentId, counselor_id, observations, date) => {
console.log('esto llega',studentId, counselor_id, observations, date);
return await db.meeting.create({
student_id: studentId,
counselor_id: counselor_id,
observations: observations,
date: date
}).then(function(data){
console.log(data);
return data;
}).catch(function(error){
console.log(error.stack);
return error;
});
}
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "api",
"version": "1.0.0",
"private": true,
"scripts": {
"start": "export NODE_ENV=development && node ./bin/www",
"devStart": "nodemon ./bin/www",
"testRequest": "concurrently \"nodemon ./bin/www\" \"node clientRequestExample.js\"",
"sequelizeAuto": "sequelize-auto -o './server/models' -d <database> -h <ip> -u <username> -p 5432 -x '<password>' -e postgres",
"sequelizeCreateMigration": "sequelize migration:generate --name $NAME",
"sequelizeMigrate": "sequelize db:migrate",
"sequelizeMigrateUndo": "sequelize db:migrate:undo"
},
"dependencies": {
"@okta/jwt-verifier": "0.0.14",
"body-parser": "^1.18.3",
"btoa": "^1.2.1",
"connect-rest": "^3.0.26",
"cookie-parser": "~1.4.3",
"d3": "^5.7.0",
"debug": "~2.2.0",
"express": "^4.16.4",
"express-validator": "^5.3.0",
"jade": "~1.11.0",
"morgan": "^1.9.1",
"pg": "^7.5.0",
"pg-hstore": "^2.3.2",
"request-promise": "^4.2.2",
"sequelize": "^5.0.0-beta.14",
"serve-favicon": "^2.5.0",
"wagner-core": "^0.2.0"
},
"devDependencies": {
"nodemon": "^1.18.4",
"concurrently": "^4.0.1"
}
}
define({ "api": [
{
"type": "get",
"url": "/coursesAcademics/:code",
"title": "Request Statistics information from an specific course.",
"version": "1.0.0",
"name": "GetCourseAcademics",
"group": "Course",
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "code",
"description": "<p>Course code.</p>"
}
]
}
},
"header": {
"fields": {
"Header": [
{
"group": "Header",
"type": "String",
"optional": false,
"field": "access-token",
"description": "<p>Unique access-token.</p>"
}
]
}
},
"examples": [
{
"title": "Example usage:",
"content": "curl -i https://localhost:3000/api/v1/coursesAcademics/EYAG1012",
"type": "curl"
}
],
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "[ACADEMICS_BY_TERM]",
"optional": false,
"field": "academicsByTerm",
"description": "<p>An array of ACADEMICS_BY_TERM of the Course .</p>"
},
{
"group": "Success 200",
"type": "Integer",
"optional": false,
"field": "year",
"description": "<p>The year of the term.</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "term",
"description": "<p>The semester of the Term.</p>"
},
{
"group": "Success 200",
"type": "StatisticByTerm",
"optional": false,
"field": "academics",
"description": "<p>Statistic of the Course in a specific Term.</p>"
}
]
},
"examples": [
{
"title": "Success-Response:",
"content": " HTTP/1.1 200 OK\n{\n \"academicsByTerm\": [\n {\n \"year\": 2018,\n \"semester\": \"1S\",\n \"academics\": {\n \"distribution\": [\n {\n \"label\": \"label1\",\n \"value\": 2\n },\n {\n \"label\": \"label2\",\n \"value\": 1\n },\n {\n \"label\": \"label3\",\n \"value\": 2\n }\n ],\n \"dist_range\": {\n \"max\": 3,\n \"min\": 2\n },\n \"student_count\": null,\n \"fail_rate\": null,\n \"drop_rate\": null,\n \"count_by_delay\": null\n }\n },\n {\n \"year\": 2015,\n \"semester\": \"1S\",\n \"academics\": {\n \"distribution\": [\n {\n \"label\": \"label1\",\n \"value\": 2\n },\n {\n \"label\": \"label2\",\n \"value\": 1\n },\n {\n \"label\": \"label3\",\n \"value\": 2\n }\n ],\n \"dist_range\": {\n \"max\": 3,\n \"min\": 2\n },\n \"student_count\": null,\n \"fail_rate\": null,\n \"drop_rate\": null,\n \"count_by_delay\": null\n }\n },\n {\n \"year\": 2015,\n \"semester\": \"2S\",\n \"academics\": {\n \"distribution\": [\n {\n \"label\": \"label1\",\n \"value\": 2\n },\n {\n \"label\": \"label2\",\n \"value\": 1\n },\n {\n \"label\": \"label3\",\n \"value\": 2\n }\n ],\n \"dist_range\": {\n \"max\": 3,\n \"min\": 2\n },\n \"student_count\": null,\n \"fail_rate\": null,\n \"drop_rate\": null,\n \"count_by_delay\": null\n }\n }\n ]\n}",
"type": "json"
}
]
},
"error": {
"fields": {
"Error 4xx": [
{
"group": "Error 4xx",
"optional": false,
"field": "ProgramNotFound",
"description": "<p>The <code>id</code> or the <code>year</code> of the Program was not found.</p>"
},
{
"group": "Error 4xx",
"optional": false,
"field": "NoAccessRight",
"description": "<p>The <code>id</code> of the User was not found.</p>"
}
]
},
"examples": [
{
"title": "Error-courseNotFound-Response:",
"content": "HTTP/1.1 404 Not Found\n{\n \"errors\": [\n {\n \"status\": 404,\n \"error\": \"coursesAcademicsNotFound\",\n \"detail\": \"Wasn't found data for that cours.\"\n }\n ]\n}",
"type": "json"
},
{
"title": "Error-NoAccessRight-Response:",
"content": "HTTP/1.1 404 Not Found\n{\n \"error\": \"NoAccessRight\"\n}",
"type": "json"
}
]
},
"filename": "routes/api/v1/courses.js",
"groupTitle": "Course"
},
{
"type": "get",
"url": "/programs/:id",
"title": "Request Program information from a specific year",
"version": "1.0.0",
"name": "GetProgram",
"group": "Program",
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "Integer",
"optional": false,
"field": "id",
"description": "<p>Program unique ID.</p>"
},
{
"group": "Parameter",
"type": "Integer",
"optional": false,
"field": "year",
"description": "<p>Year of the program.</p>"
}
]
}
},
"header": {
"fields": {
"Header": [
{
"group": "Header",
"type": "String",
"optional": false,
"field": "access-token",
"description": "<p>Unique access-token.</p>"
}
]
}
},
"examples": [
{
"title": "Example usage:",
"content": "curl -i https://localhost:3000/api/v1/programs/4711?year=2016",
"type": "curl"
}
],
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "lastDataUpdate",
"description": "<p>The last date when the data were loaded.</p>"
},
{
"group": "Success 200",
"type": "Integer",
"optional": false,
"field": "id",
"description": "<p>The id of the Program.</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "name",
"description": "<p>The name of the Program.</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "desc",
"description": "<p>The description of the Program.</p>"
},
{
"group": "Success 200",
"type": "Integer",
"optional": false,
"field": "plan",
"description": "<p>The id of the Curriculum.</p>"
},
{
"group": "Success 200",
"type": "Integer",
"optional": false,
"field": "year",
"description": "<p>The year of the Curriculum.</p>"
},
{
"group": "Success 200",
"type": "[Term]",
"optional": false,
"field": "terms",
"description": "<p>An array of Terms</p>"
},
{
"group": "Success 200",
"type": "Integer",
"optional": false,
"field": "term[position]",
"description": "<p>The position of the Term.</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "term[name]",
"description": "<p>The name of the Term.</p>"
},
{
"group": "Success 200",
"type": "[String]",
"optional": false,
"field": "term[tags]",
"description": "<p>An Array of tags for the Term.</p>"
},
{
"group": "Success 200",
"type": "[Course]",
"optional": false,
"field": "term[courses]",
"description": "<p>An array of Courses.</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "course[code]",
"description": "<p>The code of the Course.</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "course[name]",
"description": "<p>The name of the Course.</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "course[desc]",
"description": "<p>The description of the Course.</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "course[area]",
"description": "<p>The area of the Course.</p>"
},
{
"group": "Success 200",
"type": "[String]",
"optional": false,
"field": "course[tags]",
"description": "<p>An Array of tags for the Course.</p>"
},
{
"group": "Success 200",
"type": "[String]",
"optional": false,
"field": "course[requisites]",
"description": "<p>An Array of requisites for the Course.</p>"
},
{
"group": "Success 200",
"type": "Integer",
"optional": false,
"field": "course[credits]",
"description": "<p>The credits of the Course.</p>"
}
]
},
"examples": [
{
"title": "Success-Response:",
"content": " HTTP/1.1 200 OK\n {\n \"lastDataUpdate\": \"2018-01-12T05:00:00.000Z\",\n \"id\": \"4711\",\n \"name\": \"Ingeniería Civil en Informática\",\n \"desc\": \"Description\",\n \"plan\": \"3\",\n \"year\": \"2016\",\n \"tags\": [\n \"Tag1\",\n \"Tag2\"\n ],\n \"terms\": [\n {\n \"position\": \"1\",\n \"name\": \"1 Término\",\n \"tags\": [\n \"Tag1\",\n \"Tag2\"\n ],\n \"courses\": [\n {\n \"code\": \"BAIN037\",\n \"name\": \"Cálculo en una Variable\",\n \"desc\": \"Descr\",\n \"tags\": [\n \"Tag1\",\n \"Tag2\"\n ],\n \"requisites\": [\n \"Álgebra para Ingeniería\"\n ],\n \"credits\": 6\n },\n {\n \"code\": \"BAIN019\",\n \"name\": \"Química para Ingeniería\",\n \"desc\": \"Descr\",\n \"tags\": [\n \"Tag1\",\n \"Tag2\"\n ],\n \"requisites\": [],\n \"credits\": 2\n }\n ]\n },\n {\n \"position\": \"2\",\n \"name\": \"2 Término\",\n \"tags\": [\n \"Tag1\",\n \"Tag2\"\n ],\n \"courses\": [\n {\n \"code\": \"DYRE060\",\n \"name\": \"Taller de Ingeniería: Programación Aplicada\",\n \"desc\": \"Descr\",\n \"tags\": [\n \"Tag1\",\n \"Tag2\"\n ],\n \"requisites\": [\n \"Álgebra para Ingeniería\",\n \"Geometría para Ingeniería\",\n \"Taller de Ingeniería I\"\n ],\n \"credits\": 3\n },\n {\n \"code\": \"BAIN039\",\n \"name\": \"Comunicación Idioma Inglés\",\n \"desc\": \"Descr\",\n \"tags\": [\n \"Tag1\",\n \"Tag2\"\n ],\n \"requisites\": [\n \"AA\"\n ],\n \"credits\": 5\n }\n ]\n },\n {\n \"position\": \"3\",\n \"name\": \"3 Término\",\n \"tags\": [],\n \"courses\": []\n }\n ]\n}",
"type": "json"
}
]
},
"error": {
"fields": {
"Error 4xx": [
{
"group": "Error 4xx",
"optional": false,
"field": "InvalidParameter",
"description": "<p>The <code>id</code> or <code>year</code> are not Number.</p>"
},
{
"group": "Error 4xx",
"optional": false,
"field": "MissingParameter",
"description": "<p>The <code>year</code> is missing.</p>"
},
{
"group": "Error 4xx",
"optional": false,
"field": "ProgramNotFound",
"description": "<p>The <code>id</code> or the <code>year</code> of the Program was not found.</p>"
},
{
"group": "Error 4xx",
"optional": false,
"field": "NoAccessRight",
"description": "<p>The <code>id</code> of the User was not found.</p>"
}
]
},
"examples": [
{
"title": "Error-InvalidParameter-Response:",
"content": "HTTP/1.1 400 Bad Request\n{\n \"errors\": [\n {\n \"status\": 422,\n \"error\": \"InvalidParameter\",\n \"detail\": \"params[id]: Must be an Integer\"\n }\n ]\n}",
"type": "json"
},
{
"title": "Error-MissingParameter-Response:",
"content": "HTTP/1.1 400 Bad Request\n{\n \"errors\": [\n {\n \"status\": 422,\n \"error\": \"MissingParameter\",\n \"detail\": \"body[year]: Must be provided\"\n }\n ]\n}",
"type": "json"
},
{
"title": "Error-ProgramNotFound-Response:",
"content": "HTTP/1.1 404 Not Found\n{\n \"errors\": [\n {\n \"status\": 404,\n \"error\": \"ProgramNotFound\",\n \"detail\": \"The Program wasn't found.\"\n }\n ]\n}",
"type": "json"
},
{
"title": "Error-NoAccessRight-Response:",
"content": "HTTP/1.1 404 Not Found\n{\n \"error\": \"NoAccessRight\"\n}",
"type": "json"
}
]
},
"filename": "routes/api/v1/programs.js",
"groupTitle": "Program"
},
{
"type": "get",
"url": "/students/:id",
"title": "Request Student academic information from a specific program",
"version": "1.0.0",
"name": "GetStudent",
"group": "Student",
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "id",
"description": "<p>Student unique ID.</p>"
},
{
"group": "Parameter",
"type": "Integer",
"optional": false,
"field": "program",
"description": "<p>Program unique ID</p>"
}
]
}
},
"header": {
"fields": {
"Header": [
{
"group": "Header",
"type": "String",
"optional": false,
"field": "access-token",
"description": "<p>Unique access-token.</p>"
}
]
}
},
"examples": [
{
"title": "Example usage:",
"content": "curl -i https://localhost:3000/api/v1/students/00918df7-5843-c53e-eec9-1595af6fdcd9?program=223",
"type": "curl"
}
],
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "lastDataUpdate",
"description": "<p>The last date when the data were loaded.</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "id",
"description": "<p>The id of the Student.</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "program",
"description": "<p>The name of the Program.</p>"
},
{
"group": "Success 200",
"type": "Integer",
"optional": false,
"field": "cohortYear",
"description": "<p>The cohort year of the student</p>"
},
{
"group": "Success 200",
"type": "Integer",
"optional": false,
"field": "plan",
"description": "<p>The id of the last Curriculum of the Student in a Program.</p>"
},
{
"group": "Success 200",
"type": "Integer",
"optional": false,
"field": "planYear",
"description": "<p>The year version of the last Curriculum of the Student in a Program.</p>"
},
{
"group": "Success 200",
"type": "[Curriculum]",
"optional": false,
"field": "previousPlans",
"description": "<p>An array with information (id and year) about previous curriculums in a program of the student.</p>"
},
{
"group": "Success 200",
"type": "Double",
"optional": false,
"field": "bachCompletedCourses",
"description": "<p>Data related with the student's dropout</p>"
},
{
"group": "Success 200",
"type": "Double",
"optional": false,
"field": "bachTotalCourses",
"description": "<p>Data related with the student's dropout</p>"
},
{
"group": "Success 200",
"type": "Double",
"optional": false,
"field": "estimatedTermsToCompleteBach",
"description": "<p>Data related with the student's dropout</p>"
},
{
"group": "Success 200",
"type": "Double",
"optional": false,
"field": "estimatedProbability",
"description": "<p>Data related with the student's dropout</p>"
},
{
"group": "Success 200",
"type": "[Term]",
"optional": false,
"field": "terms",
"description": "<p>An array of Term academics for a student.</p>"
},
{
"group": "Success 200",
"type": "Integer",
"optional": false,
"field": "term[year]",
"description": "<p>The year of the Term.</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "term[semester]",
"description": "<p>The semester of the Term.</p>"
},
{
"group": "Success 200",
"type": "Double",
"optional": false,
"field": "term[termAvg]",
"description": "<p>An statistic of the Term.</p>"
},
{
"group": "Success 200",
"type": "Double",
"optional": false,
"field": "term[accAvg]",
"description": "<p>An statistic of the Term.</p>"
},
{
"group": "Success 200",
"type": "[Course]",
"optional": false,
"field": "term[courses]",
"description": "<p>An Array of Courses taken by the Student in the Term.</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "course[code]",
"description": "<p>The code of the Course.</p>"
},
{
"group": "Success 200",
"type": "Double",
"optional": false,
"field": "course[grade]",
"description": "<p>The grade get it by the Student.</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "course[registration]",
"description": "<p>The registration of the Course. (cursada, homologada, convalidada, anulada)</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "course[status]",
"description": "<p>The status of the Course. (Aprobada, Reprobada)</p>"
},
{
"group": "Success 200",
"type": "StatisticByGroup",
"optional": false,
"field": "course[historicGroup]",
"description": "<p>Some statistics about a course in general.</p>"
},
{
"group": "Success 200",
"type": "StatisticByCohort",
"optional": false,
"field": "course[cohortGroup]",
"description": "<p>Some statistics about a course in the specific cohort of the student.</p>"
},
{
"group": "Success 200",
"type": "StatisticByClass",
"optional": false,
"field": "course[classGroup]",
"description": "<p>Some statistics about a course in a specific term.</p>"
}
]
},
"examples": [
{
"title": "Success-Response:",
"content": " HTTP/1.1 200 OK\n {\n \"lastDataUpdate\": \"2018-01-12T05:00:00.000Z\"\n \"id\": \"00918df7-5843-c53e-eec9-1595af6fdcd9\",\n \"program\": \"Ingeniería Civil\",\n \"cohortYear\": 2016,\n \"plan\": \"2864\",\n \"planYear\": 2015,\n \"previousPlans\": [],\n \"bachCompletedCourses\": 0.0,\n \"bachTotalCourses\": 0.0,\n \"estimatedTermsToCompleteBach\": 0.0,\n \"estimatedProbability\": 0.0,\n \"terms\": [\n {\n \"year\": 2015,\n \"semester\": \"1S\",\n \"termAvg\": null,\n \"accAvg\": null,\n \"coursesTaken\": [\n {\n \"code\": \"ICF01107\",\n \"name\": \"LABORATORIO DE FÍSICA A\",\n \"grade\": 7.8,\n \"registration\": null,\n \"state\": \"AP\",\n \"historicGroup\": {\n \"course_code\": \"ICF01107\",\n \"distribution\": [\n {\n \"label\": \"label1\",\n \"value\": 2\n },\n {\n \"label\": \"label2\",\n \"value\": 1\n },\n {\n \"label\": \"label3\",\n \"value\": 2\n }\n ],\n \"dist_range\": {\n \"max\": 3,\n \"mi