mirror of
https://github.com/UniversityOfHelsinkiCS/oodikone.git
synced 2026-10-12 19:03:39 +03:00
[META] Remove apparent service provider specific code
This commit is contained in:
committed by
Aaro Koivukangas
parent
4ed8b3d2e9
commit
c2684a4e8e
@@ -65,9 +65,6 @@ instrumented/
|
||||
.vscode/launch.json
|
||||
.vscode/terminals.json
|
||||
|
||||
# Funidata specific
|
||||
environments/
|
||||
|
||||
# Target of shared symlink
|
||||
services/**/src/shared
|
||||
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
services:
|
||||
oodikone-backend:
|
||||
build:
|
||||
context: ${OODIKONE_REPO:-.}/services
|
||||
dockerfile: backend/Dockerfile
|
||||
args:
|
||||
SENTRY_ENVIRONMENT: ''
|
||||
SENTRY_RELEASE: ''
|
||||
SENTRY_DSN: ''
|
||||
SERVICE_PROVIDER: fd
|
||||
NODE_ENV: production
|
||||
image: ${DOCKER_OODIKONE_NAMESPACE:-637423527834.dkr.ecr.eu-north-1.amazonaws.com/oodikone}/oodikone-backend:${DOCKER_IMAGE_TAG:-dev}
|
||||
|
||||
oodikone-frontend:
|
||||
build:
|
||||
context: ${OODIKONE_REPO:-.}/services
|
||||
dockerfile: frontend/Dockerfile
|
||||
args:
|
||||
SENTRY_ENVIRONMENT: ''
|
||||
SENTRY_RELEASE: ''
|
||||
SENTRY_DSN: ''
|
||||
SERVICE_PROVIDER: fd
|
||||
LANGUAGE_CENTER_VIEW_ENABLED: 'false' # currently no intention to be enabled
|
||||
SIS_URL: 'https://sis-qa.funidata.fi'
|
||||
NODE_ENV: production
|
||||
image: ${DOCKER_OODIKONE_NAMESPACE:-637423527834.dkr.ecr.eu-north-1.amazonaws.com/oodikone}/oodikone-frontend:${DOCKER_IMAGE_TAG:-dev}
|
||||
|
||||
updater-scheduler:
|
||||
build:
|
||||
context: ${OODIKONE_REPO:-.}/updater/sis-updater-scheduler
|
||||
args:
|
||||
SENTRY_ENVIRONMENT: ''
|
||||
SENTRY_RELEASE: ''
|
||||
SENTRY_DSN: ''
|
||||
NODE_ENV: production
|
||||
image: ${DOCKER_OODIKONE_NAMESPACE:-637423527834.dkr.ecr.eu-north-1.amazonaws.com/oodikone}/updater-scheduler:${DOCKER_IMAGE_TAG:-dev}
|
||||
|
||||
updater-worker:
|
||||
build:
|
||||
context: ${OODIKONE_REPO:-.}/updater/sis-updater-worker
|
||||
args:
|
||||
SENTRY_ENVIRONMENT: ''
|
||||
SENTRY_RELEASE: ''
|
||||
SENTRY_DSN: ''
|
||||
SERVICE_PROVIDER: fd
|
||||
NODE_ENV: production
|
||||
image: ${DOCKER_OODIKONE_NAMESPACE:-637423527834.dkr.ecr.eu-north-1.amazonaws.com/oodikone}/updater-worker:${DOCKER_IMAGE_TAG:-dev}
|
||||
@@ -1,190 +0,0 @@
|
||||
x-defaults: &defaults
|
||||
restart: unless-stopped
|
||||
|
||||
x-build_defaults: &build_defaults
|
||||
dockerfile: dev.Dockerfile
|
||||
|
||||
services:
|
||||
adminer:
|
||||
<<: *defaults
|
||||
container_name: adminer
|
||||
environment:
|
||||
ADMINER_DESIGN: pepa-linha
|
||||
image: adminer:4.8.1
|
||||
ports:
|
||||
- 5050:8080
|
||||
volumes:
|
||||
- ./adminer-plugins:/var/www/html/plugins-enabled
|
||||
|
||||
backend:
|
||||
<<: *defaults
|
||||
build:
|
||||
<<: *build_defaults
|
||||
context: services/backend
|
||||
depends_on:
|
||||
- kone-db
|
||||
- redis
|
||||
- sis-db
|
||||
- user-db
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
DB_URL_KONE: postgres://postgres@kone-db:5432/kone-db
|
||||
DB_URL_USER: postgres://postgres@user-db:5432/user-db
|
||||
FRONT_URL: http://localhost:3000
|
||||
REDIS: redis
|
||||
SECRET_TOKEN: dev
|
||||
SIS_DB_URL: postgres://postgres@sis-db:5432/sis-db
|
||||
SIS_UPDATER_URL: http://sis-updater-scheduler:8082
|
||||
IMPORTER_DB_API_URL: 'https://localhost:3005'
|
||||
JAMI_URL: 'http://jami:3003/'
|
||||
SERVICE_PROVIDER: fd
|
||||
SIS_HOST: ${SIS_HOST}
|
||||
SIS_GRAPHQL_APPLICATION_ACCOUNT: ${SIS_GRAPHQL_APPLICATION_ACCOUNT}
|
||||
SIS_GRAPHQL_APPLICATION_KEY: ${SIS_GRAPHQL_APPLICATION_KEY}
|
||||
IMPORTER_DB_API_USER: dev_user
|
||||
IMPORTER_DB_API_PASSWORD: dev_password
|
||||
ROOT_ORG_ID: ${ROOT_ORG_ID}
|
||||
LANGUAGE_CENTER_VIEW_ENABLED: 'false'
|
||||
ports:
|
||||
- 8080:8080
|
||||
volumes:
|
||||
- backend-nodemod:/opt/app-root/backend/node_modules
|
||||
- ./environments/testu:/opt/app-root/backend/src/environment
|
||||
- ./services/backend/:/opt/app-root/backend
|
||||
- ./services/shared/:/opt/app-root/shared
|
||||
|
||||
frontend:
|
||||
<<: *defaults
|
||||
build:
|
||||
<<: *build_defaults
|
||||
context: services/frontend
|
||||
container_name: frontend
|
||||
ports:
|
||||
- 3000:3000
|
||||
environment:
|
||||
REACT_APP_SERVICE_PROVIDER: fd
|
||||
REACT_APP_LANGUAGE_CENTER_VIEW_ENABLED: 'false'
|
||||
REACT_APP_SIS_URL: 'https://sis-qa.funidata.fi'
|
||||
volumes:
|
||||
- frontend-nodemod:/opt/app-root/frontend/node_modules
|
||||
- ./services/frontend/:/opt/app-root/frontend
|
||||
- ./services/shared/:/opt/app-root/shared
|
||||
|
||||
kone-db:
|
||||
<<: *defaults
|
||||
container_name: kone-db
|
||||
environment:
|
||||
PGDATA: /data
|
||||
POSTGRES_DB: kone-db
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
image: postgres:15.10
|
||||
ports:
|
||||
- 12349:5432
|
||||
volumes:
|
||||
- kone-db-data:/data
|
||||
|
||||
redis:
|
||||
<<: *defaults
|
||||
command: 'redis-server --appendonly yes'
|
||||
container_name: redis
|
||||
image: redis:6.2.16
|
||||
ports:
|
||||
- '6379:6379'
|
||||
volumes:
|
||||
- redis-data:/data
|
||||
|
||||
sis-db:
|
||||
<<: *defaults
|
||||
container_name: sis-db
|
||||
environment:
|
||||
PGDATA: /data
|
||||
POSTGRES_DB: sis-db
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
image: postgres:15.10
|
||||
volumes:
|
||||
- sis-db-data:/data
|
||||
shm_size: 2gb
|
||||
ports:
|
||||
- 12345:5432
|
||||
|
||||
sis-updater-scheduler:
|
||||
<<: *defaults
|
||||
build:
|
||||
<<: *build_defaults
|
||||
context: updater/sis-updater-scheduler
|
||||
container_name: sis-updater-scheduler
|
||||
extra_hosts:
|
||||
- 'host.docker.internal:host-gateway'
|
||||
depends_on:
|
||||
- redis
|
||||
environment:
|
||||
REDIS_HOST: redis
|
||||
REDIS_PORT: 6379
|
||||
SECRET_TOKEN: dev
|
||||
SIS_IMPORTER_HOST: ${SIS_IMPORTER_DB_HOST:-host.docker.internal}
|
||||
SIS_IMPORTER_PORT: ${SIS_IMPORTER_DB_PORT:-15234}
|
||||
SIS_IMPORTER_DATABASE: importer-db
|
||||
SIS_IMPORTER_PASSWORD: dev
|
||||
SIS_IMPORTER_USER: dev
|
||||
SERVICE_PROVIDER: fd
|
||||
ports:
|
||||
- 8082:8082
|
||||
volumes:
|
||||
- ./updater/sis-updater-scheduler/:/opt/app-root/src
|
||||
|
||||
sis-updater-worker:
|
||||
<<: *defaults
|
||||
deploy:
|
||||
replicas: 2
|
||||
mode: replicated
|
||||
build:
|
||||
<<: *build_defaults
|
||||
context: updater/sis-updater-worker
|
||||
depends_on:
|
||||
- redis
|
||||
- sis-db
|
||||
extra_hosts:
|
||||
- 'host.docker.internal:host-gateway'
|
||||
environment:
|
||||
DB_URL: postgres://postgres@sis-db:5432/sis-db
|
||||
REDIS_HOST: redis
|
||||
REDIS_PORT: 6379
|
||||
SIS_IMPORTER_HOST: ${SIS_IMPORTER_DB_HOST:-host.docker.internal}
|
||||
SIS_IMPORTER_PORT: ${SIS_IMPORTER_DB_PORT:-15234}
|
||||
SIS_IMPORTER_DATABASE: importer-db
|
||||
SIS_IMPORTER_PASSWORD: dev
|
||||
SIS_IMPORTER_USER: dev
|
||||
SIS_PASSWORD: postgres
|
||||
ROOT_ORG_ID: ${ROOT_ORG_ID}
|
||||
SERVICE_PROVIDER: fd
|
||||
volumes:
|
||||
- ./updater/sis-updater-worker/:/opt/app-root/src
|
||||
|
||||
user-db:
|
||||
<<: *defaults
|
||||
container_name: user-db
|
||||
environment:
|
||||
PGDATA: /data
|
||||
POSTGRES_DB: user-db
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
image: postgres:15.10
|
||||
volumes:
|
||||
- user-db-data:/data
|
||||
ports:
|
||||
- 12347:5432
|
||||
|
||||
volumes:
|
||||
backend-nodemod:
|
||||
frontend-nodemod:
|
||||
kone-db-data:
|
||||
redis-data:
|
||||
sis-db-data:
|
||||
user-db-data:
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: oodikone
|
||||
importer:
|
||||
name: importer_network
|
||||
external: true
|
||||
@@ -33,12 +33,6 @@ export const baseUrl = isDev ? '/api' : ''
|
||||
export const frontUrl = process.env.FRONT_URL
|
||||
export const backendPort = 8080
|
||||
|
||||
// System run in whose environment
|
||||
export const serviceProvider = process.env.SERVICE_PROVIDER?.toLowerCase() ?? 'toska'
|
||||
|
||||
// Optional logout-url configuration
|
||||
export const configLogoutUrl = serviceProvider === 'toska' ? undefined : process.env.LOGOUT_URL
|
||||
|
||||
// Other stuff
|
||||
export const { DB_URL_KONE, DB_URL_USER, SECRET_TOKEN, SIS_DB_URL, SIS_UPDATER_URL, CRYPT_KEY } = process.env
|
||||
|
||||
|
||||
@@ -2,9 +2,8 @@ import * as Sentry from '@sentry/node'
|
||||
import { NextFunction, Request, Response } from 'express'
|
||||
import { intersection } from 'lodash-es'
|
||||
|
||||
import { configLogoutUrl, isDev, requiredGroup, serviceProvider } from '../config'
|
||||
import { getMockedUser, getMockedUserFd, getOrganizationAccess, getUserFd, getUserToska } from '../services/userService'
|
||||
import { FormattedUser } from '../types'
|
||||
import { requiredGroup } from '../config'
|
||||
import { getMockedUser, getOrganizationAccess, getUserToska } from '../services/userService'
|
||||
import { ApplicationError } from '../util/customErrors'
|
||||
import logger from '../util/logger'
|
||||
|
||||
@@ -81,33 +80,4 @@ const toskaUserMiddleware = async (req: Request, _: Response, next: NextFunction
|
||||
next()
|
||||
}
|
||||
|
||||
const fdUserMiddleware = async (req: Request, _res: Response, next: NextFunction) => {
|
||||
const { remote_user: remoteUser, 'x-show-as-user': showAsUser } = req.headers
|
||||
|
||||
if (!remoteUser) {
|
||||
throw new ApplicationError('Not enough data in request headers, remote_user was missing', 403, { configLogoutUrl })
|
||||
}
|
||||
|
||||
let user: FormattedUser | null
|
||||
|
||||
// getMockedUser in production requires the superAdmin role, which is only available
|
||||
// via iamGroups, so it's now only implemented for the dev environment
|
||||
if (showAsUser && isDev) {
|
||||
user = await getMockedUserFd({ userToMock: showAsUser as string, mockedBy: remoteUser as string })
|
||||
} else {
|
||||
user = await getUserFd({ username: remoteUser as string })
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
throw new ApplicationError(`Could not grant access with the eppn ${remoteUser}.`, 403, { configLogoutUrl })
|
||||
}
|
||||
|
||||
req.user = user
|
||||
req.logoutUrl = configLogoutUrl
|
||||
|
||||
next()
|
||||
}
|
||||
|
||||
const currentUserMiddleware = serviceProvider === 'toska' ? toskaUserMiddleware : fdUserMiddleware
|
||||
|
||||
export default currentUserMiddleware
|
||||
export default toskaUserMiddleware
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import headersMiddleware from 'unfuck-utf8-headers-middleware'
|
||||
|
||||
import { serviceProvider } from '../config'
|
||||
|
||||
const headersToska = ['uid', 'displayName', 'shib-session-id', 'hyGroupCn', 'mail', 'hyPersonSisuId']
|
||||
const headersOther = ['remote_user']
|
||||
|
||||
const headers = serviceProvider === 'toska' ? headersToska : headersOther
|
||||
const headers = headersToska
|
||||
|
||||
export default headersMiddleware(headers)
|
||||
|
||||
@@ -3,7 +3,7 @@ import compression from 'compression'
|
||||
import cors from 'cors'
|
||||
import { Express, json as jsonExpress } from 'express'
|
||||
|
||||
import { frontUrl, languageCenterViewEnabled, serviceProvider } from './config'
|
||||
import { frontUrl, languageCenterViewEnabled } from './config'
|
||||
import accessLogger from './middleware/accessLogger'
|
||||
import * as auth from './middleware/auth'
|
||||
import currentUserMiddleware from './middleware/currentUser'
|
||||
@@ -34,8 +34,7 @@ import tags from './routes/tags'
|
||||
import teachers from './routes/teachers'
|
||||
import university from './routes/university'
|
||||
import updater from './routes/updater'
|
||||
import usersToska from './routes/users'
|
||||
import usersFd from './routes/usersFd'
|
||||
import users from './routes/users'
|
||||
|
||||
const routes = (app: Express, url: string) => {
|
||||
app.use(cors({ credentials: true, origin: frontUrl }))
|
||||
@@ -66,12 +65,7 @@ const routes = (app: Express, url: string) => {
|
||||
app.use(`${url}/university`, university)
|
||||
app.use(`${url}/updater`, auth.roles(['admin']), updater)
|
||||
app.use(`${url}/teachers`, teachers)
|
||||
if (serviceProvider === 'toska') {
|
||||
app.use(`${url}/users`, usersToska)
|
||||
} else {
|
||||
app.use(`${url}/users`, usersToska)
|
||||
app.use(`${url}/users`, usersFd)
|
||||
}
|
||||
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)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Request, Response, Router } from 'express'
|
||||
|
||||
import { mapToProviders, splitByEmptySpace } from '@oodikone/shared/util'
|
||||
import { serviceProvider } from '../config'
|
||||
import * as auth from '../middleware/auth'
|
||||
import { getProvidersOfFaculty, isFaculty } from '../services/organizations'
|
||||
import { getTeachersBySearchTerm, getTeacherStatistics, getYearlyStatistics } from '../services/teachers'
|
||||
@@ -12,8 +11,7 @@ const router = Router()
|
||||
|
||||
const iamGroupsGivingFullAccess = ['hy-dekaanit', 'hy-varadekaanit-opetus']
|
||||
|
||||
const fullAccessAuth = () =>
|
||||
serviceProvider === 'toska' ? auth.roles([], iamGroupsGivingFullAccess) : auth.roles(['teachers'])
|
||||
const fullAccessAuth = () => auth.roles([], iamGroupsGivingFullAccess)
|
||||
|
||||
interface GetTeachersRequest extends Request {
|
||||
query: {
|
||||
|
||||
@@ -2,7 +2,6 @@ import { Request, Response, Router } from 'express'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
|
||||
import { Graduated, NameWithCode } from '@oodikone/shared/types'
|
||||
import { serviceProvider } from '../config'
|
||||
import { magicFacultyCode } from '../config/organizationConstants'
|
||||
import { OrganizationModel } from '../models'
|
||||
import { getDegreeProgrammesOfFaculty } from '../services/faculty/faculty'
|
||||
@@ -125,7 +124,7 @@ router.get('/allgraduationstats', async (_req: Request, res: Response) => {
|
||||
const allFaculties = await getSortedFaculties()
|
||||
const facultyCodes = allFaculties.map(faculty => faculty.code)
|
||||
const facultyData: Record<string, Awaited<ReturnType<typeof countGraduationTimes>>> = {}
|
||||
const programmeFilter = serviceProvider === 'toska' ? 'NEW_DEGREE_PROGRAMMES' : 'ALL_PROGRAMMES'
|
||||
const programmeFilter = 'NEW_DEGREE_PROGRAMMES'
|
||||
for (const facultyCode of facultyCodes) {
|
||||
let data: any = await getGraduationStats(facultyCode, programmeFilter, true)
|
||||
if (!data) {
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
import { Request, Response, Router } from 'express'
|
||||
|
||||
import { isDev } from '../config'
|
||||
import * as auth from '../middleware/auth'
|
||||
import * as userService from '../services/userService'
|
||||
|
||||
const router = Router()
|
||||
|
||||
interface NewUserEppnRequest extends Request {
|
||||
params: {
|
||||
newUserEppn: string
|
||||
}
|
||||
}
|
||||
|
||||
router.get('/from-sisu-by-eppn/:newUserEppn', auth.roles(['admin']), async (req: NewUserEppnRequest, res: Response) => {
|
||||
let { username: requesterEppn } = req.user
|
||||
const { newUserEppn } = req.params
|
||||
// In order to test this feature in the dev environment we need to set an eppn that demo sisu will recognize
|
||||
if (isDev && requesterEppn === 'mluukkai') {
|
||||
requesterEppn = newUserEppn
|
||||
}
|
||||
const person = await userService.getUserFromSisuByEppn(requesterEppn, newUserEppn)
|
||||
res.json(person)
|
||||
})
|
||||
|
||||
interface User {
|
||||
id: string
|
||||
first_name: string
|
||||
last_name: string
|
||||
call_name: string
|
||||
eppn: string
|
||||
email_address: string
|
||||
student_number: string
|
||||
phone_number: string
|
||||
document_state: string
|
||||
}
|
||||
|
||||
interface AddUserRequest extends Request {
|
||||
body: {
|
||||
user: User
|
||||
}
|
||||
}
|
||||
|
||||
interface DeleteUserRequest extends Request {
|
||||
body: {
|
||||
userId: string
|
||||
}
|
||||
}
|
||||
|
||||
router.post('/add', auth.roles(['admin']), async (req: AddUserRequest, res: Response) => {
|
||||
const { user } = req.body
|
||||
const oldUser = await userService.findByUsername(user.eppn)
|
||||
if (oldUser) return res.status(400).json({ error: 'Trying to add a user already present in the user database.' })
|
||||
const success = await userService.addNewUser(user)
|
||||
res.json(success)
|
||||
})
|
||||
|
||||
router.delete('/delete', auth.roles(['admin']), async (req: DeleteUserRequest, res: Response) => {
|
||||
const { userId } = req.body
|
||||
try {
|
||||
await userService.deleteUserById(userId)
|
||||
res.json({ deleted: userId })
|
||||
} catch (error) {
|
||||
return res.status(400).json({ error: 'Deletion was unsuccessful with the user id included in the request' })
|
||||
}
|
||||
})
|
||||
|
||||
export default router
|
||||
@@ -3,7 +3,6 @@ import { QueryTypes } from 'sequelize'
|
||||
|
||||
import { Organization } from '@oodikone/shared/models'
|
||||
import { ProgrammeModuleWithRelevantAttributes } from '@oodikone/shared/types'
|
||||
import { serviceProvider } from '../../config'
|
||||
import { programmeCodes } from '../../config/programmeCodes'
|
||||
import { dbConnections } from '../../database/connection'
|
||||
import { OrganizationModel } from '../../models'
|
||||
@@ -57,9 +56,7 @@ export const getDegreeProgrammesOfOrganization = async (organizationId: string,
|
||||
const programmesWithProgIds = programmesOfOrganization.map(programme => ({
|
||||
...programme,
|
||||
progId:
|
||||
programme.code in programmeCodes && serviceProvider !== 'fd'
|
||||
? programmeCodes[programme.code as keyof typeof programmeCodes]
|
||||
: programme.code,
|
||||
programme.code in programmeCodes ? programmeCodes[programme.code as keyof typeof programmeCodes] : programme.code,
|
||||
}))
|
||||
const programmesGroupedByCode = groupBy(orderBy(programmesWithProgIds, ['valid_from'], ['desc']), prog => prog.code)
|
||||
const curriculumPeriods = await getCurriculumPeriods()
|
||||
|
||||
@@ -3,7 +3,6 @@ import { Op } from 'sequelize'
|
||||
|
||||
import { SISStudyRight, SISStudyRightElement } from '@oodikone/shared/models'
|
||||
import { DegreeProgrammeType, Phase } from '@oodikone/shared/types'
|
||||
import { serviceProvider } from '../../config'
|
||||
import { programmeCodes } from '../../config/programmeCodes'
|
||||
import { ProgrammeModuleModel } from '../../models'
|
||||
import { getDegreeProgrammeType } from '../../util'
|
||||
@@ -97,17 +96,11 @@ export const getThesisType = async (studyProgramme: string) => {
|
||||
const degreeProgrammeType = await getDegreeProgrammeType(studyProgramme)
|
||||
if (degreeProgrammeType === DegreeProgrammeType.MASTER) {
|
||||
const mastersThesisTypes = ['urn:code:course-unit-type:masters-thesis']
|
||||
if (serviceProvider !== 'toska') {
|
||||
mastersThesisTypes.push('urn:code:course-unit-type:amk-masters-thesis')
|
||||
}
|
||||
return mastersThesisTypes
|
||||
}
|
||||
|
||||
if (degreeProgrammeType === DegreeProgrammeType.BACHELOR) {
|
||||
const bachelorsThesisTypes = ['urn:code:course-unit-type:bachelors-thesis']
|
||||
if (serviceProvider !== 'toska') {
|
||||
bachelorsThesisTypes.push('urn:code:course-unit-type:amk-bachelors-thesis')
|
||||
}
|
||||
return bachelorsThesisTypes
|
||||
}
|
||||
|
||||
@@ -167,8 +160,7 @@ export const tableTitles = {
|
||||
} as const
|
||||
|
||||
export const getId = (code: string) => {
|
||||
if (serviceProvider !== 'fd') return code in programmeCodes ? programmeCodes[code as keyof typeof programmeCodes] : ''
|
||||
return code
|
||||
return code in programmeCodes ? programmeCodes[code as keyof typeof programmeCodes] : ''
|
||||
}
|
||||
|
||||
export const getGoal = async (programme?: string) => {
|
||||
|
||||
@@ -3,7 +3,6 @@ import { LRUCache } from 'lru-cache'
|
||||
|
||||
import { User } from '@oodikone/shared/models/user'
|
||||
import { DetailedProgrammeRights, Role } from '@oodikone/shared/types'
|
||||
import { serviceProvider } from '../config'
|
||||
import { roles } from '../config/roles'
|
||||
import { sequelizeUser } from '../database/connection'
|
||||
import { UserModel } from '../models/user'
|
||||
@@ -11,13 +10,12 @@ import { ExpandedUser, FormattedUser, IamAccess } from '../types'
|
||||
|
||||
import { createLocaleComparator, getFullStudyProgrammeRights, hasFullAccessToStudentData } from '../util'
|
||||
import * as jami from '../util/jami'
|
||||
import mami from '../util/mami'
|
||||
import { sendNotificationAboutNewUser } from './mailService'
|
||||
import { getSisuAuthData, personSearchQuery, getGraphqlData } from './oriProvider'
|
||||
import { getStudentnumbersByElementdetails } from './students'
|
||||
import { checkStudyGuidanceGroupsAccess, getAllStudentsUserHasInGroups } from './studyGuidanceGroups'
|
||||
|
||||
const userAccessUtils = serviceProvider === 'toska' ? jami : mami
|
||||
const userAccessUtils = jami
|
||||
const { getAllUserAccess, getUserIams, getUserIamAccess } = userAccessUtils
|
||||
|
||||
const courseStatisticsGroup = 'grp-oodikone-basic-users'
|
||||
@@ -68,7 +66,7 @@ export const updateUser = async (username: string, fields: Partial<User>) => {
|
||||
userDataCache.delete(username)
|
||||
}
|
||||
|
||||
const getIamBasedRights = (iamAccess: IamAccess): DetailedProgrammeRights[] => {
|
||||
const getIamBasedRights = (iamAccess: IamAccess | undefined): DetailedProgrammeRights[] => {
|
||||
if (!iamAccess) {
|
||||
return []
|
||||
}
|
||||
@@ -89,8 +87,8 @@ const getUserProgrammesRights = (userProgrammes: string[]): DetailedProgrammeRig
|
||||
}
|
||||
|
||||
const getStudyProgrammeRights = (
|
||||
iamAccess: IamAccess,
|
||||
specialGroup: Record<string, boolean>,
|
||||
iamAccess: IamAccess | undefined,
|
||||
specialGroup: Record<string, boolean> | undefined,
|
||||
userProgrammes: string[]
|
||||
): DetailedProgrammeRights[] => {
|
||||
const hasFullSisuAccess = specialGroup?.fullSisuAccess
|
||||
@@ -233,14 +231,6 @@ export const getMockedUser = async ({ userToMock, mockedBy }: { userToMock: stri
|
||||
return mockedUser
|
||||
}
|
||||
|
||||
export const getMockedUserFd = async ({ userToMock, mockedBy }: { userToMock: string; mockedBy: string }) => {
|
||||
const mockedByFromDb = (await UserModel.findOne({ where: { username: mockedBy } }))?.toJSON()
|
||||
if (!mockedByFromDb) {
|
||||
return null
|
||||
}
|
||||
return await getMockedUser({ userToMock, mockedBy })
|
||||
}
|
||||
|
||||
export const getUserToska = async ({
|
||||
username,
|
||||
name,
|
||||
@@ -283,28 +273,6 @@ export const getUserToska = async ({
|
||||
return user
|
||||
}
|
||||
|
||||
export const getUserFd = async ({ username }: { username: string }) => {
|
||||
if (userDataCache.has(username)) {
|
||||
return userDataCache.get(username) as FormattedUser
|
||||
}
|
||||
|
||||
const userFromDbOrm = await UserModel.findOne({ where: { username } })
|
||||
if (!userFromDbOrm) {
|
||||
return null
|
||||
}
|
||||
|
||||
userFromDbOrm.lastLogin = new Date()
|
||||
await userFromDbOrm.save()
|
||||
|
||||
const userFromDb = userFromDbOrm.toJSON()
|
||||
|
||||
const detailedProgrammeRights = getStudyProgrammeRights({}, {}, userFromDb.programmeRights)
|
||||
const user = await formatUser({ ...userFromDb, iamGroups: [], detailedProgrammeRights })
|
||||
|
||||
userDataCache.set(username, user)
|
||||
return user
|
||||
}
|
||||
|
||||
export const addNewUser = async user => {
|
||||
const name = user.first_name.concat(' ', user.last_name)
|
||||
try {
|
||||
|
||||
@@ -1,37 +1,14 @@
|
||||
import axios from 'axios'
|
||||
|
||||
import { importerDbApiPassword, importerDbApiUser, importerToken, importerUrl, serviceProvider } from '../config'
|
||||
import { importerToken, importerUrl } from '../config'
|
||||
import logger from './logger'
|
||||
|
||||
const createBasicAuthHeader = () => {
|
||||
const auth = `${importerDbApiUser}:${importerDbApiPassword}`
|
||||
const token = Buffer.from(auth).toString('base64')
|
||||
return {
|
||||
Authorization: `Basic ${token}`,
|
||||
}
|
||||
}
|
||||
|
||||
const toskaImporterClient = axios.create({
|
||||
headers: { token: importerToken },
|
||||
baseURL: importerUrl,
|
||||
timeout: 10000,
|
||||
})
|
||||
|
||||
const fdImporterClient = axios.create({
|
||||
headers: createBasicAuthHeader(),
|
||||
baseURL: importerUrl,
|
||||
})
|
||||
|
||||
const missingBasicAuthCredentials = !importerDbApiUser || !importerDbApiPassword
|
||||
|
||||
const getFdImporterClient = () => {
|
||||
if (missingBasicAuthCredentials) {
|
||||
logger.error("Basic auth credentials not set, can't return client!")
|
||||
return null
|
||||
}
|
||||
return fdImporterClient
|
||||
}
|
||||
|
||||
const getToskaImporterClient = () => {
|
||||
if (!importerToken) {
|
||||
logger.error("Importer token not set, can't return client!")
|
||||
@@ -40,4 +17,4 @@ const getToskaImporterClient = () => {
|
||||
return toskaImporterClient
|
||||
}
|
||||
|
||||
export const getImporterClient = serviceProvider === 'toska' ? getToskaImporterClient : getFdImporterClient
|
||||
export const getImporterClient = getToskaImporterClient
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as Sentry from '@sentry/node'
|
||||
import axios from 'axios'
|
||||
|
||||
import { importerToken, isStaging, jamiUrl, serviceProvider } from '../config'
|
||||
import { importerToken, isStaging, jamiUrl } from '../config'
|
||||
import { IamAccess } from '../types'
|
||||
import logger from './logger'
|
||||
|
||||
@@ -69,14 +69,12 @@ export const getAllUserAccess = async (userIds: string[]) => {
|
||||
return data as Access[]
|
||||
}
|
||||
|
||||
if (serviceProvider === 'toska') {
|
||||
jamiClient
|
||||
.get('/ping', { timeout: 4000 })
|
||||
.then(() => {
|
||||
logger.info('JAMI connected')
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error('JAMI not responding :(', { error })
|
||||
logger.info('Are you sure you are using the latest JAMI image?')
|
||||
})
|
||||
}
|
||||
jamiClient
|
||||
.get('/ping', { timeout: 4000 })
|
||||
.then(() => {
|
||||
logger.info('JAMI connected')
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error('JAMI not responding :(', { error })
|
||||
logger.info('Are you sure you are using the latest JAMI image?')
|
||||
})
|
||||
|
||||
@@ -3,29 +3,27 @@ import * as winston from 'winston'
|
||||
import { WinstonGelfTransporter } from 'winston-gelf-transporter'
|
||||
import LokiTransport from 'winston-loki'
|
||||
|
||||
import { isProduction, serviceProvider } from '../config'
|
||||
import { isProduction } from '../config'
|
||||
|
||||
const transports: winston.transport[] = [new winston.transports.Console()]
|
||||
|
||||
if (serviceProvider !== 'fd') {
|
||||
transports.push(
|
||||
new LokiTransport({
|
||||
host: 'http://loki-svc.toska-lokki.svc.cluster.local:3100',
|
||||
labels: { app: 'oodikone', environment: process.env.NODE_ENV ?? 'production' },
|
||||
}),
|
||||
new WinstonGelfTransporter({
|
||||
handleExceptions: true,
|
||||
host: 'svm-116.cs.helsinki.fi',
|
||||
port: 9503,
|
||||
protocol: 'udp',
|
||||
hostName: os.hostname(),
|
||||
additional: {
|
||||
app: 'oodikone',
|
||||
environment: 'production',
|
||||
},
|
||||
}) as winston.transport
|
||||
)
|
||||
}
|
||||
transports.push(
|
||||
new LokiTransport({
|
||||
host: 'http://loki-svc.toska-lokki.svc.cluster.local:3100',
|
||||
labels: { app: 'oodikone', environment: process.env.NODE_ENV ?? 'production' },
|
||||
}),
|
||||
new WinstonGelfTransporter({
|
||||
handleExceptions: true,
|
||||
host: 'svm-116.cs.helsinki.fi',
|
||||
port: 9503,
|
||||
protocol: 'udp',
|
||||
hostName: os.hostname(),
|
||||
additional: {
|
||||
app: 'oodikone',
|
||||
environment: 'production',
|
||||
},
|
||||
}) as winston.transport
|
||||
)
|
||||
|
||||
const { colorize, combine, timestamp, printf } = winston.format
|
||||
const logger = winston.createLogger({
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
const getUserIamAccess = async (_, __, ___) => {
|
||||
return {}
|
||||
}
|
||||
|
||||
const getUserIams = async _ => {
|
||||
return []
|
||||
}
|
||||
|
||||
const getAllUserAccess = async _ => {
|
||||
return []
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getUserIamAccess,
|
||||
getUserIams,
|
||||
getAllUserAccess,
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{ "sisUrl": "https://sis-qa.funidata.fi" }
|
||||
@@ -4,7 +4,6 @@ import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'
|
||||
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'
|
||||
import { maxBy, orderBy, range } from 'lodash-es'
|
||||
|
||||
import { serviceProvider } from '@/conf'
|
||||
import { SemestersData } from '@/redux/semesters'
|
||||
import type { Absence } from '@/types/students'
|
||||
import type { SISStudyRightElement } from '@oodikone/shared/models'
|
||||
@@ -437,13 +436,6 @@ export const getEnrollmentTypeTextForExcel = (type: number, statutoryAbsence?: b
|
||||
return 'No study right'
|
||||
}
|
||||
|
||||
export const isDefaultServiceProvider = () => {
|
||||
if (!serviceProvider) {
|
||||
return false
|
||||
}
|
||||
return serviceProvider === 'toska'
|
||||
}
|
||||
|
||||
export const formatContent = (content: string) => content.replace(/\n +/g, '\n')
|
||||
|
||||
export const filterInternalReleases = (release: Release) => !release.title.startsWith('Internal:')
|
||||
|
||||
@@ -3,7 +3,6 @@ import Divider from '@mui/material/Divider'
|
||||
import Stack from '@mui/material/Stack'
|
||||
import Typography from '@mui/material/Typography'
|
||||
|
||||
import { isDefaultServiceProvider } from '@/common'
|
||||
import { ExternalLink } from '@/components/common/ExternalLink'
|
||||
import { ToskaLogo } from '@/components/Footer/ToskaLogo'
|
||||
import { builtAt, dataProtectionUrl, licenseUrl, sentryRelease, sourceCodeUrl } from '@/conf'
|
||||
@@ -36,7 +35,7 @@ export const Footer = () => {
|
||||
<Stack direction="row" gap={3}>
|
||||
<Stack>
|
||||
<Typography variant="subtitle1">Oodikone</Typography>
|
||||
{isDefaultServiceProvider() && <ExternalLink href={dataProtectionUrl} text="Data protection" />}
|
||||
<ExternalLink href={dataProtectionUrl} text="Data protection" />
|
||||
<ExternalLink href={sourceCodeUrl} text="Source code" />
|
||||
<ExternalLink href={licenseUrl} text="License" />
|
||||
</Stack>
|
||||
|
||||
@@ -5,7 +5,6 @@ import Typography from '@mui/material/Typography'
|
||||
import { useState } from 'react'
|
||||
import { useLocation } from 'react-router'
|
||||
|
||||
import { isDefaultServiceProvider } from '@/common'
|
||||
import { Link } from '@/components/common/Link'
|
||||
import { languageCenterViewEnabled } from '@/conf'
|
||||
import { useGetAuthorizedUserQuery } from '@/redux/auth'
|
||||
@@ -26,11 +25,7 @@ export const NavigationButton = ({ item }: { item: NavigationItem }) => {
|
||||
return true
|
||||
}
|
||||
|
||||
if (
|
||||
checkUserAccess(['admin', 'openUniSearch'], roles) &&
|
||||
subItemKey === 'openUniSearch' &&
|
||||
isDefaultServiceProvider()
|
||||
) {
|
||||
if (checkUserAccess(['admin', 'openUniSearch'], roles) && subItemKey === 'openUniSearch') {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import Toolbar from '@mui/material/Toolbar'
|
||||
import { useState, useEffect, useMemo } from 'react'
|
||||
import { useLocation } from 'react-router'
|
||||
|
||||
import { isDefaultServiceProvider } from '@/common'
|
||||
import { Link } from '@/components/common/Link'
|
||||
import { useGetAuthorizedUserQuery } from '@/redux/auth'
|
||||
import { checkUserAccess, getFullStudyProgrammeRights, hasFullAccessToTeacherData } from '@/util/access'
|
||||
@@ -48,8 +47,6 @@ export const NavigationBar = () => {
|
||||
if (key === 'faculty' && !checkUserAccess(['admin', 'fullSisuAccess', 'facultyStatistics'], roles))
|
||||
return false
|
||||
|
||||
if (key === 'feedback' && !isDefaultServiceProvider()) return false
|
||||
|
||||
if (key === 'admin' && !isAdmin) return false
|
||||
|
||||
if (
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Suspense } from 'react'
|
||||
import { Navigate, Route, Routes as RouterRoutes } from 'react-router'
|
||||
|
||||
import { isDefaultServiceProvider } from '@/common'
|
||||
import { CoursePopulation } from '@/components/CoursePopulation'
|
||||
import { CustomOpenUniPopulation } from '@/components/CustomOpenUniPopulation'
|
||||
import { CustomPopulation } from '@/components/CustomPopulation'
|
||||
@@ -36,12 +35,12 @@ export const Routes = () => (
|
||||
<Route element={<Changelog />} path="/changelog" />
|
||||
<Route element={<CompletedCourses />} path="/completedcoursessearch" />
|
||||
<Route element={<University />} path="/university" />
|
||||
{isDefaultServiceProvider() && <Route element={<Feedback />} path="/feedback" />}
|
||||
<Route element={<Feedback />} path="/feedback" />
|
||||
|
||||
<Route element={<ProtectedRoute requireUserHasRights requiredRoles={['fullSisuAccess']} />}>
|
||||
<Route element={<PopulationStatistics />} path="/populations" />
|
||||
<Route element={<StudyProgramme />} path="/study-programme/:studyProgrammeId?" />
|
||||
{isDefaultServiceProvider() && <Route element={<CoursePopulation />} path="/coursepopulation" />}
|
||||
<Route element={<CoursePopulation />} path="/coursepopulation" />
|
||||
</Route>
|
||||
|
||||
<Route element={<ProtectedRoute requiredRoles={['admin']} />}>
|
||||
@@ -79,11 +78,9 @@ export const Routes = () => (
|
||||
<Route element={<CloseToGraduation />} path="/close-to-graduation" />
|
||||
</Route>
|
||||
|
||||
{isDefaultServiceProvider() && (
|
||||
<Route element={<ProtectedRoute requiredRoles={['openUniSearch']} />}>
|
||||
<Route element={<CustomOpenUniPopulation />} path="/openunipopulation" />
|
||||
</Route>
|
||||
)}
|
||||
<Route element={<ProtectedRoute requiredRoles={['openUniSearch']} />}>
|
||||
<Route element={<CustomOpenUniPopulation />} path="/openunipopulation" />
|
||||
</Route>
|
||||
|
||||
{/* Access control inside ProtectedRoute */}
|
||||
<Route element={<ProtectedRoute />}>
|
||||
|
||||
@@ -2,7 +2,7 @@ import Typography from '@mui/material/Typography'
|
||||
import { createColumnHelper } from '@tanstack/react-table'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import { calculatePercentage, isDefaultServiceProvider } from '@/common'
|
||||
import { calculatePercentage } from '@/common'
|
||||
import { Link } from '@/components/common/Link'
|
||||
import { OodiTable } from '@/components/OodiTable'
|
||||
import { OodiTableExcelExport } from '@/components/OodiTable/excelExport'
|
||||
@@ -42,11 +42,9 @@ export const TeacherStatisticsTable = ({ statistics, variant }) => {
|
||||
cell: ({ row }) => (
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', gap: '0.5em' }}>
|
||||
{row.original.name}
|
||||
{isDefaultServiceProvider() && (
|
||||
<Link target="_blank" to={`/teachers/${row.original.id}`}>
|
||||
<NorthEastIcon />
|
||||
</Link>
|
||||
)}
|
||||
<Link target="_blank" to={`/teachers/${row.original.id}`}>
|
||||
<NorthEastIcon />
|
||||
</Link>
|
||||
</div>
|
||||
),
|
||||
})
|
||||
|
||||
@@ -3,13 +3,11 @@ import Stack from '@mui/material/Stack'
|
||||
import Typography from '@mui/material/Typography'
|
||||
|
||||
import { Link } from '@/components/common/Link'
|
||||
import { useSisUrl } from '@/hooks/useSisUrl'
|
||||
import { sisUrl } from '@/conf'
|
||||
import { PersonIcon } from '@/theme'
|
||||
import { ExternalLink } from './ExternalLink'
|
||||
|
||||
export const StudentInfoItem = ({ sisPersonId, studentNumber }: { sisPersonId: string; studentNumber: string }) => {
|
||||
const usableSisUrl = useSisUrl()
|
||||
|
||||
return (
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography component="span" sx={{ alignContent: 'center', padding: '0 0.25em' }} variant="body2">
|
||||
@@ -18,7 +16,7 @@ export const StudentInfoItem = ({ sisPersonId, studentNumber }: { sisPersonId: s
|
||||
<IconButton component={Link} target="_blank" to={`/students/${studentNumber}`}>
|
||||
<PersonIcon color="primary" fontSize="small" />
|
||||
</IconButton>
|
||||
<ExternalLink href={`${usableSisUrl}/tutor/role/staff/student/${sisPersonId}/basic/basic-info`} text="Sisu" />
|
||||
<ExternalLink href={`${sisUrl}/tutor/role/staff/student/${sisPersonId}/basic/basic-info`} text="Sisu" />
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -22,9 +22,6 @@ export const sourceCodeUrl = 'https://github.com/UniversityOfHelsinkiCS/oodikone
|
||||
export const licenseUrl = `${sourceCodeUrl}/blob/master/LICENSE`
|
||||
export const dataProtectionUrl = `${sourceCodeUrl}/blob/master/documentation/tietosuoja.md`
|
||||
|
||||
// Service provider depending this hiding some not needed features default value toska
|
||||
export const serviceProvider = process.env.REACT_APP_SERVICE_PROVIDER?.toLowerCase() ?? 'toska'
|
||||
|
||||
// Variable that can be used to disable the language center view, by default the view is enabled
|
||||
export const languageCenterViewEnabled = !process.env.REACT_APP_LANGUAGE_CENTER_VIEW_ENABLED
|
||||
? true
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { sisUrl, serviceProvider } from '@/conf'
|
||||
|
||||
export const useSisUrl = () => {
|
||||
const [runtimeConfiguredSisUrl, setRuntimeConfiguredSisUrl] = useState(sisUrl)
|
||||
|
||||
useEffect(() => {
|
||||
if (serviceProvider === 'fd')
|
||||
fetch('/frontend-config.json')
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Json response was not ok')
|
||||
}
|
||||
return response.json()
|
||||
})
|
||||
.then(data => {
|
||||
if (data.sisUrl) setRuntimeConfiguredSisUrl(data.sisUrl)
|
||||
})
|
||||
.catch(error => {
|
||||
throw new Error(error)
|
||||
})
|
||||
}, [])
|
||||
|
||||
return runtimeConfiguredSisUrl
|
||||
}
|
||||
+1
-2
@@ -2,7 +2,6 @@ import IconButton from '@mui/material/IconButton'
|
||||
import Stack from '@mui/material/Stack'
|
||||
import Typography from '@mui/material/Typography'
|
||||
|
||||
import { isDefaultServiceProvider } from '@/common'
|
||||
import { Link } from '@/components/common/Link'
|
||||
import { NorthEastIcon } from '@/theme'
|
||||
|
||||
@@ -23,7 +22,7 @@ export const TimeCell = ({
|
||||
{name}
|
||||
{name === 'Total' && !userHasAccessToAllStats && <strong> *</strong>}
|
||||
</Typography>
|
||||
{name !== 'Total' && userHasAccessToAllStats && isDefaultServiceProvider() ? (
|
||||
{name !== 'Total' && userHasAccessToAllStats ? (
|
||||
<IconButton
|
||||
color="primary"
|
||||
component={Link}
|
||||
|
||||
@@ -7,7 +7,6 @@ import { difference, flatten, max, min, pickBy, uniq } from 'lodash-es'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useLocation, useNavigate } from 'react-router'
|
||||
|
||||
import { isDefaultServiceProvider } from '@/common'
|
||||
import { ProgrammeDropdown } from '@/components/CourseStatistics/ProgrammeDropdown'
|
||||
import { useLanguage } from '@/components/LanguagePicker/useLanguage'
|
||||
import { Section } from '@/components/Section'
|
||||
@@ -435,9 +434,6 @@ export const SingleCourseStats = ({
|
||||
if (!userHasAccessToAllStats) {
|
||||
return null
|
||||
}
|
||||
if (!isDefaultServiceProvider()) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<Button disabled={disabled} onClick={showPopulation} variant="contained">
|
||||
Show population
|
||||
|
||||
@@ -4,7 +4,7 @@ import Divider from '@mui/material/Divider'
|
||||
import Stack from '@mui/material/Stack'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import { filterInternalReleases, isDefaultServiceProvider } from '@/common'
|
||||
import { filterInternalReleases } from '@/common'
|
||||
import { Link } from '@/components/common/Link'
|
||||
import { PageLayout } from '@/components/common/PageLayout'
|
||||
import { PageTitle } from '@/components/common/PageTitle'
|
||||
@@ -53,7 +53,7 @@ export const FrontPage = () => {
|
||||
content: 'View detailed information for a given student',
|
||||
},
|
||||
{
|
||||
show: isDefaultServiceProvider(),
|
||||
show: true,
|
||||
title: 'Feedback',
|
||||
content: (
|
||||
<p>
|
||||
|
||||
@@ -8,8 +8,8 @@ import Typography from '@mui/material/Typography'
|
||||
import { callApi } from '@/apiConnection'
|
||||
import { ExternalLink } from '@/components/common/ExternalLink'
|
||||
import { useStudentNameVisibility } from '@/components/common/StudentNameVisibilityToggle'
|
||||
import { sisUrl } from '@/conf'
|
||||
import { DateFormat } from '@/constants/date'
|
||||
import { useSisUrl } from '@/hooks/useSisUrl'
|
||||
import { useGetAuthorizedUserQuery } from '@/redux/auth'
|
||||
import { RefreshIcon } from '@/theme'
|
||||
import { reformatDate } from '@/util/timeAndDate'
|
||||
@@ -17,7 +17,6 @@ import { StudentPageStudent } from '@oodikone/shared/types/studentData'
|
||||
import { EnrollmentAccordion } from './EnrollmentAccordion'
|
||||
|
||||
export const StudentInfoCard = ({ student }: { student: StudentPageStudent }) => {
|
||||
const usableSisUrl = useSisUrl()
|
||||
const { visible: showName } = useStudentNameVisibility()
|
||||
const { isAdmin } = useGetAuthorizedUserQuery()
|
||||
const name = showName ? `${student.name}, ` : ''
|
||||
@@ -42,7 +41,7 @@ export const StudentInfoCard = ({ student }: { student: StudentPageStudent }) =>
|
||||
</Typography>
|
||||
<ExternalLink
|
||||
cypress="sisu-link"
|
||||
href={`${usableSisUrl}/tutor/role/staff/student/${student.sisPersonId}/basic/basic-info`}
|
||||
href={`${sisUrl}/tutor/role/staff/student/${student.sisPersonId}/basic/basic-info`}
|
||||
text="Sisu"
|
||||
variant="h6"
|
||||
/>
|
||||
|
||||
@@ -4,7 +4,6 @@ import Typography from '@mui/material/Typography'
|
||||
|
||||
import { useState } from 'react'
|
||||
|
||||
import { isDefaultServiceProvider } from '@/common'
|
||||
import { studyProgrammeToolTips } from '@/common/InfoToolTips'
|
||||
import { LineGraph } from '@/components/common/LineGraph'
|
||||
import { MedianTimeBarChart } from '@/components/common/MedianTimeBarChart'
|
||||
@@ -149,7 +148,7 @@ export const BasicInformationTab = ({
|
||||
isLoading={creditsIsLoading}
|
||||
title="Credits produced by the degree programme"
|
||||
>
|
||||
{creditGraphStats && tableStats && isDefaultServiceProvider() ? (
|
||||
{creditGraphStats && tableStats ? (
|
||||
<Stack gap={2}>
|
||||
<StackedBarChart
|
||||
cypress="credits-produced-by-the-study-programme"
|
||||
|
||||
@@ -5,7 +5,6 @@ import Stack from '@mui/material/Stack'
|
||||
import { debounce } from 'lodash-es'
|
||||
import { useState } from 'react'
|
||||
|
||||
import { isDefaultServiceProvider } from '@/common'
|
||||
import { FilterOldProgrammesToggle } from '@/components/common/FilterOldProgrammesToggle'
|
||||
import { PageLayout } from '@/components/common/PageLayout'
|
||||
import { PageTitle } from '@/components/common/PageTitle'
|
||||
@@ -94,7 +93,7 @@ export const StudyProgrammeSelector = () => {
|
||||
progId: `${programme.progId} - ${secondProgramme[0]?.progId}`,
|
||||
})
|
||||
}
|
||||
if (isDefaultServiceProvider() && programme.code.startsWith('2_')) {
|
||||
if (programme.code.startsWith('2_')) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import Tabs from '@mui/material/Tabs'
|
||||
import { useState } from 'react'
|
||||
import { useParams } from 'react-router'
|
||||
|
||||
import { isDefaultServiceProvider } from '@/common'
|
||||
import { PageLayout } from '@/components/common/PageLayout'
|
||||
import { PageTitle } from '@/components/common/PageTitle'
|
||||
import { GetTextIn, useLanguage } from '@/components/LanguagePicker/useLanguage'
|
||||
@@ -114,7 +113,7 @@ export const StudyProgramme = () => {
|
||||
},
|
||||
]
|
||||
|
||||
if (otherTabsVisible && isDefaultServiceProvider()) {
|
||||
if (otherTabsVisible) {
|
||||
tabs.push({
|
||||
key: 'ProgrammeCoursesTab',
|
||||
label: 'Programme courses',
|
||||
|
||||
@@ -10,7 +10,6 @@ import Typography from '@mui/material/Typography'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import { callApi } from '@/apiConnection'
|
||||
import { isDefaultServiceProvider } from '@/common'
|
||||
import { updaterToolTips } from '@/common/InfoToolTips'
|
||||
import { ExternalLink } from '@/components/common/ExternalLink'
|
||||
import { PageLayout } from '@/components/common/PageLayout'
|
||||
@@ -70,11 +69,9 @@ export const Updater = () => {
|
||||
<PageLayout maxWidth="lg">
|
||||
<PageTitle title="Updater" />
|
||||
<Stack spacing={2}>
|
||||
{isDefaultServiceProvider() && (
|
||||
<Button color="error" onClick={() => setError(true)} variant="contained">
|
||||
Cause frontend crash
|
||||
</Button>
|
||||
)}
|
||||
<Button color="error" onClick={() => setError(true)} variant="contained">
|
||||
Cause frontend crash
|
||||
</Button>
|
||||
<Section
|
||||
infoBoxContent={updaterToolTips.updaterSection}
|
||||
title="Updater (data pulled from sis-importer-db and brought to sis-db)"
|
||||
|
||||
@@ -7,7 +7,6 @@ import TableContainer from '@mui/material/TableContainer'
|
||||
import TableHead from '@mui/material/TableHead'
|
||||
import TableRow from '@mui/material/TableRow'
|
||||
|
||||
import { isDefaultServiceProvider } from '@/common'
|
||||
import { Link } from '@/components/common/Link'
|
||||
import { MockButton } from '@/components/Users/MockButton'
|
||||
import { DateFormat } from '@/constants/date'
|
||||
@@ -27,7 +26,7 @@ export const InfoCard = ({ user }: { user: User }) => {
|
||||
buttons={
|
||||
<>
|
||||
{user.username !== currentUserName && <MockButton username={user.username} />}
|
||||
{isDefaultServiceProvider() && <NotifyButton userEmail={user.email} />}
|
||||
{<NotifyButton userEmail={user.email} />}
|
||||
</>
|
||||
}
|
||||
title={user.name}
|
||||
|
||||
@@ -7,7 +7,6 @@ import Stack from '@mui/material/Stack'
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import { isDefaultServiceProvider } from '@/common'
|
||||
import { useStatusNotification } from '@/components/StatusNotification/Context'
|
||||
import { RoleChip } from '@/components/Users/RoleChip'
|
||||
import { useGetRolesQuery, useModifyRolesMutation } from '@/redux/users'
|
||||
@@ -71,7 +70,7 @@ export const RolesCard = ({ user }: { user: User }) => {
|
||||
<Checkbox
|
||||
checked={selected.includes(role)}
|
||||
color="success"
|
||||
disabled={!editing || (!['admin', 'teachers'].includes(role) && isDefaultServiceProvider())}
|
||||
disabled={!editing || !['admin', 'teachers'].includes(role)}
|
||||
onChange={() => toggleRole(role)}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
@@ -14,7 +14,6 @@ import Typography from '@mui/material/Typography'
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import { isDefaultServiceProvider } from '@/common'
|
||||
import { userToolTips } from '@/common/InfoToolTips'
|
||||
import { FilterOldProgrammesToggle } from '@/components/common/FilterOldProgrammesToggle'
|
||||
import { InfoBox } from '@/components/InfoBox/InfoBoxWithTooltip'
|
||||
@@ -209,28 +208,26 @@ export const StudyProgrammeRightsCard = ({ user }: { user: User }) => {
|
||||
</Stack>
|
||||
</CardContent>
|
||||
|
||||
{isDefaultServiceProvider() && (
|
||||
<CardContent>
|
||||
<Stack alignItems="center" direction="row" gap={1}>
|
||||
<Typography component="h3" fontWeight="bold">
|
||||
Current IAM group based degree programme access rights
|
||||
</Typography>
|
||||
<InfoBox content={userToolTips.iamGroupBasedAccess} mini />
|
||||
</Stack>
|
||||
{currentIamAccessRights.length > 0 ? (
|
||||
currentIamAccessRights.map(({ code, name, limited }) => (
|
||||
<Stack direction="row" justifyContent="space-between" key={code}>
|
||||
<Typography>{`${name} ${code}`}</Typography>
|
||||
<Tooltip arrow placement="left" title={limited ? 'Limited rights' : 'Full rights'}>
|
||||
{limited ? <WarningIcon color="warning" /> : <CheckCircleIcon color="success" />}
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
))
|
||||
) : (
|
||||
<Typography color="text.secondary">No IAM based access rights</Typography>
|
||||
)}
|
||||
</CardContent>
|
||||
)}
|
||||
<CardContent>
|
||||
<Stack alignItems="center" direction="row" gap={1}>
|
||||
<Typography component="h3" fontWeight="bold">
|
||||
Current IAM group based degree programme access rights
|
||||
</Typography>
|
||||
<InfoBox content={userToolTips.iamGroupBasedAccess} mini />
|
||||
</Stack>
|
||||
{currentIamAccessRights.length > 0 ? (
|
||||
currentIamAccessRights.map(({ code, name, limited }) => (
|
||||
<Stack direction="row" justifyContent="space-between" key={code}>
|
||||
<Typography>{`${name} ${code}`}</Typography>
|
||||
<Tooltip arrow placement="left" title={limited ? 'Limited rights' : 'Full rights'}>
|
||||
{limited ? <WarningIcon color="warning" /> : <CheckCircleIcon color="success" />}
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
))
|
||||
) : (
|
||||
<Typography color="text.secondary">No IAM based access rights</Typography>
|
||||
)}
|
||||
</CardContent>
|
||||
</>
|
||||
)}
|
||||
</Card>
|
||||
|
||||
@@ -2,7 +2,6 @@ import Alert from '@mui/material/Alert'
|
||||
import Box from '@mui/material/Box'
|
||||
import Stack from '@mui/material/Stack'
|
||||
|
||||
import { isDefaultServiceProvider } from '@/common'
|
||||
import { PageLayout } from '@/components/common/PageLayout'
|
||||
import { Loading } from '@/components/Loading'
|
||||
import { useTitle } from '@/hooks/title'
|
||||
@@ -38,11 +37,9 @@ export const UserPage = ({ userId }: { userId: string }) => {
|
||||
<MissingIdAlert visible={!user.sisPersonId} />
|
||||
<InfoCard user={user} />
|
||||
<Box gap={2} sx={{ display: 'flex', flexDirection: { xs: 'column', md: 'row' } }}>
|
||||
{isDefaultServiceProvider() && (
|
||||
<Box flex={1}>
|
||||
<IamGroupsCard user={user} />
|
||||
</Box>
|
||||
)}
|
||||
<Box flex={1}>
|
||||
<IamGroupsCard user={user} />
|
||||
</Box>
|
||||
<Box flex={2}>
|
||||
<RolesCard user={user} />
|
||||
</Box>
|
||||
|
||||
@@ -5,7 +5,6 @@ import Stack from '@mui/material/Stack'
|
||||
import { MaterialReactTable, MRT_ColumnDef, useMaterialReactTable } from 'material-react-table'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
|
||||
import { isDefaultServiceProvider } from '@/common'
|
||||
import { Link } from '@/components/common/Link'
|
||||
import { useLanguage } from '@/components/LanguagePicker/useLanguage'
|
||||
import { MockButton } from '@/components/Users/MockButton'
|
||||
@@ -17,7 +16,6 @@ import { User } from '@/types/api/users'
|
||||
import { reformatDate } from '@/util/timeAndDate'
|
||||
import { DetailedProgrammeRights, Role } from '@oodikone/shared/types'
|
||||
import { CopyEmailAddressesButton } from './CopyEmailAddressesButton'
|
||||
import { DeleteButton } from './DeleteButton'
|
||||
import { StatusMessage } from './StatusMessage'
|
||||
|
||||
export const UsersTable = ({
|
||||
@@ -128,9 +126,6 @@ export const UsersTable = ({
|
||||
Cell: ({ row }) => (
|
||||
<Stack direction="row" gap={1}>
|
||||
<MockButton username={row.original.username} />
|
||||
{!isDefaultServiceProvider() && (
|
||||
<DeleteButton getAllUsersQuery={getAllUsersQuery} userId={row.original.id} />
|
||||
)}
|
||||
</Stack>
|
||||
),
|
||||
enableSorting: false,
|
||||
@@ -158,7 +153,7 @@ export const UsersTable = ({
|
||||
username: true,
|
||||
roles: true,
|
||||
programmeRights: true,
|
||||
iamGroups: isDefaultServiceProvider(),
|
||||
iamGroups: true,
|
||||
lastLogin: true,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -2,12 +2,10 @@ import Stack from '@mui/material/Stack'
|
||||
import { useEffect } from 'react'
|
||||
import { useParams } from 'react-router'
|
||||
|
||||
import { isDefaultServiceProvider } from '@/common'
|
||||
import { PageLayout } from '@/components/common/PageLayout'
|
||||
import { PageTitle } from '@/components/common/PageTitle'
|
||||
import { useTitle } from '@/hooks/title'
|
||||
import { useLazyGetAllUsersQuery } from '@/redux/users'
|
||||
import { NewUserSection } from './NewUserSection'
|
||||
import { UserPage } from './UserPage'
|
||||
import { UsersTable } from './UsersTable'
|
||||
|
||||
@@ -16,10 +14,6 @@ export const Users = () => {
|
||||
const { userid } = useParams()
|
||||
const [getAllUsersQuery, { data: users = [], isLoading, isError }] = useLazyGetAllUsersQuery()
|
||||
|
||||
const onAddUser = () => {
|
||||
void getAllUsersQuery()
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!userid) {
|
||||
void getAllUsersQuery()
|
||||
@@ -30,7 +24,6 @@ export const Users = () => {
|
||||
<PageLayout maxWidth="lg">
|
||||
<PageTitle title="Users" />
|
||||
<Stack gap={2}>
|
||||
{!userid && !isDefaultServiceProvider() && <NewUserSection onAddUser={onAddUser} />}
|
||||
{userid ? (
|
||||
<UserPage userId={userid} />
|
||||
) : (
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import { isDefaultServiceProvider } from '@/common'
|
||||
|
||||
export const getGraduationGraphTitle = (programmeCode: string, doCombo = false) => {
|
||||
if (!isDefaultServiceProvider()) return ''
|
||||
if (!programmeCode) return ''
|
||||
if (['MH30_001', 'MH30_003'].includes(programmeCode)) return 'Licenciate study right'
|
||||
if (doCombo && programmeCode === 'MH90_001') return 'Bachelor + licentiate study right'
|
||||
|
||||
@@ -21,6 +21,5 @@ module.exports.SIS_IMPORTER_DATABASE = process.env.SIS_IMPORTER_DATABASE
|
||||
module.exports.EXIT_AFTER_IMMEDIATES = process.env.EXIT_AFTER_IMMEDIATES === 'yes'
|
||||
module.exports.SCHEDULE_IMMEDIATE = process.env.SCHEDULE_IMMEDIATE ? process.env.SCHEDULE_IMMEDIATE.split(',') : []
|
||||
module.exports.SLACK_WEBHOOK = process.env.SLACK_WEBHOOK
|
||||
module.exports.serviceProvider = process.env.SERVICE_PROVIDER ? process.env.SERVICE_PROVIDER.toLowerCase() : ''
|
||||
module.exports.runningInCI = process.env.CI === 'true'
|
||||
module.exports.SENTRY_DSN = process.env.SENTRY_DSN
|
||||
|
||||
@@ -4,7 +4,7 @@ const { WinstonGelfTransporter } = require('winston-gelf-transporter')
|
||||
const LokiTransport = require('winston-loki')
|
||||
const Sentry = require('winston-transport-sentry-node').default
|
||||
|
||||
const { isDev, isStaging, isProduction, runningInCI, serviceProvider, SENTRY_DSN } = require('../config')
|
||||
const { isDev, isStaging, isProduction, runningInCI, SENTRY_DSN } = require('../config')
|
||||
|
||||
const { combine, timestamp, printf, colorize, uncolorize } = winston.format
|
||||
|
||||
@@ -38,16 +38,14 @@ transports.push(
|
||||
})
|
||||
)
|
||||
|
||||
if (serviceProvider !== 'fd') {
|
||||
transports.push(
|
||||
new LokiTransport({
|
||||
host: 'http://loki-svc.toska-lokki.svc.cluster.local:3100',
|
||||
labels: { app: 'updater-scheduler', environment: process.env.NODE_ENV ?? 'production' },
|
||||
})
|
||||
)
|
||||
}
|
||||
transports.push(
|
||||
new LokiTransport({
|
||||
host: 'http://loki-svc.toska-lokki.svc.cluster.local:3100',
|
||||
labels: { app: 'updater-scheduler', environment: process.env.NODE_ENV ?? 'production' },
|
||||
})
|
||||
)
|
||||
|
||||
if (isProduction && !isStaging && serviceProvider !== 'fd') {
|
||||
if (isProduction && !isStaging) {
|
||||
transports.push(
|
||||
new WinstonGelfTransporter({
|
||||
handleExceptions: true,
|
||||
|
||||
@@ -6,7 +6,6 @@ export const PURGE_LOCK = 'PURGE_LOCK'
|
||||
export const REDIS_HOST = process.env.REDIS_HOST || 'redis-updater'
|
||||
export const REDIS_PORT = process.env.REDIS_PORT || 6379
|
||||
export const rootOrgId = process.env.ROOT_ORG_ID || 'hy-university-root-id'
|
||||
export const serviceProvider = process.env.SERVICE_PROVIDER ? process.env.SERVICE_PROVIDER.toLowerCase() : ''
|
||||
export const runningInCI = process.env.CI === 'true'
|
||||
export const { SENTRY_DSN } = process.env
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { sortBy, flatten, uniqBy } from 'lodash-es'
|
||||
|
||||
import { serviceProvider } from '../config.js'
|
||||
import logger from '../utils/logger.js'
|
||||
import {
|
||||
educationTypeToExtentcode,
|
||||
@@ -177,24 +176,21 @@ export const creditMapper =
|
||||
let is_open = false
|
||||
|
||||
// check if ay code or ay study right or ay responsible organisation
|
||||
// if fd is not service provider
|
||||
if (serviceProvider !== 'fd') {
|
||||
if (course_code && !isModule(type)) {
|
||||
if (course_code.match(/^AY?(.+?)(?:en|fi|sv)?$/)) {
|
||||
if (course_code && !isModule(type)) {
|
||||
if (course_code.match(/^AY?(.+?)(?:en|fi|sv)?$/)) {
|
||||
is_open = true
|
||||
} else if (study_right_id !== null) {
|
||||
if (
|
||||
studyRightIdToEducationType[study_right_id] ===
|
||||
'urn:code:education-type:non-degree-education:open-university-studies'
|
||||
)
|
||||
is_open = true
|
||||
} else if (study_right_id !== null) {
|
||||
if (
|
||||
studyRightIdToEducationType[study_right_id] ===
|
||||
'urn:code:education-type:non-degree-education:open-university-studies'
|
||||
)
|
||||
is_open = true
|
||||
} else if (
|
||||
organisations
|
||||
.filter(({ roleUrn }) => roleUrn === 'urn:code:organisation-role:responsible-organisation')
|
||||
.some(org => org.organisationid === 'hy-org-48645785')
|
||||
) {
|
||||
is_open = true
|
||||
}
|
||||
} else if (
|
||||
organisations
|
||||
.filter(({ roleUrn }) => roleUrn === 'urn:code:organisation-role:responsible-organisation')
|
||||
.some(org => org.organisationid === 'hy-org-48645785')
|
||||
) {
|
||||
is_open = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { serviceProvider } from '../../config.js'
|
||||
|
||||
const anyModule = rule => ({ id: rule.localId, name: 'Any module' })
|
||||
const anyCourse = rule => ({ id: rule.localId, name: 'Any course' })
|
||||
const unknownRule = rule => ({ type: rule.type, fact: 'Unhandled rule' })
|
||||
@@ -75,7 +73,7 @@ export class ModuleResolver {
|
||||
const children = []
|
||||
|
||||
for (const mod of modules) {
|
||||
if (serviceProvider !== 'fd' && mod.code?.startsWith('KK-')) continue
|
||||
if (mod.code?.startsWith('KK-')) continue
|
||||
let result = this.moduleCache[mod.id]
|
||||
if (!result) {
|
||||
result = await this.resolveSingleModule(mod)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { flatten, sortBy, uniqBy } from 'lodash-es'
|
||||
import { Op } from 'sequelize'
|
||||
import { rootOrgId, serviceProvider } from '../../config.js'
|
||||
import { rootOrgId } from '../../config.js'
|
||||
import { dbConnections } from '../../db/connection.js'
|
||||
import { selectFromByIds, bulkCreate, selectOneById } from '../../db/index.js'
|
||||
import { Course, Teacher, Credit, CreditTeacher, CourseProvider } from '../../db/models/index.js'
|
||||
@@ -133,28 +133,24 @@ export const updateAttainments = async (
|
||||
|
||||
if (!customAttainmentTypes.includes(att.type)) return att
|
||||
let courseUnit
|
||||
if (serviceProvider === 'fd') {
|
||||
courseUnit = courses.find(course => course.id === att.course_unit_id)
|
||||
} else {
|
||||
const courseUnits = courses.filter(course => course.code === attIdToCourseCode[att.id])
|
||||
const courseUnits = courses.filter(course => course.code === attIdToCourseCode[att.id])
|
||||
|
||||
const isAfterStartAndBeforeEnd = (startDate, endDate, date) => {
|
||||
const dateToCompare = new Date(date)
|
||||
return new Date(startDate) <= dateToCompare && (!endDate || dateToCompare < new Date(endDate))
|
||||
}
|
||||
const isAfterStartAndBeforeEnd = (startDate, endDate, date) => {
|
||||
const dateToCompare = new Date(date)
|
||||
return new Date(startDate) <= dateToCompare && (!endDate || dateToCompare < new Date(endDate))
|
||||
}
|
||||
|
||||
courseUnit = courseUnits.find(({ validity_period }) =>
|
||||
isAfterStartAndBeforeEnd(validity_period.startDate, validity_period.endDate, att.attainment_date)
|
||||
)
|
||||
|
||||
// Sometimes registrations are fakd, see attainment hy-opinto-141561630.
|
||||
// The attainmentdate is outside of all courses, yet should be mapped.
|
||||
// Try to catch suitable courseUnit for this purpose
|
||||
if (!courseUnit) {
|
||||
courseUnit = courseUnits.find(({ validity_period }) =>
|
||||
isAfterStartAndBeforeEnd(validity_period.startDate, validity_period.endDate, att.attainment_date)
|
||||
isAfterStartAndBeforeEnd(validity_period.startDate, validity_period.endDate, att.registration_date)
|
||||
)
|
||||
|
||||
// Sometimes registrations are fakd, see attainment hy-opinto-141561630.
|
||||
// The attainmentdate is outside of all courses, yet should be mapped.
|
||||
// Try to catch suitable courseUnit for this purpose
|
||||
if (!courseUnit) {
|
||||
courseUnit = courseUnits.find(({ validity_period }) =>
|
||||
isAfterStartAndBeforeEnd(validity_period.startDate, validity_period.endDate, att.registration_date)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
let courseProvider
|
||||
@@ -163,11 +159,17 @@ export const updateAttainments = async (
|
||||
// If there's no suitable courseunit, there isn't courseunit available at all.
|
||||
// --> Course should be created, if it doesn't exist in sis db
|
||||
if (!courseUnit) {
|
||||
if (serviceProvider === 'fd') {
|
||||
const parsedCourseCode = attIdToCourseCode[att.id]
|
||||
|
||||
// see if course exists
|
||||
course = await Course.findOne({ where: { code: parsedCourseCode, id: parsedCourseCode } })
|
||||
|
||||
// If course doesn't exist, create it
|
||||
if (!course) {
|
||||
courseUnit = {
|
||||
id: att.id,
|
||||
id: parsedCourseCode,
|
||||
name: att.name,
|
||||
code: att.code,
|
||||
code: parsedCourseCode,
|
||||
is_study_module: isModule(att.type),
|
||||
coursetypecode: att.study_level_urn,
|
||||
max_attainment_date: att.attainment_date,
|
||||
@@ -175,42 +177,16 @@ export const updateAttainments = async (
|
||||
substitutions: [],
|
||||
course_unit_type: att.course_unit_type_urn,
|
||||
}
|
||||
coursesToBeCreated.set(att.id, courseUnit)
|
||||
|
||||
coursesToBeCreated.set(parsedCourseCode, courseUnit)
|
||||
courseProvider = await CourseProvider.findOne({
|
||||
where: {
|
||||
coursecode: att.id,
|
||||
coursecode: parsedCourseCode,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
const parsedCourseCode = attIdToCourseCode[att.id]
|
||||
|
||||
// see if course exists
|
||||
course = await Course.findOne({ where: { code: parsedCourseCode, id: parsedCourseCode } })
|
||||
|
||||
// If course doesn't exist, create it
|
||||
if (!course) {
|
||||
courseUnit = {
|
||||
id: parsedCourseCode,
|
||||
name: att.name,
|
||||
code: parsedCourseCode,
|
||||
is_study_module: isModule(att.type),
|
||||
coursetypecode: att.study_level_urn,
|
||||
max_attainment_date: att.attainment_date,
|
||||
min_attainment_date: att.attainment_date,
|
||||
substitutions: [],
|
||||
course_unit_type: att.course_unit_type_urn,
|
||||
}
|
||||
|
||||
coursesToBeCreated.set(parsedCourseCode, courseUnit)
|
||||
courseProvider = await CourseProvider.findOne({
|
||||
where: {
|
||||
coursecode: parsedCourseCode,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const courseIdToUse = serviceProvider === 'fd' ? att.id : attIdToCourseCode[att.id]
|
||||
const courseIdToUse = attIdToCourseCode[att.id]
|
||||
|
||||
// If there's no courseprovider, try to create course provider
|
||||
if (!courseProvider) {
|
||||
@@ -227,9 +203,7 @@ export const updateAttainments = async (
|
||||
}
|
||||
}
|
||||
|
||||
if (serviceProvider !== 'fd') {
|
||||
courseUnit = course || { id: courseIdToUse, code: courseIdToUse }
|
||||
}
|
||||
courseUnit = course || { id: courseIdToUse, code: courseIdToUse }
|
||||
courseUnit.group_id = courseUnit.id
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { WinstonGelfTransporter } from 'winston-gelf-transporter'
|
||||
import LokiTransport from 'winston-loki'
|
||||
import WinstonSentry from 'winston-transport-sentry-node'
|
||||
|
||||
import { isDev, isStaging, isProduction, runningInCI, serviceProvider, SENTRY_DSN } from '../config.js'
|
||||
import { isDev, isStaging, isProduction, runningInCI, SENTRY_DSN } from '../config.js'
|
||||
|
||||
const Sentry = WinstonSentry.default
|
||||
|
||||
@@ -40,16 +40,14 @@ transports.push(
|
||||
})
|
||||
)
|
||||
|
||||
if (serviceProvider !== 'fd') {
|
||||
transports.push(
|
||||
new LokiTransport({
|
||||
host: 'http://loki-svc.toska-lokki.svc.cluster.local:3100',
|
||||
labels: { app: 'updater-worker', environment: process.env.NODE_ENV ?? 'production' },
|
||||
})
|
||||
)
|
||||
}
|
||||
transports.push(
|
||||
new LokiTransport({
|
||||
host: 'http://loki-svc.toska-lokki.svc.cluster.local:3100',
|
||||
labels: { app: 'updater-worker', environment: process.env.NODE_ENV ?? 'production' },
|
||||
})
|
||||
)
|
||||
|
||||
if (isProduction && !isStaging && serviceProvider !== 'fd') {
|
||||
if (isProduction && !isStaging) {
|
||||
transports.push(
|
||||
new WinstonGelfTransporter({
|
||||
handleExceptions: true,
|
||||
|
||||
Reference in New Issue
Block a user