|
| 1 | +import { |
| 2 | + isSuperAdminIam, |
| 3 | + isAdminIam, |
| 4 | + isOpenUniIam, |
| 5 | + isHyOneIam, |
| 6 | + isJoryIam, |
| 7 | + isKosuIam, |
| 8 | + isUniversityWideIam, |
| 9 | + isDoctoralIam, |
| 10 | + iamToOrganisationCode, |
| 11 | + isEmployeeIam, |
| 12 | + iamToDoctoralSchool, |
| 13 | + kosuIamToFaculties, |
| 14 | + opetusVaradekaani, |
| 15 | + isStudyLeaderGroup, |
| 16 | + isKatselmusViewer, |
| 17 | + dekaaniIamToFaculty |
| 18 | +} from './IAMConfig' |
| 19 | +import { FACULTIES } from '../organisation/faculties' |
| 20 | +import { mapToDegreeCode } from './common' |
| 21 | +import { OrganisationAccess } from '../types' |
| 22 | +import { Programme } from '../organisation/types' |
| 23 | + |
| 24 | +type AccessSpecialGroupFunction = (hyGroups: string[]) => { access?: { [programmeCode: string]: OrganisationAccess }, specialGroup?: { [key: string]: boolean } } |
| 25 | + |
| 26 | +/** |
| 27 | + * Return given access to all programmes where predicate is true |
| 28 | + * (all if no predicate defined) |
| 29 | + */ |
| 30 | +const getAllProgrammeAccess = (accessLevel: OrganisationAccess, where?: (program: Programme) => boolean): { [key: string]: OrganisationAccess } => { |
| 31 | + const access = {} |
| 32 | + FACULTIES.forEach((faculty) => { |
| 33 | + faculty.programmes.forEach((program) => { |
| 34 | + if (where?.(program) === false) return |
| 35 | + access[program.key] = { ...accessLevel } |
| 36 | + }) |
| 37 | + }) |
| 38 | + return access |
| 39 | +} |
| 40 | + |
| 41 | +/** |
| 42 | + * Grant super-admin rights if the user has correct iams (eg. grp-toska) |
| 43 | + */ |
| 44 | +const getSuperAdmin: AccessSpecialGroupFunction = (hyGroups) => { |
| 45 | + const isToska = hyGroups.some(isSuperAdminIam) |
| 46 | + if (isToska) { |
| 47 | + return { specialGroup: { superAdmin: true } } |
| 48 | + } |
| 49 | + return {} |
| 50 | +} |
| 51 | + |
| 52 | +/** |
| 53 | + * NOT USED |
| 54 | + * Grant admin rights if the user has correct iams (eg. grp-ospa) |
| 55 | + * @returns admin special group |
| 56 | + */ |
| 57 | +const getAdmin: AccessSpecialGroupFunction = (hyGroups) => { |
| 58 | + const isOspa = hyGroups.some(isAdminIam) |
| 59 | + if (isOspa) { |
| 60 | + return { specialGroup: { admin: true } } |
| 61 | + } |
| 62 | + return {} |
| 63 | +} |
| 64 | + |
| 65 | +/** |
| 66 | + * Needed for Oodikone |
| 67 | + * Grant open uni rights if the user has correct iams (eg. hy-ypa-opa-dojo) |
| 68 | + * @returns openUni special group |
| 69 | + */ |
| 70 | +const getOpenUni: AccessSpecialGroupFunction = (hyGroups) => { |
| 71 | + const isOpenUni = hyGroups.some(isOpenUniIam) |
| 72 | + if (isOpenUni) { |
| 73 | + return { specialGroup: { openUni: true } } |
| 74 | + } |
| 75 | + return {} |
| 76 | +} |
| 77 | + |
| 78 | +/** |
| 79 | + * Needed for Oodikone |
| 80 | + * Grant teachers rights if the user has correct iams (eg. hy-one) |
| 81 | + * @returns hyOne special group |
| 82 | + */ |
| 83 | +const getHyOne: AccessSpecialGroupFunction = (hyGroups) => { |
| 84 | + const isHyIam = hyGroups.some(isHyOneIam) |
| 85 | + if (isHyIam) { |
| 86 | + return { specialGroup: { hyOne: true } } |
| 87 | + } |
| 88 | + return {} |
| 89 | +} |
| 90 | + |
| 91 | +/** |
| 92 | + * Needed for Oodikone |
| 93 | + * Grant jory special group if the user has jory iams (eg. hy-ttdk-tuk-jory) |
| 94 | + * @returns jory special group |
| 95 | + */ |
| 96 | +const getJory: AccessSpecialGroupFunction = (hyGroups) => { |
| 97 | + const isJory = hyGroups.some(isJoryIam) |
| 98 | + if (isJory) { |
| 99 | + return { specialGroup: { jory: true } } |
| 100 | + } |
| 101 | + return {} |
| 102 | +} |
| 103 | + |
| 104 | +/** |
| 105 | + * Needed for Oodikone |
| 106 | + * Grant kosu special group if the user has kosu iams (eg. hy-ypa-opa-kosu-kumpula) |
| 107 | + * @returns kosu special group |
| 108 | + */ |
| 109 | +const getKosu: AccessSpecialGroupFunction = (hyGroups) => { |
| 110 | + const isKosu = hyGroups.some(isKosuIam) |
| 111 | + if (isKosu) { |
| 112 | + return { specialGroup: { kosu: true } } |
| 113 | + } |
| 114 | + return {} |
| 115 | +} |
| 116 | + |
| 117 | +/** |
| 118 | + * Needed for Oodikone |
| 119 | + * Grant katselmusViewer special group, which means that the user can see oodikone's |
| 120 | + * evaluationoverview which is linked in tilannekuvalomake |
| 121 | + * @returns katselmusViewer special group |
| 122 | + */ |
| 123 | +const getKatselmusViewer: AccessSpecialGroupFunction = (hyGroups) => { |
| 124 | + const katselmusViewer = hyGroups.some(isKatselmusViewer) |
| 125 | + |
| 126 | + if (katselmusViewer) { |
| 127 | + return { specialGroup: { katselmusViewer: true } } |
| 128 | + } |
| 129 | + return {} |
| 130 | +} |
| 131 | + |
| 132 | +/** |
| 133 | + * Get special groups based on IAM-groups |
| 134 | + */ |
| 135 | +const getSpecialGroups: AccessSpecialGroupFunction = (hyGroups) => { |
| 136 | + let specialGroup = {} |
| 137 | + |
| 138 | + ;[ |
| 139 | + getAdmin, |
| 140 | + getSuperAdmin, |
| 141 | + getOpenUni, |
| 142 | + getHyOne, |
| 143 | + getJory, |
| 144 | + getKosu, |
| 145 | + getKatselmusViewer, |
| 146 | + ] |
| 147 | + .map((f) => f(hyGroups)) |
| 148 | + .forEach(({ specialGroup: newSpecialGroup }) => { |
| 149 | + specialGroup = { ...specialGroup, ...newSpecialGroup } |
| 150 | + }) |
| 151 | + |
| 152 | + return { specialGroup } |
| 153 | +} |
| 154 | + |
| 155 | +/** |
| 156 | + * Grant reading rights to all programmes if user has uni wide IAM (eg. hy-rehtoraatti) |
| 157 | + * @returns read access to ALL programmes |
| 158 | + */ |
| 159 | +const getUniversityReadingRights: AccessSpecialGroupFunction = (hyGroups) => { |
| 160 | + const hasUniversityReadingRights = hyGroups.some(isUniversityWideIam) |
| 161 | + if (!hasUniversityReadingRights) { |
| 162 | + return {} |
| 163 | + } |
| 164 | + |
| 165 | + const access = getAllProgrammeAccess({ |
| 166 | + read: true, |
| 167 | + write: false, |
| 168 | + admin: false, |
| 169 | + }) |
| 170 | + const specialGroup = { allProgrammes: true } |
| 171 | + |
| 172 | + return { access, specialGroup } |
| 173 | +} |
| 174 | + |
| 175 | +/** |
| 176 | + * Grant reading rights to programmes of faculties if user is kosu or dekaanaatti of some faculties |
| 177 | + */ |
| 178 | +const getFacultyReadingRights: AccessSpecialGroupFunction = (hyGroups) => { |
| 179 | + // faculty codes from kosu iam |
| 180 | + const facultyCodes = hyGroups |
| 181 | + .flatMap(kosuIamToFaculties) |
| 182 | + // faculty codes from dekanaatti iam |
| 183 | + .concat(hyGroups.map(dekaaniIamToFaculty)) |
| 184 | + .filter(Boolean) |
| 185 | + const access = {} |
| 186 | + facultyCodes.forEach((fc) => { |
| 187 | + const faculty = FACULTIES.find((faculty) => faculty.code === fc) |
| 188 | + const programmeCodes = faculty.programmes.map((p) => p.key) |
| 189 | + programmeCodes.forEach((code) => { |
| 190 | + access[code] = { read: true, write: false, admin: false } |
| 191 | + }) |
| 192 | + }) |
| 193 | + return { access, specialGroup: {} } |
| 194 | +} |
| 195 | + |
| 196 | +/** |
| 197 | + * Grant admin rights to faculty programmes if user is opetusvaradekaani of that faculty |
| 198 | + */ |
| 199 | +const getFacultyAdminRights: AccessSpecialGroupFunction = (hyGroups) => { |
| 200 | + if (!hyGroups.includes(opetusVaradekaani)) return {} |
| 201 | + const facultyCodes = hyGroups.map(dekaaniIamToFaculty).filter(Boolean) |
| 202 | + |
| 203 | + const access = {} |
| 204 | + facultyCodes.forEach((fc) => { |
| 205 | + const faculty = FACULTIES.find((faculty) => faculty.code === fc) |
| 206 | + const programmeCodes = faculty.programmes.map((p) => p.key) |
| 207 | + programmeCodes.forEach((code) => { |
| 208 | + access[code] = { read: true, write: true, admin: true } |
| 209 | + }) |
| 210 | + }) |
| 211 | + return { access, specialGroup: {} } |
| 212 | +} |
| 213 | + |
| 214 | +/** |
| 215 | + * Grant reading rights to all doctoral programmes if the user belongs to doctoral IAM |
| 216 | + * @returns read access to ALL doctoral programs |
| 217 | + */ |
| 218 | +const getDoctoralAccess: AccessSpecialGroupFunction = (hyGroups) => { |
| 219 | + const hasDoctoralReadingRights = hyGroups.some(isDoctoralIam) |
| 220 | + if (!hasDoctoralReadingRights) return {} |
| 221 | + const access = getAllProgrammeAccess( |
| 222 | + { read: true, write: false, admin: false }, |
| 223 | + (program) => program.level === 'doctoral', |
| 224 | + ) |
| 225 | + const specialGroup = { doctoral: true } |
| 226 | + |
| 227 | + return { access, specialGroup } |
| 228 | +} |
| 229 | + |
| 230 | +/** |
| 231 | + * Grants reading rights to all doctoral programmes that belong to user's |
| 232 | + * doctoral school IAMs |
| 233 | + * @returns read access to doctoral programs |
| 234 | + */ |
| 235 | +const getDoctoralSchoolAccess: AccessSpecialGroupFunction = (hyGroups) => { |
| 236 | + const doctoralProgrammeCodes = hyGroups.flatMap(iamToDoctoralSchool) |
| 237 | + const access = {} |
| 238 | + doctoralProgrammeCodes.forEach((code) => { |
| 239 | + if (!code) return |
| 240 | + access[code] = { read: true } |
| 241 | + }) |
| 242 | + return { access } |
| 243 | +} |
| 244 | + |
| 245 | +/** |
| 246 | + * Grant admin access if the user belongs to studyprogramme's manager group and is a study program leader |
| 247 | + */ |
| 248 | +const getProgrammeAdminAccess: AccessSpecialGroupFunction = (hyGroups) => { |
| 249 | + const orgCodes = hyGroups |
| 250 | + .filter((iam) => isStudyLeaderGroup(iam, hyGroups)) |
| 251 | + .map((iam) => iamToOrganisationCode(iam)) |
| 252 | + .filter(Boolean) |
| 253 | + |
| 254 | + const degreeCodes = orgCodes.flatMap((codes) => codes.map(mapToDegreeCode)) |
| 255 | + |
| 256 | + if (!(degreeCodes?.length > 0)) { |
| 257 | + return { |
| 258 | + access: {}, |
| 259 | + } |
| 260 | + } |
| 261 | + |
| 262 | + const access = {} |
| 263 | + degreeCodes.forEach((code) => { |
| 264 | + access[code] = { read: true, write: true, admin: true } |
| 265 | + }) |
| 266 | + return { access } |
| 267 | +} |
| 268 | + |
| 269 | +/** |
| 270 | + * UPDATE: nobody gets this. Kept here for documentation and consistency with other Toska software |
| 271 | + * Grant write and read access if the user belongs to employees group and studyprogramme's manager group |
| 272 | + * @param {string[]} hyGroups |
| 273 | + */ |
| 274 | +// eslint-disable-next-line no-unused-vars |
| 275 | +const getProgrammeWriteAccess: AccessSpecialGroupFunction = (hyGroups) => { |
| 276 | + if (!hyGroups.some(isEmployeeIam)) return {} |
| 277 | + const orgCodes = hyGroups |
| 278 | + .map((iam) => iamToOrganisationCode(iam)) |
| 279 | + .filter(Boolean) |
| 280 | + const degreeCodes = orgCodes.flatMap((codes) => codes.map(mapToDegreeCode)) |
| 281 | + const access = {} |
| 282 | + degreeCodes.forEach((code) => { |
| 283 | + if (!code) return |
| 284 | + access[code] = { read: true, write: true, admin: false } |
| 285 | + }) |
| 286 | + |
| 287 | + return { access } |
| 288 | +} |
| 289 | + |
| 290 | +/** |
| 291 | + * Grant read access if the user belongs to studyprogramme's manager group |
| 292 | + */ |
| 293 | +const getProgrammeReadAccess: AccessSpecialGroupFunction = (hyGroups) => { |
| 294 | + const orgCodes = hyGroups |
| 295 | + .map((iam) => iamToOrganisationCode(iam)) |
| 296 | + .filter(Boolean) |
| 297 | + const degreeCodes = orgCodes.flatMap((codes) => codes.map(mapToDegreeCode)) |
| 298 | + const access = {} |
| 299 | + degreeCodes.forEach((code) => { |
| 300 | + if (!code) return |
| 301 | + access[code] = { read: true, write: false, admin: false } |
| 302 | + }) |
| 303 | + |
| 304 | + return { access } |
| 305 | +} |
| 306 | + |
| 307 | +/** |
| 308 | + * Gets access rights and special groups, |
| 309 | + * based on IAM-groups in IAM header string |
| 310 | + */ |
| 311 | +const getIAMRights: AccessSpecialGroupFunction = (hyGroups) => { |
| 312 | + let access = {} |
| 313 | + let specialGroup = {} |
| 314 | + |
| 315 | + ;[ |
| 316 | + getUniversityReadingRights, |
| 317 | + getFacultyReadingRights, |
| 318 | + getDoctoralAccess, |
| 319 | + getDoctoralSchoolAccess, |
| 320 | + getProgrammeReadAccess, |
| 321 | + // getProgrammeWriteAccess, |
| 322 | + getProgrammeAdminAccess, |
| 323 | + getFacultyAdminRights, |
| 324 | + getSpecialGroups, |
| 325 | + ] |
| 326 | + .map((f) => f(hyGroups)) |
| 327 | + .forEach((accessInfo) => { |
| 328 | + access = { ...access, ...accessInfo.access } |
| 329 | + specialGroup = { ...specialGroup, ...accessInfo.specialGroup } |
| 330 | + }) |
| 331 | + |
| 332 | + return { access, specialGroup } |
| 333 | +} |
| 334 | + |
| 335 | +export default getIAMRights |
0 commit comments