mirror of
https://github.com/UniversityOfHelsinkiCS/oodikone.git
synced 2026-10-12 19:03:39 +03:00
[META] Drop version numbers from api routes
This commit is contained in:
@@ -92,17 +92,17 @@ const clickAway = () => {
|
|||||||
|
|
||||||
const getCourseSearchHooksForSingleYear = code => {
|
const getCourseSearchHooksForSingleYear = code => {
|
||||||
cy.intercept({
|
cy.intercept({
|
||||||
pathname: '/api/v2/coursesmulti',
|
pathname: '/api/coursesmulti',
|
||||||
query: { code },
|
query: { code },
|
||||||
}).as('courses')
|
}).as('courses')
|
||||||
|
|
||||||
cy.intercept({
|
cy.intercept({
|
||||||
pathname: '/api/v3/courseyearlystats',
|
pathname: '/api/courseyearlystats',
|
||||||
query: { 'codes[]': code },
|
query: { 'codes[]': code },
|
||||||
}).as('yearlystats')
|
}).as('yearlystats')
|
||||||
|
|
||||||
cy.intercept({
|
cy.intercept({
|
||||||
pathname: '/api/v3/populationstatisticsbycourse',
|
pathname: '/api/populationstatisticsbycourse',
|
||||||
}).as('coursestats')
|
}).as('coursestats')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,17 +263,17 @@ describe('Basic user', () => {
|
|||||||
|
|
||||||
it('Searching multiple courses having substitution mappings shows course statistics', () => {
|
it('Searching multiple courses having substitution mappings shows course statistics', () => {
|
||||||
cy.intercept({
|
cy.intercept({
|
||||||
pathname: '/api/v2/coursesmulti',
|
pathname: '/api/coursesmulti',
|
||||||
query: { code: 'TKT' },
|
query: { code: 'TKT' },
|
||||||
}).as('courses')
|
}).as('courses')
|
||||||
|
|
||||||
cy.intercept({
|
cy.intercept({
|
||||||
pathname: '/api/v3/courseyearlystats',
|
pathname: '/api/courseyearlystats',
|
||||||
query: { 'codes[]': 'TKT20001', 'codes[]': 'TKT10002' },
|
query: { 'codes[]': 'TKT20001', 'codes[]': 'TKT10002' },
|
||||||
}).as('yearlystats')
|
}).as('yearlystats')
|
||||||
|
|
||||||
cy.intercept({
|
cy.intercept({
|
||||||
pathname: '/api/v3/populationstatisticsbycourse',
|
pathname: '/api/populationstatisticsbycourse',
|
||||||
}).as('coursestats')
|
}).as('coursestats')
|
||||||
|
|
||||||
cy.cs('select-multiple-courses-toggle').should('not.have.class', 'Mui-checked')
|
cy.cs('select-multiple-courses-toggle').should('not.have.class', 'Mui-checked')
|
||||||
@@ -309,17 +309,17 @@ describe('Basic user', () => {
|
|||||||
|
|
||||||
it('On searches with multiple courses, has correct links on the Course tab', () => {
|
it('On searches with multiple courses, has correct links on the Course tab', () => {
|
||||||
cy.intercept({
|
cy.intercept({
|
||||||
pathname: '/api/v2/coursesmulti',
|
pathname: '/api/coursesmulti',
|
||||||
query: { code: 'BSCS' },
|
query: { code: 'BSCS' },
|
||||||
}).as('courses')
|
}).as('courses')
|
||||||
|
|
||||||
cy.intercept({
|
cy.intercept({
|
||||||
pathname: '/api/v3/courseyearlystats',
|
pathname: '/api/courseyearlystats',
|
||||||
query: { 'codes[]': 'BSCS1003', 'codes[]': 'BSCS1001' },
|
query: { 'codes[]': 'BSCS1003', 'codes[]': 'BSCS1001' },
|
||||||
}).as('yearlystats')
|
}).as('yearlystats')
|
||||||
|
|
||||||
cy.intercept({
|
cy.intercept({
|
||||||
pathname: '/api/v3/populationstatisticsbycourse',
|
pathname: '/api/populationstatisticsbycourse',
|
||||||
}).as('coursestats')
|
}).as('coursestats')
|
||||||
|
|
||||||
cy.cs('select-multiple-courses-toggle').should('not.have.class', 'Mui-checked')
|
cy.cs('select-multiple-courses-toggle').should('not.have.class', 'Mui-checked')
|
||||||
|
|||||||
@@ -269,7 +269,7 @@ describe('Degree programme overview', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.intercept(
|
cy.intercept(
|
||||||
'GET',
|
'GET',
|
||||||
'api/v2/studyprogrammes/KH50_001/studytrackstats?special_groups=SPECIAL_INCLUDED&combined_programme='
|
'api/studyprogrammes/KH50_001/studytrackstats?special_groups=SPECIAL_INCLUDED&combined_programme='
|
||||||
).as('stQuery')
|
).as('stQuery')
|
||||||
cy.init('/study-programme')
|
cy.init('/study-programme')
|
||||||
cy.contains('a', 'Matemaattisten tieteiden kandiohjelma').click()
|
cy.contains('a', 'Matemaattisten tieteiden kandiohjelma').click()
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ describe('Population statistics tests', () => {
|
|||||||
describe('When using basic user', () => {
|
describe('When using basic user', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.init('/populations')
|
cy.init('/populations')
|
||||||
cy.intercept('/api/v3/populationstatistics/studyprogrammes').as('studyprogrammes')
|
cy.intercept('/api/populationstatistics/studyprogrammes').as('studyprogrammes')
|
||||||
cy.intercept('/api/v2/studyprogrammes/**/studytracks').as('studytracks')
|
cy.intercept('/api/studyprogrammes/**/studytracks').as('studytracks')
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('Population search', () => {
|
describe('Population search', () => {
|
||||||
@@ -251,7 +251,7 @@ describe('Population statistics tests', () => {
|
|||||||
it('Is displayed and link to individual course stats page works', () => {
|
it('Is displayed and link to individual course stats page works', () => {
|
||||||
cy.visit(pathToMathBSc2020)
|
cy.visit(pathToMathBSc2020)
|
||||||
cy.contains('Courses of class').click()
|
cy.contains('Courses of class').click()
|
||||||
cy.intercept('/api/v3/courseyearlystats**').as('coursePage')
|
cy.intercept('/api/courseyearlystats**').as('coursePage')
|
||||||
cy.cs('toggle-group-module-MAT110').click()
|
cy.cs('toggle-group-module-MAT110').click()
|
||||||
cy.contains('td', 'MAT11001').siblings().find('[data-testid="NorthEastIcon"]').click()
|
cy.contains('td', 'MAT11001').siblings().find('[data-testid="NorthEastIcon"]').click()
|
||||||
cy.wait('@coursePage')
|
cy.wait('@coursePage')
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ describe('Users tests', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("only the mocked user's programmes are visible", () => {
|
it("only the mocked user's programmes are visible", () => {
|
||||||
cy.intercept('/api/v3/populationstatistics/studyprogrammes').as('studyprogrammes')
|
cy.intercept('/api/populationstatistics/studyprogrammes').as('studyprogrammes')
|
||||||
cy.visit('/populations')
|
cy.visit('/populations')
|
||||||
cy.wait('@studyprogrammes').its('response.statusCode').should('be.oneOf', [200, 304])
|
cy.wait('@studyprogrammes').its('response.statusCode').should('be.oneOf', [200, 304])
|
||||||
|
|
||||||
|
|||||||
@@ -91,6 +91,6 @@ All things listed below should work automatically, if new combinations are done.
|
|||||||
|
|
||||||
## Study guidance groups
|
## Study guidance groups
|
||||||
|
|
||||||
- Backend: student data is fetched by bachelor degree programme code in `/v3/populationstatisticsbystudentnumbers`. Separation from code 'KHxx_xxx+MHxx_xxx' is done in backend.
|
- Backend: student data is fetched by bachelor degree programme code in `/populationstatisticsbystudentnumbers`. Separation from code 'KHxx_xxx+MHxx_xxx' is done in backend.
|
||||||
- Frontend: things are done in the same way as with class stats.
|
- Frontend: things are done in the same way as with class stats.
|
||||||
- **Need manual work**: `./oodikone/services/frontend/src/redux/elementdetails.js` add combined programme codes (both bachelor and master) to `combinedProgrammeCodes` and modify `combinedOptions` list accordingly in `useFilterAndFormattedElementDetails()` function.
|
- **Need manual work**: `./oodikone/services/frontend/src/redux/elementdetails.js` add combined programme codes (both bachelor and master) to `combinedProgrammeCodes` and modify `combinedOptions` list accordingly in `useFilterAndFormattedElementDetails()` function.
|
||||||
|
|||||||
@@ -52,8 +52,8 @@ const routes = (app: Express, url: string) => {
|
|||||||
app.use(`${url}/semesters/codes`, semesters)
|
app.use(`${url}/semesters/codes`, semesters)
|
||||||
app.use(url, tags)
|
app.use(url, tags)
|
||||||
app.use(url, programmeModules)
|
app.use(url, programmeModules)
|
||||||
app.use(`${url}/v3/course-exclusions`, courseExclusions)
|
app.use(`${url}/course-exclusions`, courseExclusions)
|
||||||
app.use(`${url}/v2/studyprogrammes`, studyProgramme)
|
app.use(`${url}/studyprogrammes`, studyProgramme)
|
||||||
app.use(`${url}/programme-criteria`, studyProgrammeCriteria)
|
app.use(`${url}/programme-criteria`, studyProgrammeCriteria)
|
||||||
app.use(`${url}/openunisearch`, auth.roles(['openUniSearch']), customOpenUniSearch)
|
app.use(`${url}/openunisearch`, auth.roles(['openUniSearch']), customOpenUniSearch)
|
||||||
app.use(`${url}/changelog`, changelog)
|
app.use(`${url}/changelog`, changelog)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import {
|
|||||||
const router = Router()
|
const router = Router()
|
||||||
|
|
||||||
router.get<never, CanError<CoursesMultiResBody>, CoursesMultiReqBody, CoursesMultiQuery>(
|
router.get<never, CanError<CoursesMultiResBody>, CoursesMultiReqBody, CoursesMultiQuery>(
|
||||||
'/v2/coursesmulti',
|
'/coursesmulti',
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
const { name, code, includeSpecial } = req.query
|
const { name, code, includeSpecial } = req.query
|
||||||
if (!(validateParamLength(name, 5) || validateParamLength(code, 2))) {
|
if (!(validateParamLength(name, 5) || validateParamLength(code, 2))) {
|
||||||
@@ -54,7 +54,7 @@ router.get<never, CanError<CoursesMultiResBody>, CoursesMultiReqBody, CoursesMul
|
|||||||
type CourseYearlyStatsResBody = Awaited<ReturnType<typeof getCourseYearlyStats>>
|
type CourseYearlyStatsResBody = Awaited<ReturnType<typeof getCourseYearlyStats>>
|
||||||
|
|
||||||
router.get<never, CanError<CourseYearlyStatsResBody>, CourseYearlyStatsReqBody, CourseYearlyStatsQuery>(
|
router.get<never, CanError<CourseYearlyStatsResBody>, CourseYearlyStatsReqBody, CourseYearlyStatsQuery>(
|
||||||
'/v3/courseyearlystats',
|
'/courseyearlystats',
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
const { codes, combineSubstitutions, separate } = req.query
|
const { codes, combineSubstitutions, separate } = req.query
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ const obfuscateStuff = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
router.get<never, CanError<PopulationstatisticsResBody>, PopulationstatisticsReqBody, PopulationstatisticsQuery>(
|
router.get<never, CanError<PopulationstatisticsResBody>, PopulationstatisticsReqBody, PopulationstatisticsQuery>(
|
||||||
'/v3/populationstatistics',
|
'/populationstatistics',
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
const { id: userId, roles: userRoles, programmeRights: userProgrammeRights, studentsUserCanAccess } = req.user
|
const { id: userId, roles: userRoles, programmeRights: userProgrammeRights, studentsUserCanAccess } = req.user
|
||||||
const { programme, combinedProgramme } = req.query
|
const { programme, combinedProgramme } = req.query
|
||||||
@@ -168,7 +168,7 @@ router.get<
|
|||||||
CanError<PopulationstatisticsbycourseResBody>,
|
CanError<PopulationstatisticsbycourseResBody>,
|
||||||
PopulationstatisticsbycourseReqBody,
|
PopulationstatisticsbycourseReqBody,
|
||||||
PopulationstatisticsbycourseParams
|
PopulationstatisticsbycourseParams
|
||||||
>('/v3/populationstatisticsbycourse', async (req, res) => {
|
>('/populationstatisticsbycourse', async (req, res) => {
|
||||||
const {
|
const {
|
||||||
id: userId,
|
id: userId,
|
||||||
roles: userRoles,
|
roles: userRoles,
|
||||||
@@ -218,7 +218,7 @@ router.get<
|
|||||||
|
|
||||||
// Used in custom population and single study guidance groups
|
// Used in custom population and single study guidance groups
|
||||||
router.post<never, GetCustomPopulationResBody, CustomPopulationQuery>(
|
router.post<never, GetCustomPopulationResBody, CustomPopulationQuery>(
|
||||||
'/v3/populationstatisticsbystudentnumbers',
|
'/populationstatisticsbystudentnumbers',
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
const { studentNumbers, tags } = req.body
|
const { studentNumbers, tags } = req.body
|
||||||
const { id: userId, roles, studentsUserCanAccess } = req.user
|
const { id: userId, roles, studentsUserCanAccess } = req.user
|
||||||
@@ -248,7 +248,7 @@ router.post<never, GetCustomPopulationResBody, CustomPopulationQuery>(
|
|||||||
)
|
)
|
||||||
|
|
||||||
router.get<never, PopulationstatisticsStudyprogrammesResBody>(
|
router.get<never, PopulationstatisticsStudyprogrammesResBody>(
|
||||||
'/v3/populationstatistics/studyprogrammes',
|
'/populationstatistics/studyprogrammes',
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
const { roles, programmeRights } = req.user
|
const { roles, programmeRights } = req.user
|
||||||
const programmes = await getDegreeProgrammesOfOrganization(rootOrgId, false)
|
const programmes = await getDegreeProgrammesOfOrganization(rootOrgId, false)
|
||||||
@@ -274,7 +274,7 @@ router.get<
|
|||||||
PopulationstatisticsMaxYearsToCreatePopulationFormResBody,
|
PopulationstatisticsMaxYearsToCreatePopulationFormResBody,
|
||||||
never,
|
never,
|
||||||
PopulationstatisticsMaxYearsToCreatePopulationFormQuery
|
PopulationstatisticsMaxYearsToCreatePopulationFormQuery
|
||||||
>('/v3/populationstatistics/maxYearsToCreatePopulationFrom', async (req, res) => {
|
>('/populationstatistics/maxYearsToCreatePopulationFrom', async (req, res) => {
|
||||||
const courseCodes = JSON.parse(req.query.courseCodes) as string[]
|
const courseCodes = JSON.parse(req.query.courseCodes) as string[]
|
||||||
const maxYearsToCreatePopulationFromOpen = await maxYearsToCreatePopulationFrom(courseCodes, Unification.OPEN)
|
const maxYearsToCreatePopulationFromOpen = await maxYearsToCreatePopulationFrom(courseCodes, Unification.OPEN)
|
||||||
const maxYearsToCreatePopulationFromUni = await maxYearsToCreatePopulationFrom(courseCodes, Unification.REGULAR)
|
const maxYearsToCreatePopulationFromUni = await maxYearsToCreatePopulationFrom(courseCodes, Unification.REGULAR)
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ import { getCoursesAndModules, getCurriculumOptions } from '../services/programm
|
|||||||
|
|
||||||
const router = Router()
|
const router = Router()
|
||||||
|
|
||||||
router.get('/v3/curriculum-options/:code', async (req: Request, res: Response) => {
|
router.get('/curriculum-options/:code', async (req: Request, res: Response) => {
|
||||||
const { code } = req.params
|
const { code } = req.params
|
||||||
const result = await getCurriculumOptions(code)
|
const result = await getCurriculumOptions(code)
|
||||||
res.json(result)
|
res.json(result)
|
||||||
})
|
})
|
||||||
|
|
||||||
router.get('/v3/curriculum/:code/:periodIds', async (req: Request, res: Response) => {
|
router.get('/curriculum/:code/:periodIds', async (req: Request, res: Response) => {
|
||||||
const { code, periodIds } = req.params
|
const { code, periodIds } = req.params
|
||||||
const { defaultProgrammeCourses, secondProgrammeCourses } = await getCoursesAndModules(code, periodIds)
|
const { defaultProgrammeCourses, secondProgrammeCourses } = await getCoursesAndModules(code, periodIds)
|
||||||
|
|
||||||
|
|||||||
@@ -26,14 +26,14 @@ const refreshProgrammesByList = (programmeCodes: string[]) => {
|
|||||||
return 'Added jobs for refreshing programme'
|
return 'Added jobs for refreshing programme'
|
||||||
}
|
}
|
||||||
|
|
||||||
router.get('/update/v2/meta', async (_req: Request, res: Response) => {
|
router.get('/update/meta', async (_req: Request, res: Response) => {
|
||||||
const response = await updateSISMetadata()
|
const response = await updateSISMetadata()
|
||||||
if (response) {
|
if (response) {
|
||||||
res.status(200).json('Update SIS meta scheduled')
|
res.status(200).json('Update SIS meta scheduled')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
router.get('/update/v2/students', async (_req: Request, res: Response) => {
|
router.get('/update/students', async (_req: Request, res: Response) => {
|
||||||
const response = await updateSISStudents()
|
const response = await updateSISStudents()
|
||||||
if (response) {
|
if (response) {
|
||||||
res.status(200).json('Update SIS students scheduled')
|
res.status(200).json('Update SIS students scheduled')
|
||||||
@@ -47,7 +47,7 @@ interface PostCustomListRequest extends Request {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
router.post('/update/v2/customlist/:type', async (req: PostCustomListRequest, res: Response) => {
|
router.post('/update/customlist/:type', async (req: PostCustomListRequest, res: Response) => {
|
||||||
const { type } = req.params
|
const { type } = req.params
|
||||||
const list = req.body
|
const list = req.body
|
||||||
const typeToJob = {
|
const typeToJob = {
|
||||||
@@ -65,7 +65,7 @@ router.post('/update/v2/customlist/:type', async (req: PostCustomListRequest, re
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
router.get('/update/v2/programmes', async (_req: Request, res: Response) => {
|
router.get('/update/programmes', async (_req: Request, res: Response) => {
|
||||||
const response = await updateSISProgrammes()
|
const response = await updateSISProgrammes()
|
||||||
if (response) {
|
if (response) {
|
||||||
res.status(200).json('Update SIS programmes scheduled')
|
res.status(200).json('Update SIS programmes scheduled')
|
||||||
|
|||||||
@@ -8,39 +8,39 @@ const client = axios.create({ baseURL: SIS_UPDATER_URL })
|
|||||||
const params = { params: { token: SECRET_TOKEN } }
|
const params = { params: { token: SECRET_TOKEN } }
|
||||||
|
|
||||||
export const abortUpdate = async () => {
|
export const abortUpdate = async () => {
|
||||||
const response = await client.get('/v1/abort', params)
|
const response = await client.get('/abort', params)
|
||||||
return response.data?.message
|
return response.data?.message
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateSISCoursesByCourseCode = async (coursecodes: string[]) => {
|
export const updateSISCoursesByCourseCode = async (coursecodes: string[]) => {
|
||||||
const data = { coursecodes }
|
const data = { coursecodes }
|
||||||
const response = await client.post('/v1/courses', data, params)
|
const response = await client.post('/courses', data, params)
|
||||||
return response.data
|
return response.data
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateSISMetadata = async () => {
|
export const updateSISMetadata = async () => {
|
||||||
const response = await client.get('/v1/meta', params)
|
const response = await client.get('/meta', params)
|
||||||
return response.data
|
return response.data
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateSISProgrammes = async () => {
|
export const updateSISProgrammes = async () => {
|
||||||
const response = await client.get('/v1/programmes', params)
|
const response = await client.get('/programmes', params)
|
||||||
return response.data
|
return response.data
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateSISRedisCache = async () => {
|
export const updateSISRedisCache = async () => {
|
||||||
const response = await client.get('/v1/rediscache', params)
|
const response = await client.get('/rediscache', params)
|
||||||
return response.data
|
return response.data
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateSISStudents = async () => {
|
export const updateSISStudents = async () => {
|
||||||
const response = await client.get('/v1/students', params)
|
const response = await client.get('/students', params)
|
||||||
return response.data
|
return response.data
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateSISStudentsByStudentNumber = async (studentnumbers: string[]) => {
|
export const updateSISStudentsByStudentNumber = async (studentnumbers: string[]) => {
|
||||||
const data = { studentnumbers }
|
const data = { studentnumbers }
|
||||||
const response = await client.post('/v1/students', data, params)
|
const response = await client.post('/students', data, params)
|
||||||
return response.data
|
return response.data
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,6 +54,6 @@ export const updateSISStudyPlans = async (days: number) => {
|
|||||||
limit: 1000,
|
limit: 1000,
|
||||||
})
|
})
|
||||||
const studentnumbers = result.map(r => r.studentnumber)
|
const studentnumbers = result.map(r => r.studentnumber)
|
||||||
const response = await client.post('v1/studyplans', { studentnumbers }, params)
|
const response = await client.post('studyplans', { studentnumbers }, params)
|
||||||
return response.data
|
return response.data
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const populationUrl = (
|
|||||||
semesters: ('SPRING' | 'FALL')[] = [],
|
semesters: ('SPRING' | 'FALL')[] = [],
|
||||||
students: string[] = []
|
students: string[] = []
|
||||||
) => {
|
) => {
|
||||||
return `/v3/populationstatistics?${programme && 'programme=' + programme}${years.map(year => '&years=' + year).join('')}${semesters.map(sem => '&semesters=' + sem).join('')}${students.map(s => '&studentStatuses=' + s).join('')}`
|
return `/populationstatistics?${programme && 'programme=' + programme}${years.map(year => '&years=' + year).join('')}${semesters.map(sem => '&semesters=' + sem).join('')}${students.map(s => '&studentStatuses=' + s).join('')}`
|
||||||
}
|
}
|
||||||
|
|
||||||
void describe('Population statistics', async () => {
|
void describe('Population statistics', async () => {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export const StudentInfoCard = ({ student }: { student: StudentPageStudent }) =>
|
|||||||
)
|
)
|
||||||
|
|
||||||
const updateStudent = async () => {
|
const updateStudent = async () => {
|
||||||
await callApi('/updater/update/v2/customlist/students', 'post', [student.studentNumber])
|
await callApi('/updater/update/customlist/students', 'post', [student.studentNumber])
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -37,11 +37,11 @@ export const Updater = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateSISMeta = () => void apiCall('/updater/update/v2/meta')
|
const updateSISMeta = () => void apiCall('/updater/update/meta')
|
||||||
const updateSISStudents = () => void apiCall('/updater/update/v2/students')
|
const updateSISStudents = () => void apiCall('/updater/update/students')
|
||||||
const updateSISProgrammes = () => void apiCall('/updater/update/v2/programmes')
|
const updateSISProgrammes = () => void apiCall('/updater/update/programmes')
|
||||||
const updateSISCustomList = () =>
|
const updateSISCustomList = () =>
|
||||||
void apiCall(`/updater/update/v2/customlist/${type}`, 'post', customList.trim().split('\n'))
|
void apiCall(`/updater/update/customlist/${type}`, 'post', customList.trim().split('\n'))
|
||||||
const refreshTeacherLeaderboardForCurrentAndPreviousYear = () =>
|
const refreshTeacherLeaderboardForCurrentAndPreviousYear = () =>
|
||||||
void apiCall('/updater/refresh-teacher-leaderboard', 'post')
|
void apiCall('/updater/refresh-teacher-leaderboard', 'post')
|
||||||
const abortSisUpdater = () => void apiCall('/updater/abort')
|
const abortSisUpdater = () => void apiCall('/updater/abort')
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ const courseExclusionsApi = RTKApi.injectEndpoints({
|
|||||||
endpoints: builder => ({
|
endpoints: builder => ({
|
||||||
setCourseExclusion: builder.mutation<ExcludedCoursesResBody, ExcludedCoursesReqBody>({
|
setCourseExclusion: builder.mutation<ExcludedCoursesResBody, ExcludedCoursesReqBody>({
|
||||||
query: ({ courseCodes, curriculumVersion, programmeCode }) => ({
|
query: ({ courseCodes, curriculumVersion, programmeCode }) => ({
|
||||||
url: `/v3/course-exclusions/`,
|
url: `/course-exclusions/`,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: { courseCodes, curriculumVersion, programmeCode },
|
body: { courseCodes, curriculumVersion, programmeCode },
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
removeCourseExclusion: builder.mutation<ExcludedCoursesResBody, ExcludedCoursesReqBody>({
|
removeCourseExclusion: builder.mutation<ExcludedCoursesResBody, ExcludedCoursesReqBody>({
|
||||||
query: ({ courseCodes, curriculumVersion, programmeCode }) => ({
|
query: ({ courseCodes, curriculumVersion, programmeCode }) => ({
|
||||||
url: `/v3/course-exclusions/`,
|
url: `/course-exclusions/`,
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
body: { courseCodes, curriculumVersion, programmeCode },
|
body: { courseCodes, curriculumVersion, programmeCode },
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ const courseSearchApi = RTKApi.injectEndpoints({
|
|||||||
endpoints: builder => ({
|
endpoints: builder => ({
|
||||||
getCourseSearchResult: builder.query<GetCourseSearchResultResponse, GetCourseSearchResultRequest>({
|
getCourseSearchResult: builder.query<GetCourseSearchResultResponse, GetCourseSearchResultRequest>({
|
||||||
query: ({ name, code, includeSpecial }) => ({
|
query: ({ name, code, includeSpecial }) => ({
|
||||||
url: '/v2/coursesmulti',
|
url: '/coursesmulti',
|
||||||
params: { name, code, includeSpecial },
|
params: { name, code, includeSpecial },
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const courseStatsApi = RTKApi.injectEndpoints({
|
|||||||
separate?: boolean
|
separate?: boolean
|
||||||
combineSubstitutions?: boolean
|
combineSubstitutions?: boolean
|
||||||
}) => ({
|
}) => ({
|
||||||
url: '/v3/courseyearlystats',
|
url: '/courseyearlystats',
|
||||||
params: { codes, separate, combineSubstitutions },
|
params: { codes, separate, combineSubstitutions },
|
||||||
}),
|
}),
|
||||||
transformResponse: (
|
transformResponse: (
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import { CurriculumOption, CurriculumDetails } from '@oodikone/shared/types'
|
|||||||
const curriculumsApi = RTKApi.injectEndpoints({
|
const curriculumsApi = RTKApi.injectEndpoints({
|
||||||
endpoints: builder => ({
|
endpoints: builder => ({
|
||||||
getCurriculumOptions: builder.query<CurriculumOption[], { code: string }>({
|
getCurriculumOptions: builder.query<CurriculumOption[], { code: string }>({
|
||||||
query: ({ code }) => `/v3/curriculum-options/${code}`,
|
query: ({ code }) => `/curriculum-options/${code}`,
|
||||||
}),
|
}),
|
||||||
getCurriculums: builder.query<CurriculumDetails, { code: string; periodIds: string[] }>({
|
getCurriculums: builder.query<CurriculumDetails, { code: string; periodIds: string[] }>({
|
||||||
query: ({ code, periodIds }) => `/v3/curriculum/${code}/${periodIds.join(',')}`,
|
query: ({ code, periodIds }) => `/curriculum/${code}/${periodIds.join(',')}`,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const populationApi = RTKApi.injectEndpoints({
|
|||||||
endpoints: builder => ({
|
endpoints: builder => ({
|
||||||
getPopulationStatistics: builder.query<Output<PopulationstatisticsResBody>, PopulationQuery>({
|
getPopulationStatistics: builder.query<Output<PopulationstatisticsResBody>, PopulationQuery>({
|
||||||
query: params => ({
|
query: params => ({
|
||||||
url: '/v3/populationstatistics/',
|
url: '/populationstatistics/',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
params,
|
params,
|
||||||
}),
|
}),
|
||||||
@@ -24,7 +24,7 @@ const populationApi = RTKApi.injectEndpoints({
|
|||||||
}),
|
}),
|
||||||
getCustomPopulation: builder.query<Output<GetCustomPopulationResBody>, CustomPopulationQuery>({
|
getCustomPopulation: builder.query<Output<GetCustomPopulationResBody>, CustomPopulationQuery>({
|
||||||
query: ({ studentNumbers, tags }) => ({
|
query: ({ studentNumbers, tags }) => ({
|
||||||
url: '/v3/populationstatisticsbystudentnumbers',
|
url: '/populationstatisticsbystudentnumbers',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: {
|
body: {
|
||||||
studentNumbers,
|
studentNumbers,
|
||||||
@@ -38,7 +38,7 @@ const populationApi = RTKApi.injectEndpoints({
|
|||||||
PopulationstatisticsbycourseParams
|
PopulationstatisticsbycourseParams
|
||||||
>({
|
>({
|
||||||
query: ({ coursecodes, from, to, separate, unifyCourses }) => ({
|
query: ({ coursecodes, from, to, separate, unifyCourses }) => ({
|
||||||
url: '/v3/populationstatisticsbycourse',
|
url: '/populationstatisticsbycourse',
|
||||||
params: { coursecodes, from, to, separate, unifyCourses },
|
params: { coursecodes, from, to, separate, unifyCourses },
|
||||||
}),
|
}),
|
||||||
transformResponse: formatPopulationData<PopulationstatisticsbycourseResBody>,
|
transformResponse: formatPopulationData<PopulationstatisticsbycourseResBody>,
|
||||||
@@ -48,12 +48,12 @@ const populationApi = RTKApi.injectEndpoints({
|
|||||||
PopulationstatisticsMaxYearsToCreatePopulationFormQuery
|
PopulationstatisticsMaxYearsToCreatePopulationFormQuery
|
||||||
>({
|
>({
|
||||||
query: ({ courseCodes }) => ({
|
query: ({ courseCodes }) => ({
|
||||||
url: '/v3/populationstatistics/maxYearsToCreatePopulationFrom',
|
url: '/populationstatistics/maxYearsToCreatePopulationFrom',
|
||||||
params: { courseCodes },
|
params: { courseCodes },
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
getProgrammes: builder.query<PopulationstatisticsStudyprogrammesResBody, void>({
|
getProgrammes: builder.query<PopulationstatisticsStudyprogrammesResBody, void>({
|
||||||
query: () => '/v3/populationstatistics/studyprogrammes',
|
query: () => '/populationstatistics/studyprogrammes',
|
||||||
keepUnusedDataFor: 60 * 60,
|
keepUnusedDataFor: 60 * 60,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -20,20 +20,20 @@ const studyProgrammeApi = RTKApi.injectEndpoints({
|
|||||||
{ id: string; yearType: YearType; specialGroups: SpecialGroups; combinedProgramme: string }
|
{ id: string; yearType: YearType; specialGroups: SpecialGroups; combinedProgramme: string }
|
||||||
>({
|
>({
|
||||||
query: ({ id, yearType, specialGroups, combinedProgramme }) =>
|
query: ({ id, yearType, specialGroups, combinedProgramme }) =>
|
||||||
`/v2/studyprogrammes/${id}/basicstats?year_type=${yearType}&special_groups=${specialGroups}&combined_programme=${combinedProgramme}`,
|
`/studyprogrammes/${id}/basicstats?year_type=${yearType}&special_groups=${specialGroups}&combined_programme=${combinedProgramme}`,
|
||||||
}),
|
}),
|
||||||
getColorizedTableCourseStats: builder.query<
|
getColorizedTableCourseStats: builder.query<
|
||||||
any, // TODO: Type
|
any, // TODO: Type
|
||||||
{ id: string }
|
{ id: string }
|
||||||
>({
|
>({
|
||||||
query: ({ id }) => `/v2/studyprogrammes/${id}/colorizedtablecoursestats`,
|
query: ({ id }) => `/studyprogrammes/${id}/colorizedtablecoursestats`,
|
||||||
}),
|
}),
|
||||||
getCreditStats: builder.query<
|
getCreditStats: builder.query<
|
||||||
CreditStatsPayload,
|
CreditStatsPayload,
|
||||||
{ codes: string[]; specialGroups: SpecialGroups; yearType: YearType }
|
{ codes: string[]; specialGroups: SpecialGroups; yearType: YearType }
|
||||||
>({
|
>({
|
||||||
query: ({ codes, specialGroups, yearType }) =>
|
query: ({ codes, specialGroups, yearType }) =>
|
||||||
`/v2/studyprogrammes/creditstats?codes=${JSON.stringify(
|
`/studyprogrammes/creditstats?codes=${JSON.stringify(
|
||||||
codes
|
codes
|
||||||
)}&yearType=${yearType}&specialGroups=${specialGroups}`,
|
)}&yearType=${yearType}&specialGroups=${specialGroups}`,
|
||||||
}),
|
}),
|
||||||
@@ -42,38 +42,38 @@ const studyProgrammeApi = RTKApi.injectEndpoints({
|
|||||||
{ id: string; yearType: YearType; specialGroups: SpecialGroups; combinedProgramme: string }
|
{ id: string; yearType: YearType; specialGroups: SpecialGroups; combinedProgramme: string }
|
||||||
>({
|
>({
|
||||||
query: ({ id, yearType, specialGroups, combinedProgramme }) =>
|
query: ({ id, yearType, specialGroups, combinedProgramme }) =>
|
||||||
`/v2/studyprogrammes/${id}/graduationstats?year_type=${yearType}&special_groups=${specialGroups}&combined_programme=${combinedProgramme}`,
|
`/studyprogrammes/${id}/graduationstats?year_type=${yearType}&special_groups=${specialGroups}&combined_programme=${combinedProgramme}`,
|
||||||
}),
|
}),
|
||||||
getStudyTrackStats: builder.query<
|
getStudyTrackStats: builder.query<
|
||||||
StudyTrackStats,
|
StudyTrackStats,
|
||||||
{ id: string; specialGroups: SpecialGroups; combinedProgramme: string }
|
{ id: string; specialGroups: SpecialGroups; combinedProgramme: string }
|
||||||
>({
|
>({
|
||||||
query: ({ id, specialGroups, combinedProgramme }) =>
|
query: ({ id, specialGroups, combinedProgramme }) =>
|
||||||
`/v2/studyprogrammes/${id}/studytrackstats?special_groups=${specialGroups}&combined_programme=${combinedProgramme}`,
|
`/studyprogrammes/${id}/studytrackstats?special_groups=${specialGroups}&combined_programme=${combinedProgramme}`,
|
||||||
}),
|
}),
|
||||||
getProgrammeCoursesStats: builder.query<
|
getProgrammeCoursesStats: builder.query<
|
||||||
StudyProgrammeCourse[],
|
StudyProgrammeCourse[],
|
||||||
{ id: string; yearType: YearType; combinedProgramme: string }
|
{ id: string; yearType: YearType; combinedProgramme: string }
|
||||||
>({
|
>({
|
||||||
query: ({ id, yearType, combinedProgramme }) =>
|
query: ({ id, yearType, combinedProgramme }) =>
|
||||||
`/v2/studyprogrammes/${id}/coursestats?yearType=${yearType}&combinedProgramme=${combinedProgramme}`,
|
`/studyprogrammes/${id}/coursestats?yearType=${yearType}&combinedProgramme=${combinedProgramme}`,
|
||||||
}),
|
}),
|
||||||
getStudyTracks: builder.query<Record<string, Name | string>, { id: string }>({
|
getStudyTracks: builder.query<Record<string, Name | string>, { id: string }>({
|
||||||
query: ({ id }) => `/v2/studyprogrammes/${id}/studytracks`,
|
query: ({ id }) => `/studyprogrammes/${id}/studytracks`,
|
||||||
}),
|
}),
|
||||||
updateBasicView: builder.query<
|
updateBasicView: builder.query<
|
||||||
any, // TODO: Type
|
any, // TODO: Type
|
||||||
{ id: string; combinedProgramme: string }
|
{ id: string; combinedProgramme: string }
|
||||||
>({
|
>({
|
||||||
query: ({ id, combinedProgramme }) =>
|
query: ({ id, combinedProgramme }) =>
|
||||||
`/v2/studyprogrammes/${id}/update_basicview?combined_programme=${combinedProgramme}`,
|
`/studyprogrammes/${id}/update_basicview?combined_programme=${combinedProgramme}`,
|
||||||
}),
|
}),
|
||||||
updateStudyTrackView: builder.query<
|
updateStudyTrackView: builder.query<
|
||||||
any, // TODO: Type
|
any, // TODO: Type
|
||||||
{ id: string; combinedProgramme: string }
|
{ id: string; combinedProgramme: string }
|
||||||
>({
|
>({
|
||||||
query: ({ id, combinedProgramme }) =>
|
query: ({ id, combinedProgramme }) =>
|
||||||
`/v2/studyprogrammes/${id}/update_studytrackview?combined_programme=${combinedProgramme}`,
|
`/studyprogrammes/${id}/update_studytrackview?combined_programme=${combinedProgramme}`,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
overrideExisting: false,
|
overrideExisting: false,
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ const app = express()
|
|||||||
app.use(express.json())
|
app.use(express.json())
|
||||||
app.use(message)
|
app.use(message)
|
||||||
|
|
||||||
app.get('/v1/healthcheck', async (_, res) => {
|
app.get('/healthcheck', async (_, res) => {
|
||||||
const latestMessage = await redisClient.get(REDIS_LATEST_MESSAGE_RECEIVED)
|
const latestMessage = await redisClient.get(REDIS_LATEST_MESSAGE_RECEIVED)
|
||||||
const threshold = new Date().getTime() - 1000 * 60 * 60 * 6 // 6 hours ago
|
const threshold = new Date().getTime() - 1000 * 60 * 60 * 6 // 6 hours ago
|
||||||
if (!latestMessage || new Date(latestMessage).getTime() < threshold) {
|
if (!latestMessage || new Date(latestMessage).getTime() < threshold) {
|
||||||
@@ -53,20 +53,20 @@ app.get('/v1/healthcheck', async (_, res) => {
|
|||||||
|
|
||||||
app.use(auth)
|
app.use(auth)
|
||||||
|
|
||||||
app.get('/v1/meta', async (_, res) => {
|
app.get('/meta', async (_, res) => {
|
||||||
await scheduleMeta()
|
await scheduleMeta()
|
||||||
|
|
||||||
res.locals.msg('Scheduled meta')
|
res.locals.msg('Scheduled meta')
|
||||||
})
|
})
|
||||||
|
|
||||||
app.get('/v1/students', async (_, res) => {
|
app.get('/students', async (_, res) => {
|
||||||
await scheduleStudents()
|
await scheduleStudents()
|
||||||
|
|
||||||
logger.info('Scheduled students')
|
logger.info('Scheduled students')
|
||||||
res.locals.msg('Scheduled students')
|
res.locals.msg('Scheduled students')
|
||||||
})
|
})
|
||||||
|
|
||||||
app.post('/v1/studyplans', async (req, res) => {
|
app.post('/studyplans', async (req, res) => {
|
||||||
const { studentnumbers } = req.body
|
const { studentnumbers } = req.body
|
||||||
const msg = `Scheduling update of ${studentnumbers.length} students whose studyplan has not been updated recently`
|
const msg = `Scheduling update of ${studentnumbers.length} students whose studyplan has not been updated recently`
|
||||||
logger.info(msg)
|
logger.info(msg)
|
||||||
@@ -75,14 +75,14 @@ app.post('/v1/studyplans', async (req, res) => {
|
|||||||
res.locals.msg('Shceduled studyplans update')
|
res.locals.msg('Shceduled studyplans update')
|
||||||
})
|
})
|
||||||
|
|
||||||
app.get('/v1/programmes', async (_, res) => {
|
app.get('/programmes', async (_, res) => {
|
||||||
await scheduleProgrammes()
|
await scheduleProgrammes()
|
||||||
|
|
||||||
logger.info('Scheduled programmes')
|
logger.info('Scheduled programmes')
|
||||||
res.locals.msg('Scheduled programmes')
|
res.locals.msg('Scheduled programmes')
|
||||||
})
|
})
|
||||||
|
|
||||||
app.post('/v1/students', async (req, res) => {
|
app.post('/students', async (req, res) => {
|
||||||
const studentnumbers = req.body.studentnumbers.map(n => (n[0] === '0' ? n : `0${n}`))
|
const studentnumbers = req.body.studentnumbers.map(n => (n[0] === '0' ? n : `0${n}`))
|
||||||
|
|
||||||
logger.info(`Scheduling ${studentnumbers.length} custom studentnumbers`)
|
logger.info(`Scheduling ${studentnumbers.length} custom studentnumbers`)
|
||||||
@@ -91,13 +91,13 @@ app.post('/v1/students', async (req, res) => {
|
|||||||
res.locals.msg('Scheduled studentnumbers')
|
res.locals.msg('Scheduled studentnumbers')
|
||||||
})
|
})
|
||||||
|
|
||||||
app.get('/v1/rediscache', async (req, res) => {
|
app.get('/rediscache', async (req, res) => {
|
||||||
await queue.add('reload_redis')
|
await queue.add('reload_redis')
|
||||||
logger.info('Scheduled redis cache reloading')
|
logger.info('Scheduled redis cache reloading')
|
||||||
res.locals.msg('Scheduled redis cache reloading')
|
res.locals.msg('Scheduled redis cache reloading')
|
||||||
})
|
})
|
||||||
|
|
||||||
app.get('/v1/abort', async (req, res) => {
|
app.get('/abort', async (req, res) => {
|
||||||
const jobCountsBeforeDrain = await queue.getJobCounts()
|
const jobCountsBeforeDrain = await queue.getJobCounts()
|
||||||
await queue.drain()
|
await queue.drain()
|
||||||
const jobCountsAfterDrain = await queue.getJobCounts()
|
const jobCountsAfterDrain = await queue.getJobCounts()
|
||||||
@@ -115,7 +115,7 @@ app.get('/v1/abort', async (req, res) => {
|
|||||||
res.locals.msg(`Removed approximately ${differenceString} from queue`)
|
res.locals.msg(`Removed approximately ${differenceString} from queue`)
|
||||||
})
|
})
|
||||||
|
|
||||||
app.post('/v1/courses', async (req, res) => {
|
app.post('/courses', async (req, res) => {
|
||||||
await scheduleByCourseCodes(req.body.coursecodes)
|
await scheduleByCourseCodes(req.body.coursecodes)
|
||||||
|
|
||||||
logger.info('Scheduled courses')
|
logger.info('Scheduled courses')
|
||||||
|
|||||||
Reference in New Issue
Block a user