diff --git a/package-lock.json b/package-lock.json
index b2af04034..8e0325a5e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,7 +19,7 @@
"@sentry/browser": "^8.0.0",
"@sentry/node": "^8.0.0",
"@sentry/tracing": "^7.0.0",
- "@vitejs/plugin-react-swc": "^3.6.0",
+ "@vitejs/plugin-react-swc": "^3.7.1",
"axios": "^1.7.2",
"buffer": "^6.0.3",
"chart.js": "^3.4.0",
@@ -122,6 +122,9 @@
},
"engines": {
"node": ">=14.7"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-darwin-arm64": "4.24.0"
}
},
"node_modules/@ampproject/remapping": {
@@ -4204,6 +4207,149 @@
"node": ">= 8.0.0"
}
},
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.20.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz",
+ "integrity": "sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.20.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.20.0.tgz",
+ "integrity": "sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz",
+ "integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.20.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.20.0.tgz",
+ "integrity": "sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.20.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.20.0.tgz",
+ "integrity": "sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.20.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.20.0.tgz",
+ "integrity": "sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.20.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.20.0.tgz",
+ "integrity": "sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.20.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.20.0.tgz",
+ "integrity": "sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
+ "version": "4.20.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.20.0.tgz",
+ "integrity": "sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.20.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.20.0.tgz",
+ "integrity": "sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.20.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.20.0.tgz",
+ "integrity": "sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.20.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz",
@@ -4230,6 +4376,45 @@
"linux"
]
},
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.20.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz",
+ "integrity": "sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.20.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz",
+ "integrity": "sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.20.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz",
+ "integrity": "sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
"node_modules/@rtsao/scc": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
@@ -4918,86 +5103,6 @@
}
}
},
- "node_modules/@swc/core-darwin-arm64": {
- "version": "1.7.36",
- "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.36.tgz",
- "integrity": "sha512-8vDczXzCgv3ceTPhEivlpGprN44YlrCK1nbfU9g2TrhV/Aiqi09W/eM5zLesdoM1Z3mJl492gc/8nlTkpDdusw==",
- "cpu": [
- "arm64"
- ],
- "license": "Apache-2.0 AND MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@swc/core-darwin-x64": {
- "version": "1.7.36",
- "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.7.36.tgz",
- "integrity": "sha512-Pa2Gao7+Wf5m3SsK4abKRtd48AtoUnJInvaC3d077swBfgZjbjUbQvcpdc2dOeQtWwo49rFqUZJonMsL0jnPgQ==",
- "cpu": [
- "x64"
- ],
- "license": "Apache-2.0 AND MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@swc/core-linux-arm-gnueabihf": {
- "version": "1.7.36",
- "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.36.tgz",
- "integrity": "sha512-3YsMWd7V+WZEjbfBnLkkz/olcRBa8nyoK0iIOnNARJBMcYaJxjkJSMZpmSojCnIVwvjA1N83CPAbUL+W+fCnHg==",
- "cpu": [
- "arm"
- ],
- "license": "Apache-2.0",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@swc/core-linux-arm64-gnu": {
- "version": "1.7.36",
- "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.36.tgz",
- "integrity": "sha512-lqM3aBB7kJazJYOwHeA5OGNLqXoQPZ/76b3dV+XcjN1GhD0CcXz6mW5PRYVin6OSN1eKrKBKJjtDA1mqADDEvw==",
- "cpu": [
- "arm64"
- ],
- "license": "Apache-2.0 AND MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@swc/core-linux-arm64-musl": {
- "version": "1.7.36",
- "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.36.tgz",
- "integrity": "sha512-bqei2YDzvUfG0pth5W2xJaj0eG4XWYk0d/NJ75vBX6bkIzK6dC8iuKQ41jOfUWonnrAs7rTDDJW0sTn/evvRdw==",
- "cpu": [
- "arm64"
- ],
- "license": "Apache-2.0 AND MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/@swc/core-linux-x64-gnu": {
"version": "1.7.36",
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.36.tgz",
@@ -5030,54 +5135,6 @@
"node": ">=10"
}
},
- "node_modules/@swc/core-win32-arm64-msvc": {
- "version": "1.7.36",
- "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.36.tgz",
- "integrity": "sha512-k7+dmb13a/zPw+E4XYfPmLZFWJgcOcBRKIjYl9nQErtYsgsg3Ji6TBbsvJVETy23lNHyewZ17V5Vq6NzaG0hzg==",
- "cpu": [
- "arm64"
- ],
- "license": "Apache-2.0 AND MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@swc/core-win32-ia32-msvc": {
- "version": "1.7.36",
- "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.36.tgz",
- "integrity": "sha512-ridD3ay6YM2PEYHZXXFN+edYEv0FOynaqOBP+NSnGNHA35azItIjoIe+KNi4WltGtAjpKCHSpjGCNfna12wdYQ==",
- "cpu": [
- "ia32"
- ],
- "license": "Apache-2.0 AND MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@swc/core-win32-x64-msvc": {
- "version": "1.7.36",
- "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.36.tgz",
- "integrity": "sha512-j1z2Z1Ln9d0E3dHsPkC1K9XDh0ojhRPwV+GfRTu4D61PE+aYhYLvbJC6xPvL4/204QrStRS7eDu3m+BcDp3rgQ==",
- "cpu": [
- "x64"
- ],
- "license": "Apache-2.0 AND MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/@swc/counter": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
@@ -16505,6 +16562,19 @@
"fsevents": "~2.3.2"
}
},
+ "node_modules/rollup/node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.20.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz",
+ "integrity": "sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
"node_modules/run-parallel": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
diff --git a/package.json b/package.json
index e4caa11b1..50ddbeee7 100644
--- a/package.json
+++ b/package.json
@@ -55,7 +55,7 @@
"@sentry/browser": "^8.0.0",
"@sentry/node": "^8.0.0",
"@sentry/tracing": "^7.0.0",
- "@vitejs/plugin-react-swc": "^3.6.0",
+ "@vitejs/plugin-react-swc": "^3.7.1",
"axios": "^1.7.2",
"buffer": "^6.0.3",
"chart.js": "^3.4.0",
@@ -156,6 +156,9 @@
"util": "^0.12.4",
"vite-plugin-eslint": "^1.8.1"
},
+ "optionalDependencies": {
+ "@rollup/rollup-darwin-arm64": "4.24.0"
+ },
"browserslist": {
"production": [
">0.2%",
diff --git a/src/client/pages/FeedbackTarget/FeedbackTarget.jsx b/src/client/pages/FeedbackTarget/FeedbackTarget.jsx
index f360d0d6e..71393ff27 100644
--- a/src/client/pages/FeedbackTarget/FeedbackTarget.jsx
+++ b/src/client/pages/FeedbackTarget/FeedbackTarget.jsx
@@ -17,10 +17,26 @@ const FeedbackTarget = () => {
const { authorizedUser } = useAuthorizedUser()
const { organisations, isLoading: organisationsLoading } = useOrganisations()
+ function getPriority(org) {
+ let weight = 0
+ if (org.access.admin) {
+ weight += 100
+ }
+ if (org.access.write) {
+ weight += 10
+ }
+ if (org.access.read) {
+ weight += 1
+ }
+ return weight
+ }
const organisation =
isLoading || organisationsLoading || !courseUnit
? null
- : organisations?.find(org => courseUnit.organisations[0].id === org.id)
+ : organisations
+ ?.filter(org => courseUnit.organisations.map(o => o.id)?.includes(org.id))
+ ?.sort((a, b) => getPriority(b) - getPriority(a)) // admin, write, read
+ ?.at(0)
if (isLoading) {
return
diff --git a/src/client/pages/FeedbackTarget/tabs/Results/ExportFeedbacksMenu.jsx b/src/client/pages/FeedbackTarget/tabs/Results/ExportFeedbacksMenu.jsx
index 2c03bf71a..cca6a4247 100644
--- a/src/client/pages/FeedbackTarget/tabs/Results/ExportFeedbacksMenu.jsx
+++ b/src/client/pages/FeedbackTarget/tabs/Results/ExportFeedbacksMenu.jsx
@@ -24,11 +24,21 @@ const getHeaders = (questions, feedbacks, language) => {
}
const getData = (questions, feedbacks, language) => {
- const options = flatMap(questions, q =>
- ['MULTIPLE_CHOICE', 'SINGLE_CHOICE'].includes(q.type) ? (q.data?.options ?? []) : []
- )
+ //Filter to choice questions only
+ const choiceQuestions = questions.filter(q => ['MULTIPLE_CHOICE', 'SINGLE_CHOICE'].includes(q.type))
+
+ // optionIds are not unique, so we need to create unique ids for options by adding questionId to the beginning of the id and set it as questionOptionId
+ choiceQuestions.forEach(question => {
+ if (question.data && question.data.options) {
+ question.data.options.forEach(option => {
+ option.questionOptionId = `${question.id}_${option.id}`
+ })
+ }
+ })
+
+ const options = flatMap(choiceQuestions, q => q.data?.options ?? [])
- const optionById = keyBy(options, ({ id }) => id)
+ const optionById = keyBy(options, ({ questionOptionId }) => questionOptionId)
const data = feedbacks.map(f => {
const feedback = f.data
@@ -40,13 +50,15 @@ const getData = (questions, feedbacks, language) => {
if (Array.isArray(d.data)) {
return d.data
.map(optionId => {
- const option = optionById[optionId]
+ const questionOptionId = `${q.id}_${optionId}`
+ const option = optionById[questionOptionId]
return getLanguageValue(option?.label, language)
})
.join(', ')
}
- const option = optionById[d.data]
+ const questionOptionId = `${q.id}_${d.data}`
+ const option = optionById[questionOptionId]
return getLanguageValue(option?.label, language)
}
diff --git a/src/client/pages/FeedbackTarget/tabs/Results/QuestionResults/QuestionResults.jsx b/src/client/pages/FeedbackTarget/tabs/Results/QuestionResults/QuestionResults.jsx
index f79605f7d..be7e576cb 100644
--- a/src/client/pages/FeedbackTarget/tabs/Results/QuestionResults/QuestionResults.jsx
+++ b/src/client/pages/FeedbackTarget/tabs/Results/QuestionResults/QuestionResults.jsx
@@ -39,7 +39,9 @@ const getQuestionsWithFeedback = (questions, questionOrder, feedbacks) => {
) // filter short answers which are not a number, or answers that are blank
.filter(answer => {
const isNumber = !Number.isNaN(parseInt(answer.data, 10))
- return isNumber || answer.data?.trim?.().length > 1
+ const isArray = Array.isArray(answer.data)
+ const arrayLength = isArray ? answer.data.length : 0
+ return isNumber || arrayLength > 0 || answer.data?.trim?.().length > 1
})
const feedbackDataByQuestionId = groupBy(feedbackData, ({ questionId }) => questionId ?? '_')
diff --git a/src/client/pages/MyFeedbacks/FeedbackTargetItem.jsx b/src/client/pages/MyFeedbacks/FeedbackTargetItem.jsx
index d9969d75f..3a32658a9 100644
--- a/src/client/pages/MyFeedbacks/FeedbackTargetItem.jsx
+++ b/src/client/pages/MyFeedbacks/FeedbackTargetItem.jsx
@@ -21,7 +21,7 @@ import { getStartAndEndString } from '../../util/getDateRangeString'
import feedbackTargetIsEnded from '../../util/feedbackTargetIsEnded'
import feedbackTargetCourseIsOngoing from '../../util/feedbackTargetCourseIsOngoing'
import feedbackTargetNotGivingFeedback from '../../util/feedbackTargetNotGivingFeedback'
-import { SHOW_FEEDBACKS_TO_STUDENTS_ONLY_AFTER_ENDING, SHOW_COURSE_CODES_WITH_COURSE_NAMES } from '../../util/common'
+import { SHOW_FEEDBACKS_TO_STUDENTS_ONLY_AFTER_ENDING } from '../../util/common'
import { getCourseCode } from '../../util/courseIdentifiers'
const NoFeedbackActions = ({ editPath, noFeedbackAllowed, onNotGivingFeedback }) => {
@@ -273,13 +273,6 @@ const PeriodInfoAddition = ({ isEnded }) => {
return null
}
-const getCourseDisplayName = (translatedName, courseCode, isOrganisationSurvey) => {
- if (SHOW_COURSE_CODES_WITH_COURSE_NAMES && !isOrganisationSurvey) {
- return `${courseCode} ${translatedName}`
- }
- return `${translatedName}`
-}
-
const FeedbackTargetItem = ({ feedbackTarget, divider }) => {
const { t, i18n } = useTranslation()
const queryClient = useQueryClient()
@@ -296,11 +289,6 @@ const FeedbackTargetItem = ({ feedbackTarget, divider }) => {
const courseName = getCourseName(feedbackTarget, t)
const visibleCourseCode = getCourseCode(courseUnit)
const translatedName = getLanguageValue(courseName, i18n.language)
- const courseDisplayName = getCourseDisplayName(
- translatedName,
- feedbackTarget.courseUnit.courseCode,
- feedbackTarget.courseUnit.userCreated
- )
const editPath = `/targets/${id}/feedback`
const viewPath = `/targets/${id}/results`
@@ -337,7 +325,7 @@ const FeedbackTargetItem = ({ feedbackTarget, divider }) => {
disableGutters
>
- {visibleCourseCode} {courseDisplayName}
+ {visibleCourseCode} {translatedName}
diff --git a/src/server/models/user.js b/src/server/models/user.js
index fa77e23e1..17c1667da 100644
--- a/src/server/models/user.js
+++ b/src/server/models/user.js
@@ -51,8 +51,22 @@ class User extends Model {
const organisationIds = rows.flatMap(row => Object.values(row))
+ function getPriority(org) {
+ let weight = 0
+ if (org.access.admin) {
+ weight += 100
+ }
+ if (org.access.write) {
+ weight += 10
+ }
+ if (org.access.read) {
+ weight += 1
+ }
+ return weight
+ }
const organisationAccess = organisations
.filter(({ organisation }) => organisationIds.includes(organisation.id))
+ ?.sort((a, b) => getPriority(a) - getPriority(b)) // read, write, admin. Reduce on next line practically takes the last value
.reduce((finalAccess, org) => ({ ...finalAccess, ...org.access }), {})
return organisationAccess ?? null
diff --git a/src/server/services/feedbackTargets/getAccess.js b/src/server/services/feedbackTargets/getAccess.js
index 6b568e373..db52d145a 100644
--- a/src/server/services/feedbackTargets/getAccess.js
+++ b/src/server/services/feedbackTargets/getAccess.js
@@ -4,23 +4,48 @@ const getAccess = async ({ userFeedbackTarget, user, feedbackTarget }) => {
if (user.dataValues.isAdmin) return Access.ADMIN
const accessStatus = userFeedbackTarget?.accessStatus
-
+ let uftAccess = null
if (accessStatus) {
- return Access.For(accessStatus)
+ uftAccess = Access.For(accessStatus)
}
// User not directly associated. Lets check if they have access through organisation
const organisationAccess = await user.getOrganisationAccessByCourseUnitId(feedbackTarget.courseUnitId)
- if (!organisationAccess) {
- return null
+ let orgAccess = null
+ if (organisationAccess) {
+ if (organisationAccess.admin) {
+ orgAccess = Access.ORGANISATION_ADMIN
+ } else if (organisationAccess.read) {
+ orgAccess = Access.ORGANISATION_READ
+ }
}
- if (organisationAccess.admin) {
- return Access.ORGANISATION_ADMIN
+ // only direct access, return that
+ if (uftAccess !== null && orgAccess === null) {
+ return uftAccess
+ }
+ // access only through organisation, return that
+ if (uftAccess === null && orgAccess !== null) {
+ return orgAccess
+ }
+ // both direct access and access through organisation, return highest
+ if (uftAccess !== null && orgAccess !== null) {
+ if (orgAccess === Access.ORGANISATION_ADMIN) {
+ if (uftAccess === Access.ADMIN || uftAccess === Access.RESPONSIBLE_TEACHER) {
+ return uftAccess
+ }
+ return orgAccess
+ }
+ if (orgAccess === Access.ORGANISATION_READ) {
+ if (uftAccess === Access.STUDENT) {
+ return orgAccess
+ }
+ return uftAccess
+ }
}
- return Access.ORGANISATION_READ
+ return null
}
module.exports = { getAccess }
diff --git a/src/server/services/summary/getCourseUnitGroupSummary.js b/src/server/services/summary/getCourseUnitGroupSummary.js
index 7bc36d0ad..2a12bbda7 100644
--- a/src/server/services/summary/getCourseUnitGroupSummary.js
+++ b/src/server/services/summary/getCourseUnitGroupSummary.js
@@ -91,7 +91,6 @@ const getCourseUnitGroupSummaries = async ({ user, courseCode, startDate, endDat
const allOrgIds = cuOrgIds.concat(curOrgIds)
const hasOrgAccess = Object.values(orgAccess).some(o => allOrgIds.includes(o.organisation.id))
-
if (!user.isAdmin && !hasOrgAccess) {
const hasCurAccess = feedbackTargets.some(fbt => accessibleCurIds.includes(fbt.courseRealisation.id))
if (!hasCurAccess) {