mirror of
https://github.com/UniversityOfHelsinkiCS/oodikone.git
synced 2026-10-12 19:03:39 +03:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83ef6f5760 | ||
|
|
59de371d9a | ||
|
|
362250868d | ||
|
|
846d4b9ec7 | ||
|
|
6d8f4e0992 | ||
|
|
b41bfbd47e | ||
|
|
d774d5f073 | ||
|
|
6259cfface | ||
|
|
7cd101bb57 | ||
|
|
329bd4696a | ||
|
|
750a12e14b | ||
|
|
f46a8fee5b | ||
|
|
0d8f51bc4f | ||
|
|
d3c01133b7 | ||
|
|
abb7d2211f | ||
|
|
dd7088c332 | ||
|
|
27bbfc6519 | ||
|
|
c1433392d4 | ||
|
|
f7131d361c | ||
|
|
5840889fa9 | ||
|
|
887b57fca7 | ||
|
|
c496912d88 | ||
|
|
442a58c74a | ||
|
|
ac1632c1e1 | ||
|
|
25dc072b2e | ||
|
|
46b575ae6d | ||
|
|
24fafbe4ff | ||
|
|
18f6d6157c | ||
|
|
3c27f19ea1 | ||
|
|
ad7c36f235 | ||
|
|
6caebdab25 | ||
|
|
58423df517 | ||
|
|
a547382f1c | ||
|
|
bf178fb086 | ||
|
|
fc023f09cb | ||
|
|
3fe9683c98 | ||
|
|
8d20225a57 | ||
|
|
b83c90dca1 | ||
|
|
47de8e89c3 | ||
|
|
64606c2a98 | ||
|
|
b5e913d85e | ||
|
|
8e5dcb3e78 | ||
|
|
ebd03acff0 | ||
|
|
0fe06bfd12 | ||
|
|
3f564ab66a | ||
|
|
9e6349739a | ||
|
|
d1936c6358 | ||
|
|
a075df412c | ||
|
|
b53d84f706 | ||
|
|
0312174e40 | ||
|
|
442ced9124 | ||
|
|
ea9345d82c | ||
|
|
132bf930fb | ||
|
|
980fbef339 | ||
|
|
c68e9abfd4 | ||
|
|
530435a069 | ||
|
|
8cbd4fd957 | ||
|
|
3152e5a76d |
+11
-1
@@ -21,7 +21,17 @@
|
||||
"cypress/no-assigning-return-values": "off",
|
||||
"cypress/unsafe-to-chain-command": "off",
|
||||
"default-param-last": "off",
|
||||
"import/order": "off",
|
||||
"import/order": [
|
||||
"error",
|
||||
{
|
||||
"alphabetize": { "order": "asc", "caseInsensitive": true },
|
||||
"groups": [
|
||||
["builtin", "external"],
|
||||
["internal", "parent", "sibling", "index"]
|
||||
],
|
||||
"newlines-between": "always"
|
||||
}
|
||||
],
|
||||
"no-async-promise-executor": "off",
|
||||
"no-await-in-loop": "off",
|
||||
"no-console": "error",
|
||||
|
||||
@@ -162,13 +162,13 @@ describe('Population Statistics', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('Credit filter works', () => {
|
||||
it('Credit filter works', { retries: 2 }, () => {
|
||||
runTestStepWithPreAndPostParts('CreditsEarned', () => {
|
||||
testRangeFilter('CreditsEarned-filter-card', 50, 150, 118)
|
||||
})
|
||||
})
|
||||
|
||||
it('Age filter works', () => {
|
||||
it('Age filter works', { retries: 2 }, () => {
|
||||
cy.clock(MOCKED_DATE, ['Date'])
|
||||
runTestStepWithPreAndPostParts('Age', () => {
|
||||
testRangeFilter('Age-filter-card', 20, 40, 47)
|
||||
|
||||
@@ -57,7 +57,7 @@ describe('When language center is opened', () => {
|
||||
it('"Access denied" is shown', () => {
|
||||
cy.init('/languagecenterview', 'norights')
|
||||
cy.contains('Access denied')
|
||||
cy.contains("You're currently not allowed to see this page.")
|
||||
cy.contains("You don't currently have permission to view this page.")
|
||||
cy.contains('Special populations').click()
|
||||
cy.contains('Language center view').should('not.exist')
|
||||
})
|
||||
|
||||
@@ -165,7 +165,7 @@ describe('Population Statistics tests', () => {
|
||||
}
|
||||
|
||||
cy.get("[data-cy='credits-gained-table-body'] td:nth-child(3)").then($els => {
|
||||
const sum = [...$els].map($el => parseInt($el.innerText)).reduce((a, b) => a + b, 0)
|
||||
const sum = [...$els].map($el => parseInt($el.innerText, 10)).reduce((a, b) => a + b, 0)
|
||||
expect(sum).to.equal(170)
|
||||
})
|
||||
|
||||
@@ -182,7 +182,6 @@ describe('Population Statistics tests', () => {
|
||||
if (!$parentDiv.hasClass('active')) cy.get("[data-cy='Credit statistics']").click()
|
||||
})
|
||||
cy.contains('Credits gained').click()
|
||||
cy.get('.credits-gained-divider').click()
|
||||
cy.get("[data-cy='credits-gained-table-Avoin väylä']").should('exist')
|
||||
cy.get("[data-cy='credits-gained-table-Yhteispisteet']").should('exist')
|
||||
cy.get("[data-cy='credits-gained-table-Muu']").should('exist')
|
||||
@@ -198,8 +197,9 @@ describe('Population Statistics tests', () => {
|
||||
})
|
||||
cy.get("[data-cy='credit-stats-tab'] > .menu > :nth-child(2)").click()
|
||||
|
||||
cy.get("[data-cy='credit-stats-table-name-header']").should('contain', 'Statistic for n = 170 Students')
|
||||
cy.get("[data-cy='credit-stats-mean']").should('contain', '114.74')
|
||||
cy.get("[data-cy='credit-stats-population-size']").should('contain', 'n = 170')
|
||||
cy.get("[data-cy='credit-stats-average']").should('contain', '114.74')
|
||||
cy.get("[data-cy='credit-stats-median']").should('contain', '109.00')
|
||||
cy.get("[data-cy='credit-stats-stdev']").should('contain', '65.53')
|
||||
cy.get("[data-cy='credit-stats-min']").should('contain', '5')
|
||||
cy.get("[data-cy='credit-stats-max']").should('contain', '314')
|
||||
|
||||
@@ -64,6 +64,7 @@ describe('Students tests', () => {
|
||||
cy.get('.prompt').type(student.studentnumber)
|
||||
cy.contains('td a', student.studentnumber).click()
|
||||
cy.contains('Introduction to Machine Learning (DATA11002)')
|
||||
.parent()
|
||||
.siblings()
|
||||
.last()
|
||||
.within(() => {
|
||||
|
||||
@@ -15,7 +15,7 @@ describe('Study guidance group tests', () => {
|
||||
cy.init('/studyguidancegroups')
|
||||
cy.contains('Access denied')
|
||||
cy.contains(
|
||||
"You're currently not allowed to see this page. Please contant oodikone@helsinki.fi, if this is a mistake."
|
||||
"You don't currently have permission to view this page. If you believe this is a mistake, please contact oodikone@helsinki.fi."
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -79,14 +79,7 @@ describe('Study guidance group tests', () => {
|
||||
})
|
||||
|
||||
it('general tab of the students table has the correct columns', () => {
|
||||
const firstRowHeadings = [
|
||||
'Phone number',
|
||||
'Student number',
|
||||
'Credits',
|
||||
'Start year at uni',
|
||||
'Study programmes',
|
||||
'Tags',
|
||||
]
|
||||
const firstRowHeadings = ['Student number', 'Credits', 'Start year at uni', 'Study programmes', 'Tags']
|
||||
const secondRowHeadings = ['All', 'Since 1.1.1970']
|
||||
cy.cs('Students (2)').click()
|
||||
cy.get('[data-cy="student-table-tabs"] table thead tr').then($tr => {
|
||||
@@ -137,17 +130,14 @@ describe('Study guidance group tests', () => {
|
||||
|
||||
it('general tab of the students table has the correct columns', () => {
|
||||
const firstRowHeadings = [
|
||||
'Phone number',
|
||||
'Student number',
|
||||
'Credits',
|
||||
'Start of studyright',
|
||||
'Started in programme',
|
||||
'Semesters present',
|
||||
'Enrollment status',
|
||||
'Graduation date',
|
||||
'Start year at uni',
|
||||
'Other programmes',
|
||||
'Semesters present amount',
|
||||
'Transferred from',
|
||||
'Gender',
|
||||
'Citizenship',
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 13 KiB |
Generated
+6
-11
@@ -16,7 +16,7 @@
|
||||
"express": "^4.19.2",
|
||||
"express-async-errors": "^3.1.1",
|
||||
"lodash": "^4.17.21",
|
||||
"lru-cache": "^5.1.1",
|
||||
"lru-cache": "^10.2.2",
|
||||
"moment": "^2.30.1",
|
||||
"moment-timezone": "^0.5.37",
|
||||
"morgan": "^1.10.0",
|
||||
@@ -1317,11 +1317,11 @@
|
||||
"integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ=="
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
|
||||
"dependencies": {
|
||||
"yallist": "^3.0.2"
|
||||
"version": "10.2.2",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz",
|
||||
"integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==",
|
||||
"engines": {
|
||||
"node": "14 || >=16.14"
|
||||
}
|
||||
},
|
||||
"node_modules/luxon": {
|
||||
@@ -2494,11 +2494,6 @@
|
||||
"engines": {
|
||||
"node": ">=0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"express": "^4.19.2",
|
||||
"express-async-errors": "^3.1.1",
|
||||
"lodash": "^4.17.21",
|
||||
"lru-cache": "^5.1.1",
|
||||
"lru-cache": "^10.2.2",
|
||||
"moment": "^2.30.1",
|
||||
"moment-timezone": "^0.5.37",
|
||||
"morgan": "^1.10.0",
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
require('express-async-errors')
|
||||
const express = require('express')
|
||||
|
||||
const { baseUrl, backendPort } = require('./conf-backend')
|
||||
const routes = require('./routes')
|
||||
const { startCron } = require('./events')
|
||||
const { initializeDatabaseConnection, dbConnections } = require('./database/connection')
|
||||
const { startCron } = require('./events')
|
||||
const routes = require('./routes')
|
||||
const logger = require('./util/logger')
|
||||
require('./worker/worker')
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const Sequelize = require('sequelize')
|
||||
const EventEmitter = require('events')
|
||||
const Sequelize = require('sequelize')
|
||||
const Umzug = require('umzug')
|
||||
|
||||
const conf = require('../conf-backend')
|
||||
const logger = require('../util/logger')
|
||||
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
const { ARRAY, STRING } = require('sequelize')
|
||||
|
||||
module.exports = {
|
||||
up: async queryInterface => {
|
||||
await queryInterface.addColumn('users', 'roles', {
|
||||
type: ARRAY(STRING),
|
||||
allowNull: false,
|
||||
defaultValue: [],
|
||||
})
|
||||
await queryInterface.sequelize.query(`
|
||||
UPDATE users
|
||||
SET roles = COALESCE(subquery.roles, '{}')
|
||||
FROM (
|
||||
SELECT uag."userId" AS "userId", ARRAY_AGG(ag.group_code) AS roles
|
||||
FROM user_accessgroup uag
|
||||
JOIN access_groups ag ON uag."accessGroupId" = ag.id
|
||||
GROUP BY uag."userId"
|
||||
) AS subquery
|
||||
WHERE users.id = subquery."userId"
|
||||
`)
|
||||
await queryInterface.addColumn('users', 'programme_rights', {
|
||||
type: ARRAY(STRING),
|
||||
allowNull: false,
|
||||
defaultValue: [],
|
||||
})
|
||||
await queryInterface.sequelize.query(`
|
||||
UPDATE users
|
||||
SET programme_rights = subquery.programme_rights
|
||||
FROM (
|
||||
SELECT "userId", ARRAY_AGG("elementDetailCode") AS programme_rights
|
||||
FROM "user_elementdetails"
|
||||
GROUP BY "userId"
|
||||
) AS subquery
|
||||
WHERE users.id = subquery."userId"
|
||||
`)
|
||||
},
|
||||
down: async queryInterface => {
|
||||
await queryInterface.removeColumn('users', 'roles')
|
||||
await queryInterface.removeColumn('users', 'programme_rights')
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
up: async queryInterface => {
|
||||
await queryInterface.dropTable('user_faculties')
|
||||
},
|
||||
down: async () => {},
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
up: async queryInterface => {
|
||||
await queryInterface.dropTable('user_elementdetails')
|
||||
},
|
||||
down: async () => {},
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
up: async queryInterface => {
|
||||
await queryInterface.dropTable('user_accessgroup')
|
||||
},
|
||||
down: async () => {},
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
up: async queryInterface => {
|
||||
await queryInterface.dropTable('access_groups')
|
||||
},
|
||||
down: async () => {},
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
up: async queryInterface => {
|
||||
await queryInterface.removeColumn('users', 'iam_groups')
|
||||
},
|
||||
down: async () => {},
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
up: async queryInterface => {
|
||||
await queryInterface.dropTable('"Sessions"')
|
||||
},
|
||||
down: async () => {},
|
||||
}
|
||||
@@ -1,23 +1,24 @@
|
||||
const { CronJob } = require('cron')
|
||||
const { refreshAssociationsInRedis } = require('./services/studyrights')
|
||||
const { getAllProgrammes } = require('./services/studyrights')
|
||||
const { updateBasicView, updateStudytrackView } = require('./services/studyprogramme/studyprogrammeUpdates')
|
||||
const { findAndSaveTeachers } = require('./services/topteachers')
|
||||
const { faculties } = require('./services/organisations')
|
||||
const { combinedStudyprogrammes } = require('./services/studyprogramme/studyprogrammeHelpers')
|
||||
const { updateFacultyOverview, updateFacultyProgressOverview } = require('./services/faculty/facultyUpdates')
|
||||
|
||||
const { isProduction, runningInCI } = require('./conf-backend')
|
||||
const { getCurrentSemester } = require('./services/semesters')
|
||||
const logger = require('./util/logger')
|
||||
const { getAssociations } = require('./services/studyrights')
|
||||
const { redisClient } = require('./services/redis')
|
||||
const { updateFacultyOverview, updateFacultyProgressOverview } = require('./services/faculty/facultyUpdates')
|
||||
const { computeLanguageCenterData, LANGUAGE_CENTER_REDIS_KEY } = require('./services/languageCenterData')
|
||||
const { jobMaker } = require('./worker/queue')
|
||||
const { deleteOutdatedUsers } = require('./services/userService')
|
||||
const { faculties } = require('./services/organisations')
|
||||
const {
|
||||
findStudentsCloseToGraduation,
|
||||
CLOSE_TO_GRADUATION_REDIS_KEY,
|
||||
} = require('./services/populations/closeToGraduation')
|
||||
const { redisClient } = require('./services/redis')
|
||||
const { getCurrentSemester } = require('./services/semesters')
|
||||
const { combinedStudyprogrammes } = require('./services/studyprogramme/studyprogrammeHelpers')
|
||||
const { updateBasicView, updateStudytrackView } = require('./services/studyprogramme/studyprogrammeUpdates')
|
||||
const { refreshAssociationsInRedis } = require('./services/studyrights')
|
||||
const { getAllProgrammes } = require('./services/studyrights')
|
||||
const { getAssociations } = require('./services/studyrights')
|
||||
const { findAndSaveTeachers } = require('./services/topteachers')
|
||||
const { deleteOutdatedUsers } = require('./services/userService')
|
||||
const logger = require('./util/logger')
|
||||
const { jobMaker } = require('./worker/queue')
|
||||
|
||||
const schedule = (cronTime, func) => new CronJob({ cronTime, onTick: func, start: true, timeZone: 'Europe/Helsinki' })
|
||||
|
||||
@@ -112,7 +113,7 @@ const dailyJobs = () => {
|
||||
refreshProgrammes()
|
||||
jobMaker.languagecenter()
|
||||
jobMaker.statistics()
|
||||
refreshCloseToGraduating()
|
||||
jobMaker.closeToGraduation()
|
||||
}
|
||||
|
||||
const startCron = () => {
|
||||
@@ -124,8 +125,8 @@ const startCron = () => {
|
||||
})
|
||||
schedule('0 4 * * 3', async () => {
|
||||
logger.info("Deleting users who haven't logged in for 18 months")
|
||||
const numberOfDeletedUsers = await deleteOutdatedUsers()
|
||||
logger.info(`Deleted ${numberOfDeletedUsers} users.`)
|
||||
const [, result] = await deleteOutdatedUsers()
|
||||
logger.info(`Deleted ${result.rowCount} users.`)
|
||||
})
|
||||
schedule('0 19 * * 1', async () => {
|
||||
logger.info('Updating students whose studyplans have not been updated recently')
|
||||
@@ -146,4 +147,5 @@ module.exports = {
|
||||
refreshProgramme,
|
||||
refreshProgrammes,
|
||||
refreshLanguageCenterData,
|
||||
refreshCloseToGraduating,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const morgan = require('morgan')
|
||||
const logger = require('../util/logger')
|
||||
const _ = require('lodash')
|
||||
const morgan = require('morgan')
|
||||
|
||||
const logger = require('../util/logger')
|
||||
const { getFullStudyProgrammeRights } = require('../util/utils')
|
||||
|
||||
// So this appears to be a hack to get neatly formatted stats like response-time etc. from morgan
|
||||
@@ -28,8 +29,9 @@ const accessLogger = morgan((tokens, req, res) => {
|
||||
].join(' ')
|
||||
|
||||
const fullStudyProgrammeRights = getFullStudyProgrammeRights(user.programmeRights)
|
||||
const iamBasedRights = user.programmeRights.filter(right => right.isIamBased)
|
||||
|
||||
const usingIamRights = user.iamRights.some(programmeCode => tokens.url(req, res).includes(programmeCode))
|
||||
const usingIamRights = iamBasedRights.some(right => tokens.url(req, res).includes(right.code))
|
||||
const onlyIamRights = !user.isAdmin && fullStudyProgrammeRights.length === 0
|
||||
|
||||
logger.info(message, {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
const Sentry = require('@sentry/node')
|
||||
const { ApplicationError } = require('../util/customErrors')
|
||||
const { getUser, getMockedUser, getOrganizationAccess } = require('../services/userService')
|
||||
const { requiredGroup } = require('../conf-backend')
|
||||
const _ = require('lodash')
|
||||
|
||||
const { requiredGroup } = require('../conf-backend')
|
||||
const { getUser, getMockedUser, getOrganizationAccess } = require('../services/userService')
|
||||
const { ApplicationError } = require('../util/customErrors')
|
||||
const logger = require('../util/logger')
|
||||
|
||||
const parseIamGroups = iamGroups => iamGroups?.split(';').filter(Boolean) ?? []
|
||||
const parseIamGroups = iamGroups => iamGroups?.split(';') ?? []
|
||||
|
||||
const hasRequiredIamGroup = (iamGroups, iamRights) =>
|
||||
_.intersection(iamGroups, requiredGroup).length > 0 || iamRights.length > 0
|
||||
@@ -36,7 +37,7 @@ const currentUserMiddleware = async (req, _res, next) => {
|
||||
}
|
||||
|
||||
const iamGroups = parseIamGroups(hygroupcn)
|
||||
const { access = {}, specialGroup = {} } = await getOrganizationAccess({ id: sisId, iamGroups })
|
||||
const { access = {}, specialGroup = {} } = await getOrganizationAccess(sisId, iamGroups)
|
||||
const iamRights = Object.keys(access)
|
||||
|
||||
if (!hasRequiredIamGroup(iamGroups, iamRights)) {
|
||||
@@ -44,19 +45,12 @@ const currentUserMiddleware = async (req, _res, next) => {
|
||||
throw new ApplicationError(`User '${username}' does not have required iam group`, 403, { logoutUrl })
|
||||
}
|
||||
|
||||
let user = await getUser({
|
||||
username,
|
||||
name,
|
||||
email,
|
||||
iamGroups,
|
||||
iamRights,
|
||||
specialGroup,
|
||||
sisId,
|
||||
access,
|
||||
})
|
||||
let user
|
||||
|
||||
if (showAsUser && user.isAdmin) {
|
||||
if (showAsUser && specialGroup?.superAdmin) {
|
||||
user = await getMockedUser({ userToMock: showAsUser, mockedBy: username })
|
||||
} else {
|
||||
user = await getUser({ username, name, email, iamGroups, specialGroup, sisId, access })
|
||||
}
|
||||
|
||||
Sentry.setUser({ username: user.mockedBy ?? username })
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const Sentry = require('@sentry/node')
|
||||
|
||||
const { ApplicationError } = require('../util/customErrors')
|
||||
const logger = require('../util/logger')
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Model, STRING, DATE, JSONB, BOOLEAN } = require('sequelize')
|
||||
const { Model, BOOLEAN, DATE, JSONB, STRING } = require('sequelize')
|
||||
|
||||
const { dbConnections } = require('../database/connection')
|
||||
|
||||
class Course extends Model {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Model, STRING, DATE, JSONB } = require('sequelize')
|
||||
const { Model, DATE, JSONB, STRING } = require('sequelize')
|
||||
|
||||
const { dbConnections } = require('../database/connection')
|
||||
|
||||
class CourseProvider extends Model {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Model, STRING, DATE, JSONB } = require('sequelize')
|
||||
const { Model, DATE, JSONB, STRING } = require('sequelize')
|
||||
|
||||
const { dbConnections } = require('../database/connection')
|
||||
|
||||
class CourseType extends Model {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Model, DATE, INTEGER, STRING, DOUBLE, BOOLEAN } = require('sequelize')
|
||||
const { Model, BOOLEAN, DATE, DOUBLE, INTEGER, STRING } = require('sequelize')
|
||||
|
||||
const { dbConnections } = require('../database/connection')
|
||||
|
||||
class Credit extends Model {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Model, STRING, DATE } = require('sequelize')
|
||||
const { Model, DATE, STRING } = require('sequelize')
|
||||
|
||||
const { dbConnections } = require('../database/connection')
|
||||
|
||||
class CreditTeacher extends Model {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Model, INTEGER, DATE, JSONB } = require('sequelize')
|
||||
const { Model, DATE, INTEGER, JSONB } = require('sequelize')
|
||||
|
||||
const { dbConnections } = require('../database/connection')
|
||||
|
||||
class CreditType extends Model {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Model, INTEGER, DATE, JSONB, STRING } = require('sequelize')
|
||||
const { Model, DATE, INTEGER, JSONB, STRING } = require('sequelize')
|
||||
|
||||
const { dbConnections } = require('../database/connection')
|
||||
|
||||
class ElementDetail extends Model {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Model, DATE, INTEGER, STRING, BOOLEAN } = require('sequelize')
|
||||
const { Model, BOOLEAN, DATE, INTEGER, STRING } = require('sequelize')
|
||||
|
||||
const { dbConnections } = require('../database/connection')
|
||||
|
||||
class Enrollment extends Model {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Model, INTEGER, STRING, DATE } = require('sequelize')
|
||||
const { Model, DATE, INTEGER, STRING } = require('sequelize')
|
||||
|
||||
const { dbConnections } = require('../database/connection')
|
||||
|
||||
class ExcludedCourse extends Model {}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
const Organization = require('./organization')
|
||||
const CourseType = require('./courseType')
|
||||
const Course = require('./course')
|
||||
const Student = require('./student')
|
||||
const CourseProvider = require('./courseProvider')
|
||||
const Semester = require('./semester')
|
||||
const SemesterEnrollment = require('./semesterEnrollment')
|
||||
const Teacher = require('./teacher')
|
||||
const CreditType = require('./creditType')
|
||||
const CourseType = require('./courseType')
|
||||
const Credit = require('./credit')
|
||||
const CreditTeacher = require('./creditTeacher')
|
||||
const CreditType = require('./creditType')
|
||||
const ElementDetail = require('./elementDetail')
|
||||
const Studyplan = require('./studyplan')
|
||||
const StudyrightExtent = require('./studyrightExtent')
|
||||
const Studyright = require('./studyright')
|
||||
const StudyrightElement = require('./studyrightElement')
|
||||
const Transfer = require('./transfer')
|
||||
const Enrollment = require('./enrollment')
|
||||
const ExcludedCourse = require('./excludedCourse')
|
||||
const Organization = require('./organization')
|
||||
const ProgrammeModule = require('./programmeModule')
|
||||
const ProgrammeModuleChild = require('./programmeModuleChild')
|
||||
const ExcludedCourse = require('./excludedCourse')
|
||||
const Enrollment = require('./enrollment')
|
||||
const Semester = require('./semester')
|
||||
const SemesterEnrollment = require('./semesterEnrollment')
|
||||
const Student = require('./student')
|
||||
const Studyplan = require('./studyplan')
|
||||
const Studyright = require('./studyright')
|
||||
const StudyrightElement = require('./studyrightElement')
|
||||
const StudyrightExtent = require('./studyrightExtent')
|
||||
const Teacher = require('./teacher')
|
||||
const Transfer = require('./transfer')
|
||||
|
||||
CourseType.hasMany(Course, { foreignKey: 'coursetypecode', sourceKey: 'coursetypecode' })
|
||||
Course.belongsTo(CourseType, { foreignKey: 'coursetypecode', targetKey: 'coursetypecode' })
|
||||
@@ -121,25 +121,25 @@ ProgrammeModule.belongsToMany(ProgrammeModule, {
|
||||
Organization.hasMany(Organization, { foreignKey: 'parent_id', as: 'children' })
|
||||
|
||||
module.exports = {
|
||||
Organization,
|
||||
Course,
|
||||
CourseType,
|
||||
Student,
|
||||
CourseProvider,
|
||||
Semester,
|
||||
SemesterEnrollment,
|
||||
Teacher,
|
||||
CreditType,
|
||||
CourseType,
|
||||
Credit,
|
||||
CreditTeacher,
|
||||
CreditType,
|
||||
ElementDetail,
|
||||
Enrollment,
|
||||
ExcludedCourse,
|
||||
Organization,
|
||||
ProgrammeModule,
|
||||
ProgrammeModuleChild,
|
||||
Semester,
|
||||
SemesterEnrollment,
|
||||
Student,
|
||||
Studyplan,
|
||||
StudyrightExtent,
|
||||
Studyright,
|
||||
StudyrightElement,
|
||||
Teacher,
|
||||
Transfer,
|
||||
ProgrammeModule,
|
||||
ProgrammeModuleChild,
|
||||
ExcludedCourse,
|
||||
Enrollment,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const { STRING } = require('sequelize')
|
||||
const Sequelize = require('sequelize')
|
||||
const { ARRAY, BIGINT, DATE, INTEGER, STRING } = require('sequelize')
|
||||
|
||||
const { sequelizeKone } = require('../database/connection')
|
||||
|
||||
const ExcludedCourse = sequelizeKone.define(
|
||||
@@ -7,23 +7,23 @@ const ExcludedCourse = sequelizeKone.define(
|
||||
{
|
||||
id: {
|
||||
primaryKey: true,
|
||||
type: Sequelize.INTEGER,
|
||||
type: INTEGER,
|
||||
autoIncrement: true,
|
||||
},
|
||||
programme_code: {
|
||||
type: Sequelize.STRING,
|
||||
type: STRING,
|
||||
},
|
||||
curriculum_version: {
|
||||
type: STRING,
|
||||
},
|
||||
course_code: {
|
||||
type: Sequelize.STRING,
|
||||
type: STRING,
|
||||
},
|
||||
created_at: {
|
||||
type: Sequelize.DATE,
|
||||
type: DATE,
|
||||
},
|
||||
updated_at: {
|
||||
type: Sequelize.DATE,
|
||||
type: DATE,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -36,11 +36,11 @@ const TagStudent = sequelizeKone.define(
|
||||
{
|
||||
studentnumber: {
|
||||
primaryKey: true,
|
||||
type: Sequelize.STRING,
|
||||
type: STRING,
|
||||
},
|
||||
tag_id: {
|
||||
primaryKey: true,
|
||||
type: Sequelize.BIGINT,
|
||||
type: BIGINT,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -52,21 +52,21 @@ const Tag = sequelizeKone.define(
|
||||
'tag',
|
||||
{
|
||||
tagname: {
|
||||
type: Sequelize.STRING,
|
||||
type: STRING,
|
||||
},
|
||||
tag_id: {
|
||||
primaryKey: true,
|
||||
type: Sequelize.BIGINT,
|
||||
type: BIGINT,
|
||||
autoIncrement: true,
|
||||
},
|
||||
studytrack: {
|
||||
type: Sequelize.STRING,
|
||||
type: STRING,
|
||||
},
|
||||
year: {
|
||||
type: Sequelize.STRING,
|
||||
type: STRING,
|
||||
},
|
||||
personal_user_id: {
|
||||
type: Sequelize.BIGINT,
|
||||
type: BIGINT,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -77,17 +77,17 @@ const Tag = sequelizeKone.define(
|
||||
const CustomPopulationSearch = sequelizeKone.define('custom_population_searches', {
|
||||
id: {
|
||||
primaryKey: true,
|
||||
type: Sequelize.BIGINT,
|
||||
type: BIGINT,
|
||||
autoIncrement: true,
|
||||
},
|
||||
userId: {
|
||||
type: Sequelize.BIGINT,
|
||||
type: BIGINT,
|
||||
},
|
||||
name: {
|
||||
type: Sequelize.STRING,
|
||||
type: STRING,
|
||||
},
|
||||
students: {
|
||||
type: Sequelize.ARRAY(Sequelize.STRING),
|
||||
type: ARRAY(STRING),
|
||||
},
|
||||
})
|
||||
|
||||
@@ -97,18 +97,18 @@ const OpenUniPopulationSearch = sequelizeKone.define(
|
||||
{
|
||||
id: {
|
||||
primaryKey: true,
|
||||
type: Sequelize.BIGINT,
|
||||
type: BIGINT,
|
||||
autoIncrement: true,
|
||||
},
|
||||
userId: {
|
||||
type: Sequelize.BIGINT,
|
||||
type: BIGINT,
|
||||
},
|
||||
name: {
|
||||
type: Sequelize.STRING,
|
||||
type: STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
courseCodes: {
|
||||
type: Sequelize.ARRAY(Sequelize.STRING),
|
||||
type: ARRAY(STRING),
|
||||
},
|
||||
},
|
||||
{ underscored: true, timestamps: true }
|
||||
@@ -125,40 +125,40 @@ const ProgressCriteria = sequelizeKone.define(
|
||||
type: STRING,
|
||||
},
|
||||
coursesYearOne: {
|
||||
type: Sequelize.ARRAY(Sequelize.STRING),
|
||||
type: ARRAY(STRING),
|
||||
},
|
||||
coursesYearTwo: {
|
||||
type: Sequelize.ARRAY(Sequelize.STRING),
|
||||
type: ARRAY(STRING),
|
||||
},
|
||||
coursesYearThree: {
|
||||
type: Sequelize.ARRAY(Sequelize.STRING),
|
||||
type: ARRAY(STRING),
|
||||
},
|
||||
coursesYearFour: {
|
||||
type: Sequelize.ARRAY(Sequelize.STRING),
|
||||
type: ARRAY(STRING),
|
||||
},
|
||||
coursesYearFive: {
|
||||
type: Sequelize.ARRAY(Sequelize.STRING),
|
||||
type: ARRAY(STRING),
|
||||
},
|
||||
coursesYearSix: {
|
||||
type: Sequelize.ARRAY(Sequelize.STRING),
|
||||
type: ARRAY(STRING),
|
||||
},
|
||||
creditsYearOne: {
|
||||
type: Sequelize.INTEGER,
|
||||
type: INTEGER,
|
||||
},
|
||||
creditsYearTwo: {
|
||||
type: Sequelize.INTEGER,
|
||||
type: INTEGER,
|
||||
},
|
||||
creditsYearThree: {
|
||||
type: Sequelize.INTEGER,
|
||||
type: INTEGER,
|
||||
},
|
||||
creditsYearFour: {
|
||||
type: Sequelize.INTEGER,
|
||||
type: INTEGER,
|
||||
},
|
||||
creditsYearFive: {
|
||||
type: Sequelize.INTEGER,
|
||||
type: INTEGER,
|
||||
},
|
||||
creditsYearSix: {
|
||||
type: Sequelize.INTEGER,
|
||||
type: INTEGER,
|
||||
},
|
||||
},
|
||||
{ underscored: true, timestamps: true }
|
||||
@@ -169,18 +169,18 @@ const StudyGuidanceGroupTag = sequelizeKone.define(
|
||||
{
|
||||
id: {
|
||||
primaryKey: true,
|
||||
type: Sequelize.BIGINT,
|
||||
type: BIGINT,
|
||||
autoIncrement: true,
|
||||
},
|
||||
studyGuidanceGroupId: {
|
||||
type: Sequelize.STRING,
|
||||
type: STRING,
|
||||
unique: true,
|
||||
},
|
||||
studyProgramme: {
|
||||
type: Sequelize.STRING,
|
||||
type: STRING,
|
||||
},
|
||||
year: {
|
||||
type: Sequelize.STRING,
|
||||
type: STRING,
|
||||
},
|
||||
},
|
||||
{ underscored: true, timestamps: true }
|
||||
@@ -191,10 +191,10 @@ const StudyProgrammePin = sequelizeKone.define(
|
||||
{
|
||||
userId: {
|
||||
primaryKey: true,
|
||||
type: Sequelize.INTEGER,
|
||||
type: INTEGER,
|
||||
},
|
||||
studyProgrammes: {
|
||||
type: Sequelize.ARRAY(Sequelize.STRING),
|
||||
type: ARRAY(STRING),
|
||||
},
|
||||
},
|
||||
{ underscored: true, timestamps: false }
|
||||
@@ -204,12 +204,12 @@ TagStudent.belongsTo(Tag, { foreignKey: 'tag_id', sourceKey: 'tag_id' })
|
||||
Tag.hasMany(TagStudent, { foreignKey: 'tag_id', sourceKey: 'tag_id' })
|
||||
|
||||
module.exports = {
|
||||
TagStudent,
|
||||
Tag,
|
||||
CustomPopulationSearch,
|
||||
OpenUniPopulationSearch,
|
||||
ExcludedCourse,
|
||||
StudyGuidanceGroupTag,
|
||||
OpenUniPopulationSearch,
|
||||
ProgressCriteria,
|
||||
StudyGuidanceGroupTag,
|
||||
StudyProgrammePin,
|
||||
Tag,
|
||||
TagStudent,
|
||||
}
|
||||
|
||||
@@ -1,85 +1,42 @@
|
||||
const Sequelize = require('sequelize')
|
||||
const { ARRAY, BIGINT, DATE, STRING } = require('sequelize')
|
||||
|
||||
const { sequelizeUser } = require('../database/connection')
|
||||
|
||||
const UserElementDetails = sequelizeUser.define(
|
||||
'user_elementdetails',
|
||||
{
|
||||
userId: {
|
||||
primaryKey: true,
|
||||
type: Sequelize.BIGINT,
|
||||
},
|
||||
elementDetailCode: {
|
||||
primaryKey: true,
|
||||
type: Sequelize.STRING,
|
||||
},
|
||||
},
|
||||
{
|
||||
tablename: 'user_elementdetails',
|
||||
}
|
||||
)
|
||||
|
||||
const AccessGroup = sequelizeUser.define('access_group', {
|
||||
id: {
|
||||
primaryKey: true,
|
||||
type: Sequelize.BIGINT,
|
||||
autoIncrement: true,
|
||||
},
|
||||
group_code: {
|
||||
type: Sequelize.STRING,
|
||||
unique: true,
|
||||
},
|
||||
group_info: {
|
||||
type: Sequelize.STRING,
|
||||
},
|
||||
createdAt: {
|
||||
type: Sequelize.DATE,
|
||||
},
|
||||
updatedAt: {
|
||||
type: Sequelize.DATE,
|
||||
},
|
||||
})
|
||||
|
||||
const User = sequelizeUser.define(
|
||||
'users',
|
||||
{
|
||||
id: {
|
||||
primaryKey: true,
|
||||
type: Sequelize.BIGINT,
|
||||
type: BIGINT,
|
||||
autoIncrement: true,
|
||||
},
|
||||
full_name: { type: Sequelize.STRING },
|
||||
fullName: STRING,
|
||||
username: {
|
||||
type: Sequelize.STRING,
|
||||
type: STRING,
|
||||
unique: true,
|
||||
},
|
||||
email: { type: Sequelize.STRING },
|
||||
language: { type: Sequelize.STRING },
|
||||
sisu_person_id: { type: Sequelize.STRING },
|
||||
iam_groups: {
|
||||
type: Sequelize.ARRAY(Sequelize.STRING),
|
||||
email: STRING,
|
||||
language: STRING,
|
||||
sisuPersonId: STRING,
|
||||
lastLogin: DATE,
|
||||
roles: {
|
||||
type: ARRAY(STRING),
|
||||
allowNull: false,
|
||||
defaultValue: [],
|
||||
},
|
||||
programmeRights: {
|
||||
type: ARRAY(STRING),
|
||||
allowNull: false,
|
||||
defaultValue: [],
|
||||
},
|
||||
last_login: { type: Sequelize.DATE },
|
||||
},
|
||||
{
|
||||
tableName: 'users',
|
||||
timestamps: false,
|
||||
underscored: true,
|
||||
}
|
||||
)
|
||||
|
||||
User.hasMany(UserElementDetails, { as: 'programme' })
|
||||
UserElementDetails.belongsTo(User)
|
||||
|
||||
User.belongsToMany(AccessGroup, {
|
||||
through: 'user_accessgroup',
|
||||
as: 'accessgroup',
|
||||
})
|
||||
AccessGroup.belongsToMany(User, { through: 'user_accessgroup' })
|
||||
|
||||
module.exports = {
|
||||
User,
|
||||
UserElementDetails,
|
||||
AccessGroup,
|
||||
sequelizeUser,
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Model, STRING, DATE, JSONB } = require('sequelize')
|
||||
const { Model, DATE, JSONB, STRING } = require('sequelize')
|
||||
|
||||
const { dbConnections } = require('../database/connection')
|
||||
|
||||
class Organization extends Model {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Model, STRING, DATE, INTEGER, JSONB, ARRAY, TEXT } = require('sequelize')
|
||||
const { Model, ARRAY, DATE, INTEGER, JSONB, STRING, TEXT } = require('sequelize')
|
||||
|
||||
const { dbConnections } = require('../database/connection')
|
||||
|
||||
class ProgrammeModule extends Model {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Model, STRING, DATE } = require('sequelize')
|
||||
const { Model, DATE, STRING } = require('sequelize')
|
||||
|
||||
const { dbConnections } = require('../database/connection')
|
||||
|
||||
class ProgrammeModuleChild extends Model {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Model, STRING, DATE, JSONB, INTEGER } = require('sequelize')
|
||||
const { Model, DATE, INTEGER, JSONB, STRING } = require('sequelize')
|
||||
|
||||
const { dbConnections } = require('../database/connection')
|
||||
|
||||
class Semester extends Model {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Model, STRING, DATE, INTEGER, BOOLEAN } = require('sequelize')
|
||||
const { Model, BOOLEAN, DATE, INTEGER, STRING } = require('sequelize')
|
||||
|
||||
const { dbConnections } = require('../database/connection')
|
||||
|
||||
class SemesterEnrollment extends Model {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Model, STRING, DATE, INTEGER } = require('sequelize')
|
||||
const { Model, DATE, INTEGER, STRING } = require('sequelize')
|
||||
|
||||
const { dbConnections } = require('../database/connection')
|
||||
|
||||
class Student extends Model {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Model, DATE, ARRAY, STRING, INTEGER } = require('sequelize')
|
||||
const { Model, ARRAY, DATE, INTEGER, STRING } = require('sequelize')
|
||||
|
||||
const { dbConnections } = require('../database/connection')
|
||||
|
||||
class Studyplan extends Model {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Model, STRING, DATE, INTEGER, BOOLEAN, JSONB } = require('sequelize')
|
||||
const { Model, BOOLEAN, DATE, INTEGER, JSONB, STRING } = require('sequelize')
|
||||
|
||||
const { dbConnections } = require('../database/connection')
|
||||
|
||||
class Studyright extends Model {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Model, STRING, DATE } = require('sequelize')
|
||||
const { Model, DATE, STRING } = require('sequelize')
|
||||
|
||||
const { dbConnections } = require('../database/connection')
|
||||
|
||||
class StudyrightElement extends Model {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Model, INTEGER, DATE, JSONB } = require('sequelize')
|
||||
const { Model, DATE, INTEGER, JSONB } = require('sequelize')
|
||||
|
||||
const { dbConnections } = require('../database/connection')
|
||||
|
||||
class StudyrightExtent extends Model {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Model, STRING, DATE } = require('sequelize')
|
||||
const { Model, DATE, STRING } = require('sequelize')
|
||||
|
||||
const { dbConnections } = require('../database/connection')
|
||||
|
||||
class Teacher extends Model {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Model, STRING, DATE } = require('sequelize')
|
||||
const { Model, DATE, STRING } = require('sequelize')
|
||||
|
||||
const { dbConnections } = require('../database/connection')
|
||||
|
||||
class Transfer extends Model {}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/* eslint-disable no-console */
|
||||
const { computeCreditsProduced } = require('../services/providerCredits')
|
||||
const { parseCsv } = require('./helpers')
|
||||
const _ = require('lodash')
|
||||
|
||||
const { parseCsv } = require('./helpers')
|
||||
const { computeCreditsProduced } = require('../services/providerCredits')
|
||||
|
||||
const diffs = []
|
||||
const noDiffCounter = 0
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable no-console */
|
||||
const Papa = require('papaparse')
|
||||
const fs = require('fs/promises')
|
||||
const Papa = require('papaparse')
|
||||
|
||||
const parseCsv = async (fileName, fun) => {
|
||||
try {
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
/* eslint-disable no-console */
|
||||
|
||||
const axios = require('axios').default
|
||||
|
||||
const _ = require('lodash')
|
||||
|
||||
const { optimizedStatisticsOf } = require('../services/populations')
|
||||
const { Student, Transfer, StudyrightElement, Studyright } = require('../models')
|
||||
const { rapoToken, tokenImporterApi, importerDbApiUrl, nodeproxyUrl } = require('./conf')
|
||||
const { Student, Transfer, StudyrightElement, Studyright } = require('../models')
|
||||
const { optimizedStatisticsOf } = require('../services/populations')
|
||||
|
||||
const getFromRapo = async (urlStart, urlEnd) => {
|
||||
console.log({ urlStart, urlEnd })
|
||||
|
||||
@@ -1,40 +1,39 @@
|
||||
const Sentry = require('@sentry/node')
|
||||
const express = require('express')
|
||||
const cors = require('cors')
|
||||
const express = require('express')
|
||||
|
||||
const { frontUrl } = require('./conf-backend')
|
||||
const shibbolethCharsetMiddleware = require('./middleware/shibbolethCharsetMiddleware')
|
||||
const currentUserMiddleware = require('./middleware/currentUserMiddleware')
|
||||
const accessLogger = require('./middleware/accessLogger')
|
||||
const auth = require('./middleware/auth')
|
||||
const currentUserMiddleware = require('./middleware/currentUserMiddleware')
|
||||
const errorMiddleware = require('./middleware/errorMiddleware')
|
||||
const shibbolethCharsetMiddleware = require('./middleware/shibbolethCharsetMiddleware')
|
||||
const changelog = require('./routes/changelog')
|
||||
const courses = require('./routes/courses')
|
||||
const students = require('./routes/students')
|
||||
const population = require('./routes/population')
|
||||
const login = require('./routes/login')
|
||||
const language = require('./routes/language')
|
||||
const users = require('./routes/users')
|
||||
const elementdetails = require('./routes/elementdetails')
|
||||
const teachers = require('./routes/teachers')
|
||||
const providers = require('./routes/providers')
|
||||
const faculties = require('./routes/faculties')
|
||||
const university = require('./routes/university')
|
||||
const closeToGraduation = require('./routes/closeToGraduation')
|
||||
const completedCoursesSearch = require('./routes/completedCoursesSearch')
|
||||
const courseExclusions = require('./routes/courseExclusions')
|
||||
const semesters = require('./routes/semesters')
|
||||
const feedback = require('./routes/feedback')
|
||||
const tags = require('./routes/tags')
|
||||
const updater = require('./routes/updater')
|
||||
const courses = require('./routes/courses')
|
||||
const customOpenUniSearch = require('./routes/customOpenUniSearch')
|
||||
const customPopulationSearch = require('./routes/customPopulationSearch')
|
||||
const elementdetails = require('./routes/elementdetails')
|
||||
const faculties = require('./routes/faculties')
|
||||
const feedback = require('./routes/feedback')
|
||||
const languageCenterData = require('./routes/languageCenterData')
|
||||
const login = require('./routes/login')
|
||||
const population = require('./routes/population')
|
||||
const programmeModules = require('./routes/programmeModules')
|
||||
const providers = require('./routes/providers')
|
||||
const semesters = require('./routes/semesters')
|
||||
const students = require('./routes/students')
|
||||
const studyGuidanceGroups = require('./routes/studyGuidanceGroups')
|
||||
const studyProgramme = require('./routes/studyProgramme')
|
||||
const customOpenUniSearch = require('./routes/customOpenUniSearch')
|
||||
const studyProgrammeCriteria = require('./routes/studyProgrammeCriteria')
|
||||
const completedCoursesSearch = require('./routes/completedCoursesSearch')
|
||||
const closeToGraduation = require('./routes/closeToGraduation')
|
||||
const studyProgrammePins = require('./routes/studyProgrammePins')
|
||||
const tags = require('./routes/tags')
|
||||
const teachers = require('./routes/teachers')
|
||||
const university = require('./routes/university')
|
||||
const updater = require('./routes/updater')
|
||||
const users = require('./routes/users')
|
||||
const initializeSentry = require('./util/sentry')
|
||||
|
||||
module.exports = (app, url) => {
|
||||
@@ -53,7 +52,6 @@ module.exports = (app, url) => {
|
||||
app.use(url, courses)
|
||||
app.use(url, students)
|
||||
app.use(url, population)
|
||||
app.use(url, language)
|
||||
app.use(url, providers)
|
||||
app.use(url, semesters)
|
||||
app.use(url, tags)
|
||||
@@ -69,11 +67,11 @@ module.exports = (app, url) => {
|
||||
app.use(`${url}/university`, university)
|
||||
app.use(`${url}/updater`, auth.roles(['admin']), updater)
|
||||
app.use(`${url}/teachers`, auth.roles(['teachers']), teachers)
|
||||
app.use(`${url}/users`, auth.roles(['admin']), users)
|
||||
app.use(`${url}/users`, users)
|
||||
app.use(`${url}/feedback`, feedback)
|
||||
app.use(`${url}/custom-population-search`, customPopulationSearch)
|
||||
app.use(`${url}/studyguidancegroups`, auth.roles(['studyGuidanceGroups']), studyGuidanceGroups)
|
||||
app.use(`${url}/close-to-graduation`, auth.roles(['fullSisuAccess']), closeToGraduation)
|
||||
app.use(`${url}/close-to-graduation`, auth.roles(['fullSisuAccess', 'studyGuidanceGroups']), closeToGraduation)
|
||||
app.use(`${url}/study-programme-pins`, studyProgrammePins)
|
||||
app.get('*', async (_, res) => {
|
||||
const results = { error: 'unknown endpoint' }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const router = require('express').Router()
|
||||
const axios = require('axios')
|
||||
const router = require('express').Router()
|
||||
|
||||
const { isDev } = require('../conf-backend')
|
||||
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
const { getCloseToGraduationData } = require('../services/populations/closeToGraduation')
|
||||
|
||||
const router = require('express').Router()
|
||||
|
||||
router.get('/', async (_req, res) => {
|
||||
const result = await getCloseToGraduationData()
|
||||
const { getCloseToGraduationData } = require('../services/populations/closeToGraduation')
|
||||
const { getAllStudentsUserHasInGroups } = require('../services/studyGuidanceGroups')
|
||||
const { hasFullAccessToStudentData } = require('../util/utils')
|
||||
|
||||
router.get('/', async (req, res) => {
|
||||
if (hasFullAccessToStudentData(req.user.roles)) {
|
||||
const result = await getCloseToGraduationData()
|
||||
return res.json(result)
|
||||
}
|
||||
const studentsInUsersGuidanceGroups = await getAllStudentsUserHasInGroups(req.user.sisPersonId)
|
||||
const result = await getCloseToGraduationData(studentsInUsersGuidanceGroups)
|
||||
res.json(result)
|
||||
})
|
||||
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
const router = require('express').Router()
|
||||
const { getCompletedCourses } = require('../services/completedCoursesSearch')
|
||||
const { getImporterClient } = require('../util/importerClient')
|
||||
|
||||
const importerClient = getImporterClient()
|
||||
const _ = require('lodash')
|
||||
|
||||
const { getCompletedCourses } = require('../services/completedCoursesSearch')
|
||||
const {
|
||||
getOpenUniSearches,
|
||||
createNewSearch,
|
||||
deleteSearch,
|
||||
updateSearch,
|
||||
} = require('../services/openUni/openUniManageSearches')
|
||||
const { getImporterClient } = require('../util/importerClient')
|
||||
const logger = require('../util/logger')
|
||||
const { hasFullAccessToStudentData } = require('../util/utils')
|
||||
|
||||
const importerClient = getImporterClient()
|
||||
|
||||
router.get('/', async (req, res) => {
|
||||
const studentNumbers = JSON.parse(req.query?.studentlist) || []
|
||||
const courseCodes = JSON.parse(req.query?.courselist) || []
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const router = require('express').Router()
|
||||
|
||||
const { addExcludedCourses, removeExcludedCourses } = require('../services/excludedCourses')
|
||||
|
||||
router.delete('/v3/course_exclusions/:code', async (req, res) => {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
const router = require('express').Router()
|
||||
const crypto = require('crypto')
|
||||
const router = require('express').Router()
|
||||
|
||||
const courseService = require('../services/courses')
|
||||
const { faculties } = require('../services/organisations')
|
||||
const { validateParamLength } = require('../util')
|
||||
const { getFullStudyProgrammeRights } = require('../util/utils')
|
||||
const { getFullStudyProgrammeRights, hasFullAccessToStudentData } = require('../util/utils')
|
||||
|
||||
router.get('/v2/coursesmulti', async (req, res) => {
|
||||
let results = { courses: [] }
|
||||
@@ -38,12 +38,12 @@ router.get('/v3/courseyearlystats', async (req, res) => {
|
||||
user: { roles, programmeRights },
|
||||
} = req
|
||||
|
||||
const allowedRoles = roles && ['admin', 'courseStatistics'].find(role => roles.includes(role))
|
||||
const userHasFullAccessToStudentData = hasFullAccessToStudentData(roles)
|
||||
const userHasCorrectRole = userHasFullAccessToStudentData || roles.includes('courseStatistics')
|
||||
const fullStudyProgrammeRights = getFullStudyProgrammeRights(programmeRights)
|
||||
|
||||
// If user has rights to see at least one programme, then they are allowed
|
||||
// to see all of them
|
||||
if (!allowedRoles && fullStudyProgrammeRights.length === 0) {
|
||||
// If user has rights to see at least one programme, then they are allowed to see all of them
|
||||
if (!userHasCorrectRole && fullStudyProgrammeRights.length === 0) {
|
||||
return res.status(403).json({ error: 'No programmes so no access to course stats' })
|
||||
}
|
||||
|
||||
@@ -54,18 +54,13 @@ router.get('/v3/courseyearlystats', async (req, res) => {
|
||||
if (!codes) {
|
||||
res.status(422).send('Missing required query parameters')
|
||||
} else {
|
||||
// Studentnumbers should be obfuscated to all other users except admins
|
||||
// and users with rights to any specific study programmes
|
||||
const anonymize = allowedRoles !== 'admin' && fullStudyProgrammeRights.length === 0
|
||||
// Student numbers should be obfuscated to all other users except admins,
|
||||
// fullSisuAccess users, and users with rights to any specific study programmes
|
||||
const anonymize = !userHasFullAccessToStudentData && fullStudyProgrammeRights.length === 0
|
||||
const anonymizationSalt = anonymize ? crypto.randomBytes(12).toString('hex') : null
|
||||
const results = await courseService.courseYearlyStats(codes, separate, anonymizationSalt, combineSubstitutions)
|
||||
res.json(results)
|
||||
}
|
||||
})
|
||||
|
||||
router.get('/faculties-only', async (_req, res) => {
|
||||
const facultyList = await faculties()
|
||||
res.json(facultyList)
|
||||
})
|
||||
|
||||
module.exports = router
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
const router = require('express').Router()
|
||||
const moment = require('moment-timezone')
|
||||
const { getCustomOpenUniCourses } = require('../services/openUni/openUniStats')
|
||||
|
||||
const {
|
||||
getOpenUniSearches,
|
||||
createNewSearch,
|
||||
deleteSearch,
|
||||
updateSearch,
|
||||
} = require('../services/openUni/openUniManageSearches')
|
||||
const { getCustomOpenUniCourses } = require('../services/openUni/openUniStats')
|
||||
|
||||
router.get('/', async (req, res) => {
|
||||
const courseCodes = JSON.parse(req.query?.courselist) || []
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const router = require('express').Router()
|
||||
|
||||
const {
|
||||
getCustomPopulationSearchesByUser,
|
||||
createCustomPopulationSearch,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const router = require('express').Router()
|
||||
|
||||
const { getAllProgrammes, getAllElementDetails } = require('../services/studyrights')
|
||||
|
||||
router.get('/elementdetails/all', async (_req, res) => {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
const router = require('express').Router()
|
||||
|
||||
const auth = require('../middleware/auth')
|
||||
const { combineFacultyBasics } = require('../services/faculty/facultyBasics')
|
||||
const { getFacultyCredits } = require('../services/faculty/facultyCredits')
|
||||
const { combineFacultyThesisWriters } = require('../services/faculty/facultyThesisWriters')
|
||||
const { countGraduationTimes } = require('../services/faculty/facultyGraduationTimes')
|
||||
const { updateFacultyOverview, updateFacultyProgressOverview } = require('../services/faculty/facultyUpdates')
|
||||
const { combineFacultyStudentProgress } = require('../services/faculty/facultyStudentProgress')
|
||||
const { combineFacultyStudents } = require('../services/faculty/facultyStudents')
|
||||
const { getFacultyList } = require('../services/faculty/facultyHelpers')
|
||||
const {
|
||||
getProgrammes,
|
||||
getBasicStats,
|
||||
@@ -19,9 +18,11 @@ const {
|
||||
getFacultyProgressStats,
|
||||
setFacultyProgressStats,
|
||||
} = require('../services/faculty/facultyService')
|
||||
const { combineFacultyStudentProgress } = require('../services/faculty/facultyStudentProgress')
|
||||
const { combineFacultyStudents } = require('../services/faculty/facultyStudents')
|
||||
const { combineFacultyThesisWriters } = require('../services/faculty/facultyThesisWriters')
|
||||
const { updateFacultyOverview, updateFacultyProgressOverview } = require('../services/faculty/facultyUpdates')
|
||||
const logger = require('../util/logger')
|
||||
const { getFacultyList } = require('../services/faculty/facultyHelpers')
|
||||
const auth = require('../middleware/auth')
|
||||
|
||||
// Faculty uses a lot of tools designed for Study programme.
|
||||
// Some of them have been copied here and slightly edited for faculty purpose.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const router = require('express').Router()
|
||||
|
||||
const { sendFeedbackToToska } = require('../services/mailservice')
|
||||
const logger = require('../util/logger')
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
const router = require('express').Router()
|
||||
const userService = require('../services/userService')
|
||||
|
||||
router.post('/language', async (req, res) => {
|
||||
const {
|
||||
body: { language },
|
||||
user: { userId },
|
||||
} = req
|
||||
if (!['fi', 'sv', 'en'].includes(language)) {
|
||||
return res.status(400).json('invalid language')
|
||||
}
|
||||
try {
|
||||
const result = await userService.updateUser(userId, { language })
|
||||
return res.status(200).json(result)
|
||||
} catch (e) {
|
||||
return res.status(e.response.status).json(e.response.data)
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = router
|
||||
@@ -1,4 +1,5 @@
|
||||
const router = require('express').Router()
|
||||
|
||||
const { getLanguageCenterData } = require('../services/languageCenterData')
|
||||
|
||||
router.get('/', async (req, res) => {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
const router = require('express').Router()
|
||||
const { ApplicationError } = require('../util/customErrors')
|
||||
const _ = require('lodash')
|
||||
|
||||
const { ApplicationError } = require('../util/customErrors')
|
||||
|
||||
router.get('/login', async (req, res) => {
|
||||
const { user, logoutUrl } = req
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
const crypto = require('crypto')
|
||||
const Sentry = require('@sentry/node')
|
||||
const crypto = require('crypto')
|
||||
const router = require('express').Router()
|
||||
const _ = require('lodash')
|
||||
const populationService = require('../services/populations')
|
||||
const studentService = require('../services/students')
|
||||
const StudyrightService = require('../services/studyrights')
|
||||
const CourseService = require('../services/courses')
|
||||
const StatMergeService = require('../services/statMerger')
|
||||
const { mapToProviders, getFullStudyProgrammeRights, hasFullAccessToStudentData } = require('../util/utils')
|
||||
const { encrypt, decrypt } = require('../services/encrypt')
|
||||
const { mapCodesToIds } = require('../services/studyprogramme/studyprogrammeHelpers')
|
||||
|
||||
const courseService = require('../services/courses')
|
||||
const { encrypt, decrypt } = require('../services/encrypt')
|
||||
const populationService = require('../services/populations')
|
||||
const statMergeService = require('../services/statMerger')
|
||||
const studentService = require('../services/students')
|
||||
const { mapCodesToIds } = require('../services/studyprogramme/studyprogrammeHelpers')
|
||||
const studyrightService = require('../services/studyrights')
|
||||
const { ApplicationError } = require('../util/customErrors')
|
||||
const { getFullStudyProgrammeRights, hasFullAccessToStudentData, mapToProviders } = require('../util/utils')
|
||||
|
||||
const filterPersonalTags = (population, userId) => {
|
||||
return {
|
||||
@@ -27,9 +27,9 @@ const filterPersonalTags = (population, userId) => {
|
||||
router.post('/v2/populationstatistics/courses', async (req, res) => {
|
||||
if (!req.body.year || !req.body.semesters || !req.body.studyRights) {
|
||||
Sentry.captureException(new Error('The body should have a year, semester and study rights defined'))
|
||||
res.status(400).json({ error: 'The body should have a year, semester and study rights defined' })
|
||||
return
|
||||
return res.status(400).json({ error: 'The body should have a year, semester and study rights defined' })
|
||||
}
|
||||
|
||||
if (!Array.isArray(req.body.studyRights)) {
|
||||
// studyRights should always be an array
|
||||
req.body.studyRights = [req.body.studyRights]
|
||||
@@ -41,6 +41,27 @@ router.post('/v2/populationstatistics/courses', async (req, res) => {
|
||||
|
||||
const encrypted = req.body.selectedStudents[0]?.encryptedData
|
||||
|
||||
if (
|
||||
!encrypted &&
|
||||
!hasFullAccessToStudentData(req.user.roles) &&
|
||||
req.body.selectedStudents.some(student => !req.user.studentsUserCanAccess.includes(student))
|
||||
) {
|
||||
return res.status(403).json({ error: 'Trying to request unauthorized students data' })
|
||||
}
|
||||
|
||||
if (!req.body.semesters.every(semester => semester === 'FALL' || semester === 'SPRING')) {
|
||||
return res.status(400).json({ error: 'Semester should be either SPRING OR FALL' })
|
||||
}
|
||||
|
||||
if (
|
||||
req.body.studentStatuses &&
|
||||
!req.body.studentStatuses.every(
|
||||
status => status === 'EXCHANGE' || status === 'NONDEGREE' || status === 'TRANSFERRED'
|
||||
)
|
||||
) {
|
||||
return res.status(400).json({ error: 'Student status should be either EXCHANGE or NONDEGREE or TRANSFERRED' })
|
||||
}
|
||||
|
||||
if (req.body.years) {
|
||||
const upperYearBound = new Date().getFullYear() + 1
|
||||
const multicoursestatPromises = Promise.all(
|
||||
@@ -63,26 +84,23 @@ router.post('/v2/populationstatistics/courses', async (req, res) => {
|
||||
})
|
||||
)
|
||||
const multicoursestats = await multicoursestatPromises
|
||||
const result = StatMergeService.populationCourseStatsMerger(multicoursestats)
|
||||
const result = statMergeService.populationCourseStatsMerger(multicoursestats)
|
||||
if (result.error) {
|
||||
res.status(400).json(result)
|
||||
return
|
||||
return res.status(400).json(result)
|
||||
}
|
||||
|
||||
res.json(result)
|
||||
} else {
|
||||
if (encrypted) req.body.selectedStudents = req.body.selectedStudents.map(decrypt)
|
||||
|
||||
const result = await populationService.bottlenecksOf(req.body, null, encrypted)
|
||||
|
||||
if (result.error) {
|
||||
Sentry.captureException(new Error(result.error))
|
||||
res.status(400).json(result)
|
||||
return
|
||||
}
|
||||
|
||||
res.json(result)
|
||||
return res.json(result)
|
||||
}
|
||||
|
||||
if (encrypted) req.body.selectedStudents = req.body.selectedStudents.map(decrypt)
|
||||
|
||||
const result = await populationService.bottlenecksOf(req.body, null, encrypted)
|
||||
if (result.error) {
|
||||
Sentry.captureException(new Error(result.error))
|
||||
return res.status(400).json(result)
|
||||
}
|
||||
|
||||
return res.json(result)
|
||||
})
|
||||
|
||||
router.post('/v2/populationstatistics/coursesbytag', async (req, res) => {
|
||||
@@ -203,7 +221,7 @@ router.get('/v3/populationstatistics', async (req, res) => {
|
||||
)
|
||||
const multipopulationstudents = await multipopulationstudentPromises
|
||||
|
||||
const result = StatMergeService.populationStudentsMerger(multipopulationstudents)
|
||||
const result = statMergeService.populationStudentsMerger(multipopulationstudents)
|
||||
|
||||
if (result.error) {
|
||||
Sentry.captureException(new Error(result.error))
|
||||
@@ -231,18 +249,20 @@ router.get('/v3/populationstatistics', async (req, res) => {
|
||||
!fullProgrammeRights.includes(studyRights.combinedProgramme)
|
||||
) {
|
||||
result.students = result.students.map(student => {
|
||||
const { iv, encryptedData } = encrypt(student.studentNumber)
|
||||
const obfuscatedBirthDate = new Date(new Date(student.birthdate).setMonth(0, 0)) // only birth year for age distribution
|
||||
const { iv, encryptedData: studentNumber } = encrypt(student.studentNumber)
|
||||
const obfuscatedBirthDate = new Date(Date.UTC(new Date(student.birthdate).getUTCFullYear(), 0, 1)) // correct year for age distribution calculation but the date is always January 1st
|
||||
return {
|
||||
...student,
|
||||
firstnames: '',
|
||||
lastname: '',
|
||||
phone_number: '',
|
||||
started: null,
|
||||
phoneNumber: '',
|
||||
iv,
|
||||
studentNumber: encryptedData,
|
||||
studentNumber,
|
||||
name: '',
|
||||
email: '',
|
||||
secondaryEmail: '',
|
||||
sis_person_id: '',
|
||||
enrollments: student.enrollments?.map(enrollment => ({ ...enrollment, studentnumber: studentNumber })),
|
||||
tags: [],
|
||||
birthdate: obfuscatedBirthDate,
|
||||
obfuscated: true,
|
||||
@@ -265,7 +285,7 @@ router.get('/v3/populationstatisticsbycourse', async (req, res) => {
|
||||
return res.status(400).json({ error: 'The body should have a yearcode and coursecode defined' })
|
||||
}
|
||||
|
||||
const maxYearsToCreatePopulationFrom = await CourseService.maxYearsToCreatePopulationFrom(JSON.parse(coursecodes))
|
||||
const maxYearsToCreatePopulationFrom = await courseService.maxYearsToCreatePopulationFrom(JSON.parse(coursecodes))
|
||||
const toFromDiff = Math.abs(to - from + 1)
|
||||
// 2 semesters = 1 year
|
||||
const requestedYearsToCreatePopulationFrom = Math.ceil(separate ? toFromDiff / 2 : toFromDiff)
|
||||
@@ -294,7 +314,7 @@ router.get('/v3/populationstatisticsbycourse', async (req, res) => {
|
||||
)
|
||||
let courseproviders = []
|
||||
if (!hasFullAccessToStudentData(roles)) {
|
||||
courseproviders = await CourseService.getCourseProvidersForCourses(JSON.parse(coursecodes))
|
||||
courseproviders = await courseService.getCourseProvidersForCourses(JSON.parse(coursecodes))
|
||||
}
|
||||
const fullStudyProgrammeRights = getFullStudyProgrammeRights(programmeRights)
|
||||
const rightsMappedToProviders = mapToProviders(fullStudyProgrammeRights)
|
||||
@@ -372,7 +392,7 @@ router.get('/v3/populationstatistics/studyprogrammes', async (req, res) => {
|
||||
user: { roles, programmeRights },
|
||||
} = req
|
||||
if (hasFullAccessToStudentData(roles)) {
|
||||
const studyrights = await StudyrightService.getAssociations()
|
||||
const studyrights = await studyrightService.getAssociations()
|
||||
mapCodesToIds(studyrights.programmes)
|
||||
res.json(studyrights)
|
||||
} else {
|
||||
@@ -380,28 +400,28 @@ router.get('/v3/populationstatistics/studyprogrammes', async (req, res) => {
|
||||
// For combined programme
|
||||
// If more programmes are combined, then a function might be a better idea to add moar rights
|
||||
if (allRights.includes('KH90_001') || allRights.includes('MH90_001')) allRights.push('KH90_001', 'MH90_001')
|
||||
const studyrights = await StudyrightService.getFilteredAssociations(allRights)
|
||||
const studyrights = await studyrightService.getFilteredAssociations(allRights)
|
||||
mapCodesToIds(studyrights.programmes)
|
||||
res.json(studyrights)
|
||||
}
|
||||
})
|
||||
|
||||
router.get('/v3/populationstatistics/studyprogrammes/unfiltered', async (req, res) => {
|
||||
const studyrights = await StudyrightService.getAssociations()
|
||||
const studyrights = await studyrightService.getAssociations()
|
||||
res.json(studyrights)
|
||||
})
|
||||
|
||||
router.get('/v3/populationstatistics/maxYearsToCreatePopulationFrom', async (req, res) => {
|
||||
const { courseCodes } = req.query
|
||||
const maxYearsToCreatePopulationFromOpen = await CourseService.maxYearsToCreatePopulationFrom(
|
||||
const maxYearsToCreatePopulationFromOpen = await courseService.maxYearsToCreatePopulationFrom(
|
||||
JSON.parse(courseCodes),
|
||||
'openStats'
|
||||
)
|
||||
const maxYearsToCreatePopulationFromUni = await CourseService.maxYearsToCreatePopulationFrom(
|
||||
const maxYearsToCreatePopulationFromUni = await courseService.maxYearsToCreatePopulationFrom(
|
||||
JSON.parse(courseCodes),
|
||||
'regularStats'
|
||||
)
|
||||
const maxYearsToCreatePopulationFromBoth = await CourseService.maxYearsToCreatePopulationFrom(
|
||||
const maxYearsToCreatePopulationFromBoth = await courseService.maxYearsToCreatePopulationFrom(
|
||||
JSON.parse(courseCodes),
|
||||
'unifyStats'
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const router = require('express').Router()
|
||||
|
||||
const { getCoursesAndModules, getCurriculumVersions } = require('../services/programmeModules')
|
||||
|
||||
router.get('/v3/curriculum-options/:code', async (req, res) => {
|
||||
@@ -9,7 +10,7 @@ router.get('/v3/curriculum-options/:code', async (req, res) => {
|
||||
|
||||
router.get('/v3/curriculum/:code/:periodIds', async (req, res) => {
|
||||
const { code, periodIds } = req.params
|
||||
const result = await getCoursesAndModules(code, periodIds.replace(' ', '').split(','))
|
||||
const result = await getCoursesAndModules(code, periodIds)
|
||||
res.json({
|
||||
defaultProgrammeCourses: result.defaultProgrammeCourses.courses,
|
||||
defaultProgrammeModules: result.defaultProgrammeCourses.modules,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const router = require('express').Router()
|
||||
|
||||
const { getAllProviders } = require('../services/providers')
|
||||
|
||||
router.get('/providers', async (_req, res) => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const router = require('express').Router()
|
||||
|
||||
const { getSemestersAndYears } = require('../services/semesters')
|
||||
|
||||
router.get('/semesters/codes', async (req, res) => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const router = require('express').Router()
|
||||
|
||||
const { changeGroupTags, getAllGroupsAndStudents } = require('../services/studyGuidanceGroups')
|
||||
const { logger } = require('../util/logger')
|
||||
const { getAllGroupsAndStudents, changeGroupTags } = require('../services/studyGuidanceGroups')
|
||||
|
||||
router.get('/', async (req, res) => {
|
||||
const {
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
const router = require('express').Router()
|
||||
const { getBasicStatsForStudytrack } = require('../services/studyprogramme/studyprogrammeBasics')
|
||||
const { getCreditsProduced } = require('../services/providerCredits')
|
||||
const { getGraduationStatsForStudytrack } = require('../services/studyprogramme/studyprogrammeGraduations')
|
||||
const {
|
||||
getStudyprogrammeCoursesForStudytrack,
|
||||
getStudyprogrammeStatsForColorizedCoursesTable,
|
||||
} = require('../services/studyprogramme/studyprogrammeCourses')
|
||||
const { getStudytrackStatsForStudyprogramme } = require('../services/studyprogramme/studytrackStats')
|
||||
|
||||
const { ElementDetail } = require('../models')
|
||||
const {
|
||||
getBasicStats,
|
||||
setBasicStats,
|
||||
@@ -15,11 +9,18 @@ const {
|
||||
getStudytrackStats,
|
||||
setStudytrackStats,
|
||||
} = require('../services/analyticsService')
|
||||
const { updateBasicView, updateStudytrackView } = require('../services/studyprogramme/studyprogrammeUpdates')
|
||||
const { getCreditsProduced } = require('../services/providerCredits')
|
||||
const { getProgrammeName } = require('../services/studyprogramme')
|
||||
const logger = require('../util/logger')
|
||||
const { getBasicStatsForStudytrack } = require('../services/studyprogramme/studyprogrammeBasics')
|
||||
const {
|
||||
getStudyprogrammeCoursesForStudytrack,
|
||||
getStudyprogrammeStatsForColorizedCoursesTable,
|
||||
} = require('../services/studyprogramme/studyprogrammeCourses')
|
||||
const { getGraduationStatsForStudytrack } = require('../services/studyprogramme/studyprogrammeGraduations')
|
||||
const { updateBasicView, updateStudytrackView } = require('../services/studyprogramme/studyprogrammeUpdates')
|
||||
const { getStudytrackStatsForStudyprogramme } = require('../services/studyprogramme/studytrackStats')
|
||||
const { getAssociations } = require('../services/studyrights')
|
||||
const { ElementDetail } = require('../models')
|
||||
const logger = require('../util/logger')
|
||||
|
||||
// For grafana statistics (idea stolen from Norppa)
|
||||
const logInfoForGrafana = async (code, combinedProgramme) => {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
const router = require('express').Router()
|
||||
|
||||
const {
|
||||
getCriteria,
|
||||
saveYearlyCourseCriteria,
|
||||
saveYearlyCreditCriteria,
|
||||
} = require('../services/studyprogramme/studyProgrammeCriteria')
|
||||
|
||||
const router = require('express').Router()
|
||||
|
||||
router.get('/', async (req, res) => {
|
||||
const studyProgramme = req.query?.programmecode
|
||||
if (studyProgramme !== '' && !studyProgramme) return res.status(422).end()
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
const router = require('express').Router()
|
||||
|
||||
const {
|
||||
createStudyProgrammePin,
|
||||
getStudyProgrammePins,
|
||||
removeStudyProgrammePin,
|
||||
} = require('../services/studyProgrammePins')
|
||||
|
||||
const router = require('express').Router()
|
||||
|
||||
router.get('/', async (req, res) => {
|
||||
const userId = req.user.id
|
||||
const result = await getStudyProgrammePins(userId)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const router = require('express').Router()
|
||||
const { difference } = require('lodash')
|
||||
|
||||
const Tags = require('../services/tags')
|
||||
const Students = require('../services/students')
|
||||
const Tags = require('../services/tags')
|
||||
const { getFullStudyProgrammeRights } = require('../util/utils')
|
||||
|
||||
const filterRelevantTags = (tags, userId) => {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
const router = require('express').Router()
|
||||
|
||||
const { isFaculty, providersOfFaculty } = require('../services/organisations')
|
||||
const teachers = require('../services/teachers')
|
||||
const topteachers = require('../services/topteachers')
|
||||
const { isFaculty, providersOfFaculty } = require('../services/organisations')
|
||||
const router = require('express').Router()
|
||||
const { mapToProviders, getFullStudyProgrammeRights } = require('../util/utils')
|
||||
const { getFullStudyProgrammeRights, mapToProviders } = require('../util/utils')
|
||||
|
||||
router.get('/', async (req, res) => {
|
||||
const { searchTerm } = req.query
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const router = require('express').Router()
|
||||
const { getFacultyList } = require('../services/faculty/facultyHelpers')
|
||||
const { getGraduationStats, getFacultyProgressStats } = require('../services/faculty/facultyService')
|
||||
|
||||
const { getFacultyList } = require('../services/faculty/facultyHelpers')
|
||||
const { getFacultyProgressStats, getGraduationStats } = require('../services/faculty/facultyService')
|
||||
const { getMedian } = require('../services/studyprogramme/studyprogrammeHelpers')
|
||||
|
||||
const degreeNames = ['bachelor', 'bachelorMaster', 'master', 'licentiate', 'doctor']
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
const router = require('express').Router()
|
||||
|
||||
const { refreshFaculties, refreshProgrammes } = require('../events')
|
||||
const {
|
||||
updateSISMetadata,
|
||||
updateSISStudents,
|
||||
updateSISProgrammes,
|
||||
updateSISRedisCache,
|
||||
updateStudentsByStudentNumber,
|
||||
abort,
|
||||
updateCoursesByCourseCode,
|
||||
updateSISMetadata,
|
||||
updateSISProgrammes,
|
||||
updateSISRedisCache,
|
||||
updateSISStudents,
|
||||
updateStudentsByStudentNumber,
|
||||
updateStudentsIndividually,
|
||||
} = require('../services/sisUpdaterService')
|
||||
|
||||
const logger = require('../util/logger')
|
||||
const { jobMaker, getJobs } = require('../worker/queue')
|
||||
|
||||
@@ -75,7 +75,7 @@ router.get('/update/v2/programmes', async (_req, res) => {
|
||||
})
|
||||
|
||||
router.get('/refresh_redis_cache', async (req, res) => {
|
||||
logger.info(`${req.user.userId} requested refresh of redis cache`)
|
||||
logger.info(`${req.user.username} requested refresh of redis cache`)
|
||||
const response = await updateSISRedisCache()
|
||||
if (response) {
|
||||
res.status(200).json('Refreshing SIS redis cache scheduled')
|
||||
@@ -83,29 +83,35 @@ router.get('/refresh_redis_cache', async (req, res) => {
|
||||
})
|
||||
|
||||
router.post('/refresh_statistic_v2', async (req, res) => {
|
||||
logger.info(`${req.user.userId} requested refresh of statistics`)
|
||||
logger.info(`${req.user.username} requested refresh of statistics`)
|
||||
jobMaker.statistics()
|
||||
res.status(200).json('Teacher and study programme statistics refreshed')
|
||||
})
|
||||
|
||||
router.post('/refresh_study_programmes_v2', async (req, res) => {
|
||||
logger.info(`${req.user.userId} requested refresh of study programmes`)
|
||||
logger.info(`${req.user.username} requested refresh of study programmes`)
|
||||
refreshProgrammes()
|
||||
res.status(200).json('Added job for refreshing study programme overviews')
|
||||
})
|
||||
|
||||
router.post('/refresh_faculties_v2', async (req, res) => {
|
||||
logger.info(`${req.user.userId} requested refresh of faculties`)
|
||||
logger.info(`${req.user.username} requested refresh of faculties`)
|
||||
refreshFaculties()
|
||||
res.status(200).json('Added job for refreshing faculties')
|
||||
})
|
||||
|
||||
router.post('/refresh_language_center_data', async (req, res) => {
|
||||
logger.info(`${req.user.userId} requested refresh of language center data`)
|
||||
logger.info(`${req.user.username} requested refresh of language center data`)
|
||||
jobMaker.languagecenter()
|
||||
res.status(200).json('Added job for refreshing language center data')
|
||||
})
|
||||
|
||||
router.post('/refresh-close-to-graduation', async (req, res) => {
|
||||
logger.info(`${req.user.username} requested refresh of close to graduation data`)
|
||||
jobMaker.closeToGraduation()
|
||||
res.status(200).json('Added job for refreshing close to graduation data')
|
||||
})
|
||||
|
||||
router.get('/abort', async (_req, res) => {
|
||||
await abort()
|
||||
res.status(200).json()
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
const router = require('express').Router()
|
||||
const userService = require('../services/userService')
|
||||
|
||||
const auth = require('../middleware/auth')
|
||||
const { sendNotificationAboutAccessToUser, previewNotificationAboutAccessToUser } = require('../services/mailservice')
|
||||
const userService = require('../services/userService')
|
||||
const logger = require('../util/logger')
|
||||
|
||||
router.get('/', async (_req, res) => {
|
||||
router.get('/', auth.roles(['admin']), async (_req, res) => {
|
||||
const results = await userService.findAll()
|
||||
res.json(results)
|
||||
})
|
||||
|
||||
router.get('/access_groups', async (_req, res) => {
|
||||
const result = await userService.getAccessGroups()
|
||||
res.json(result)
|
||||
router.get('/access_groups', auth.roles(['admin']), async (_req, res) => {
|
||||
res.json(userService.roles)
|
||||
})
|
||||
|
||||
router.get('/:uid', async (req, res) => {
|
||||
router.get('/:uid', auth.roles(['admin']), async (req, res) => {
|
||||
try {
|
||||
const { uid } = req.params
|
||||
const user = await userService.findOne(uid)
|
||||
@@ -23,21 +24,22 @@ router.get('/:uid', async (req, res) => {
|
||||
}
|
||||
})
|
||||
|
||||
router.post('/modifyaccess', async (req, res) => {
|
||||
router.post('/modifyaccess', auth.roles(['admin']), async (req, res) => {
|
||||
const { username, accessgroups } = req.body
|
||||
try {
|
||||
const result = await userService.modifyAccess(req.body)
|
||||
res.status(200).json(result)
|
||||
await userService.modifyAccess(username, accessgroups)
|
||||
res.status(204).end()
|
||||
} catch (e) {
|
||||
res.status(400).json(e)
|
||||
}
|
||||
})
|
||||
|
||||
router.get('/email/preview', (_req, res) => {
|
||||
router.get('/email/preview', auth.roles(['admin']), (_req, res) => {
|
||||
const { accessMessageSubject, accessMessageText } = previewNotificationAboutAccessToUser()
|
||||
res.json({ subject: accessMessageSubject, html: accessMessageText })
|
||||
})
|
||||
|
||||
router.post('/email', async (req, res) => {
|
||||
router.post('/email', auth.roles(['admin']), async (req, res) => {
|
||||
const userEmail = req.body.email
|
||||
if (!userEmail) {
|
||||
return res.status(400).json({ error: 'email is missing' })
|
||||
@@ -51,18 +53,34 @@ router.post('/email', async (req, res) => {
|
||||
res.status(200).end()
|
||||
})
|
||||
|
||||
router.post('/:uid/elements', async (req, res) => {
|
||||
router.post('/:uid/elements', auth.roles(['admin']), async (req, res) => {
|
||||
const { uid } = req.params
|
||||
const { codes } = req.body
|
||||
const user = await userService.enableElementDetails(uid, codes)
|
||||
res.json(user)
|
||||
await userService.modifyElementDetails(uid, codes, true)
|
||||
res.status(204).end()
|
||||
})
|
||||
|
||||
router.delete('/:uid/elements', async (req, res) => {
|
||||
router.delete('/:uid/elements', auth.roles(['admin']), async (req, res) => {
|
||||
const { uid } = req.params
|
||||
const { codes } = req.body
|
||||
const user = await userService.removeElementDetails(uid, codes)
|
||||
res.json(user)
|
||||
await userService.modifyElementDetails(uid, codes, false)
|
||||
res.status(204).end()
|
||||
})
|
||||
|
||||
router.post('/language', async (req, res) => {
|
||||
const {
|
||||
body: { language },
|
||||
user: { username },
|
||||
} = req
|
||||
if (!['fi', 'sv', 'en'].includes(language)) {
|
||||
return res.status(400).json('invalid language')
|
||||
}
|
||||
try {
|
||||
await userService.updateUser(username, { language })
|
||||
return res.status(204).end()
|
||||
} catch (e) {
|
||||
return res.status(500).json({ error: e.message })
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = router
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const { redisClient } = require('./redis')
|
||||
const moment = require('moment')
|
||||
|
||||
const { redisClient } = require('./redis')
|
||||
|
||||
// Only new bachelor, masters and doctoral programmes get their data updated in redis every night, use redis for them
|
||||
const isUpdatedNewProgramme = code => code.includes('KH') || code.includes('MH') || /^(T)[0-9]{6}$/.test(code)
|
||||
const isFaculty = code =>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const { Credit, Enrollment, Student, Course } = require('../models')
|
||||
const { Op, where, fn, col } = require('sequelize')
|
||||
|
||||
const { Credit, Enrollment, Student, Course } = require('../models')
|
||||
|
||||
const getCompletedCourses = async (studentNumbers, courseCodes) => {
|
||||
let courses = await Course.findAll({
|
||||
attributes: ['code', 'name', 'substitutions'],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Op } = require('sequelize')
|
||||
|
||||
const { Course } = require('../../models')
|
||||
const { getSortRank } = require('../../util/utils')
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Op } = require('sequelize')
|
||||
|
||||
const {
|
||||
Credit,
|
||||
Student,
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
const { Op } = require('sequelize')
|
||||
const { Credit, Course, Organization, Enrollment } = require('../../models')
|
||||
|
||||
const { parseCredit } = require('./parseCredits')
|
||||
const { parseEnrollment } = require('./parseEnrollments')
|
||||
const { CourseYearlyStatsCounter } = require('./course_yearly_stats_counter')
|
||||
const { sortMainCode } = require('../../util/utils')
|
||||
const { byNameAndOrCodeLike, byCodes } = require('./courseFinders')
|
||||
const {
|
||||
enrollmentsForCourses,
|
||||
creditsForCourses,
|
||||
getStudentNumberToSrElementsMap,
|
||||
} = require('./creditsAndEnrollmentsOfCourse')
|
||||
const { byNameAndOrCodeLike, byCodes } = require('./courseFinders')
|
||||
const { parseCredit } = require('./parseCredits')
|
||||
const { parseEnrollment } = require('./parseEnrollments')
|
||||
const { Credit, Course, Organization, Enrollment } = require('../../models')
|
||||
const { sortMainCode } = require('../../util/utils')
|
||||
|
||||
const isOpenUniCourseCode = code => code.match(/^AY?(.+?)(?:en|fi|sv)?$/)
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const crypto = require('crypto')
|
||||
|
||||
const { Credit } = require('../../models')
|
||||
|
||||
const formatStudyrightElement = ({ code, element_detail, startdate, studyright: sr }) => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const crypto = require('crypto')
|
||||
|
||||
const { formatStudyrightElement } = require('./parseCredits')
|
||||
|
||||
const parseEnrollment = (enrollment, anonymizationSalt, studentNumberToSrElementsMap) => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { createCipheriv, createDecipheriv, randomBytes } = require('crypto')
|
||||
|
||||
const { CRYPT_KEY } = require('../conf-backend')
|
||||
|
||||
const algorithm = 'aes-256-cbc'
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Op } = require('sequelize')
|
||||
|
||||
const { ExcludedCourse } = require('../models/models_kone')
|
||||
|
||||
const addExcludedCourses = async (programmecode, coursecodes, curriculum) => {
|
||||
|
||||
@@ -1,4 +1,19 @@
|
||||
const { uniqBy } = require('lodash')
|
||||
const { Op } = require('sequelize')
|
||||
|
||||
const {
|
||||
facultyFormatStudyright,
|
||||
facultyFormatProgramme,
|
||||
formatFacultyTransfer,
|
||||
formatFacultyThesisWriter,
|
||||
formatOrganization,
|
||||
isNewProgramme,
|
||||
mapCodesToIds,
|
||||
facultyProgrammeStudents,
|
||||
} = require('./facultyHelpers')
|
||||
const {
|
||||
dbConnections: { sequelize },
|
||||
} = require('../../database/connection')
|
||||
const {
|
||||
ElementDetail,
|
||||
Organization,
|
||||
@@ -11,20 +26,6 @@ const {
|
||||
Credit,
|
||||
Course,
|
||||
} = require('../../models')
|
||||
const {
|
||||
facultyFormatStudyright,
|
||||
facultyFormatProgramme,
|
||||
formatFacultyTransfer,
|
||||
formatFacultyThesisWriter,
|
||||
formatOrganization,
|
||||
isNewProgramme,
|
||||
mapCodesToIds,
|
||||
facultyProgrammeStudents,
|
||||
} = require('./facultyHelpers')
|
||||
const { uniqBy } = require('lodash')
|
||||
const {
|
||||
dbConnections: { sequelize },
|
||||
} = require('../../database/connection')
|
||||
|
||||
const transferredFaculty = async (programmeCodeIn, programmeCodeOut, start, end) =>
|
||||
(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const { indexOf, isArray } = require('lodash')
|
||||
const moment = require('moment')
|
||||
|
||||
const {
|
||||
startedStudyrights,
|
||||
graduatedStudyrights,
|
||||
@@ -11,9 +12,9 @@ const {
|
||||
studyrightsByRightStartYear,
|
||||
getTransfersIn,
|
||||
} = require('./faculty')
|
||||
const { getStatsBasis, getYearsArray, defineYear } = require('../studyprogramme/studyprogrammeHelpers')
|
||||
const { findRightProgramme, isNewProgramme, checkTransfers, getExtentFilter } = require('./facultyHelpers')
|
||||
const { codes } = require('../../../config/programmeCodes')
|
||||
const { getStatsBasis, getYearsArray, defineYear } = require('../studyprogramme/studyprogrammeHelpers')
|
||||
|
||||
const filterDuplicateStudyrights = studyrights => {
|
||||
// bachelor+master students have two studyrights (separated by two last digits in studyrightid)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const { getCreditsProduced } = require('../providerCredits')
|
||||
const { getProgrammes } = require('./facultyService')
|
||||
const { getCreditsProduced } = require('../providerCredits')
|
||||
|
||||
/*
|
||||
Returns credits produced by the programmes of the faculty but also the credits where the provider is the faculty itself.
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
const moment = require('moment')
|
||||
|
||||
const { graduatedStudyrights, studyrightsByRightStartYear, hasMasterRight } = require('./faculty')
|
||||
const { findRightProgramme, isNewProgramme } = require('./facultyHelpers')
|
||||
const { getYearsArray, getYearsObject, getMedian, defineYear } = require('../studyprogramme/studyprogrammeHelpers')
|
||||
const { getProgrammes } = require('./facultyService')
|
||||
const { codes } = require('../../../config/programmeCodes')
|
||||
const { bachelorStudyright, countTimeCategories, getStatutoryAbsences } = require('../graduationHelpers')
|
||||
const { getProgrammes } = require('./facultyService')
|
||||
const { getYearsArray, getYearsObject, getMedian, defineYear } = require('../studyprogramme/studyprogrammeHelpers')
|
||||
|
||||
const sortProgrammes = data => {
|
||||
const check = name => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { Op } = require('sequelize')
|
||||
|
||||
const { codes } = require('../../../config/programmeCodes')
|
||||
const { faculties } = require('../organisations')
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const { redisClient } = require('../redis')
|
||||
const moment = require('moment')
|
||||
|
||||
const { findFacultyProgrammeCodes } = require('./faculty')
|
||||
const { redisClient } = require('../redis')
|
||||
|
||||
const createRedisKeyForFacultyProgrammes = (id, programmeFilter) => `FACULTY_PROGRAMMES_${id}_${programmeFilter}`
|
||||
const createRedisKeyForBasicStats = (id, yearType, programmeFilter, specialGroups) =>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
const { indexOf, inRange } = require('lodash')
|
||||
const moment = require('moment')
|
||||
const { getAcademicYearDates } = require('../../util/semester')
|
||||
const { getCreditThresholds, getYearsArray } = require('../studyprogramme/studyprogrammeHelpers')
|
||||
const { studytrackStudents } = require('../studyprogramme/studentGetters')
|
||||
|
||||
const { getStudyRightsByExtent, getStudyRightsByBachelorStart, getTransfersIn, getTransfersOut } = require('./faculty')
|
||||
const { checkTransfers } = require('./facultyHelpers')
|
||||
const { getAcademicYearDates } = require('../../util/semester')
|
||||
const { studytrackStudents } = require('../studyprogramme/studentGetters')
|
||||
const { getCreditThresholds, getYearsArray } = require('../studyprogramme/studyprogrammeHelpers')
|
||||
|
||||
const getStudentData = (
|
||||
startDate,
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
const { getStudyRightsByExtent, getStudentsByStudentnumbers, getTransfersIn } = require('./faculty')
|
||||
const { checkTransfers } = require('./facultyHelpers')
|
||||
const { getAcademicYearDates } = require('../../util/semester')
|
||||
const { enrolledStudents, absentStudents } = require('../studyprogramme/studentGetters')
|
||||
const {
|
||||
getStartDate,
|
||||
getYearsArray,
|
||||
@@ -5,11 +9,7 @@ const {
|
||||
getYearsObject,
|
||||
tableTitles,
|
||||
} = require('../studyprogramme/studyprogrammeHelpers')
|
||||
const { getAcademicYearDates } = require('../../util/semester')
|
||||
const { getStudyRightsByExtent, getStudentsByStudentnumbers, getTransfersIn } = require('./faculty')
|
||||
const { checkTransfers } = require('./facultyHelpers')
|
||||
const { inactiveStudyrights, graduatedStudyRights } = require('../studyprogramme/studyrightFinders')
|
||||
const { enrolledStudents, absentStudents } = require('../studyprogramme/studentGetters')
|
||||
|
||||
const emptyTotals = () => {
|
||||
return {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const { indexOf } = require('lodash')
|
||||
const { mapToProviders } = require('../../util/utils')
|
||||
|
||||
const { thesisWriters } = require('./faculty')
|
||||
const { mapToProviders } = require('../../util/utils')
|
||||
const {
|
||||
getStatsBasis,
|
||||
getYearsArray,
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
const logger = require('../../util/logger')
|
||||
const { findFacultyProgrammeCodes } = require('./faculty')
|
||||
const { combineFacultyBasics } = require('./facultyBasics')
|
||||
const { combineFacultyThesisWriters } = require('./facultyThesisWriters')
|
||||
const { countGraduationTimes } = require('./facultyGraduationTimes')
|
||||
const {
|
||||
setFacultyProgrammes,
|
||||
@@ -13,8 +11,10 @@ const {
|
||||
} = require('./facultyService')
|
||||
const { combineFacultyStudentProgress } = require('./facultyStudentProgress')
|
||||
const { combineFacultyStudents } = require('./facultyStudents')
|
||||
const { computeCreditsProduced } = require('../providerCredits')
|
||||
const { combineFacultyThesisWriters } = require('./facultyThesisWriters')
|
||||
const logger = require('../../util/logger')
|
||||
const { setCreditStats } = require('../analyticsService')
|
||||
const { computeCreditsProduced } = require('../providerCredits')
|
||||
|
||||
const updateFacultyOverview = async (faculty, statsType) => {
|
||||
const calendarNewSpecial = {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const { Op } = require('sequelize')
|
||||
const moment = require('moment')
|
||||
const { Op } = require('sequelize')
|
||||
|
||||
const { Semester, SemesterEnrollment, Studyright } = require('../models')
|
||||
|
||||
// categorize graduation times
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
const { Course, Credit, Enrollment, StudyrightElement, Studyright } = require('../models')
|
||||
const { Op } = require('sequelize')
|
||||
const { redisClient } = require('./redis')
|
||||
const { orderBy } = require('lodash')
|
||||
const { Op } = require('sequelize')
|
||||
|
||||
const { redisClient } = require('./redis')
|
||||
const { Course, Credit, Enrollment, StudyrightElement, Studyright } = require('../models')
|
||||
|
||||
const LANGUAGE_CENTER_REDIS_KEY = 'LANGUAGE_CENTER_DATA'
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const axios = require('axios')
|
||||
|
||||
const { isProduction, pateToken } = require('../conf-backend')
|
||||
const { ApplicationError } = require('../util/customErrors')
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
const logger = require('../../util/logger')
|
||||
const {
|
||||
getOpenUniSearchesByUser,
|
||||
createOpenUniPopulationSearch,
|
||||
updateOpenUniPopulationSearch,
|
||||
deleteOpenUniSearch,
|
||||
} = require('./openUniSearches')
|
||||
const logger = require('../../util/logger')
|
||||
|
||||
const getOpenUniSearches = async userId => {
|
||||
const savedSearches = await getOpenUniSearchesByUser(userId)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const { Credit, Enrollment, Studyright, Student, Course } = require('../../models')
|
||||
const { OpenUniPopulationSearch } = require('../../models/models_kone')
|
||||
const { Op } = require('sequelize')
|
||||
|
||||
const {
|
||||
mapOpenCredits,
|
||||
mapOpenEnrollments,
|
||||
@@ -7,7 +7,8 @@ const {
|
||||
mapStudyRights,
|
||||
mapCourseInfo,
|
||||
} = require('./openUniHelpers')
|
||||
const { Op } = require('sequelize')
|
||||
const { Credit, Enrollment, Studyright, Student, Course } = require('../../models')
|
||||
const { OpenUniPopulationSearch } = require('../../models/models_kone')
|
||||
|
||||
const getCredits = async (courseCodes, startdate) =>
|
||||
(
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user