Skip to content

Commit 6dc0550

Browse files
committed
show responsibles of all courses for faculties
1 parent c14b796 commit 6dc0550

File tree

8 files changed

+98
-6
lines changed

8 files changed

+98
-6
lines changed

public/locales/en/translation.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,8 @@
551551
"feedbackCorrespondents": "Feedback liaisons",
552552
"surveyTab": "Programme questions",
553553
"organisationSurveysTab": "Programme surveys",
554+
"surveyFacultyTab": "Faculty questions",
555+
"organisationFacultySurveysTab": "Faculty surveys",
554556
"summaryTab": "Summary",
555557
"courseRealisationsTab": "Courses",
556558
"responsiblesTab": "Responsibles",

public/locales/fi/translation.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,8 @@
551551
"feedbackCorrespondents": "Palautevastaavat",
552552
"surveyTab": "Koulutusohjelman kysymykset",
553553
"organisationSurveysTab": "Koulutusohjelman kyselyt",
554+
"surveyFacultyTab": "Tiedekunnan kysymykset",
555+
"organisationFacultySurveysTab": "Tiedekunnan kyselyt",
554556
"summaryTab": "Yhteenveto",
555557
"courseRealisationsTab": "Kurssit",
556558
"responsiblesTab": "Vastuuopettajat",

public/locales/sv/translation.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,8 @@
528528
"feedbackCorrespondents": "Korrespondenter för responsen",
529529
"surveyTab": "Utbildningsprogrammets frågor",
530530
"organisationSurveysTab": "Utbildningsprogrammets enkäter",
531+
"surveyFacultyTab": "Fakultetsfrågor",
532+
"organisationFacultySurveysTab": "Fakultetsenkäter",
531533
"summaryTab": "Sammandrag",
532534
"courseRealisationsTab": "Kurser",
533535
"openQuestionsTab": "Öppna frågor",

src/client/pages/Organisation/Organisation.jsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ const Organisation = () => {
5656
const hasWriteAccess = Boolean(organisation?.access?.write)
5757
const hasAdminAccess = Boolean(organisation?.access?.admin)
5858

59+
const isFaculty = Boolean(organisation?.isFaculty)
60+
5961
if (!hasReadAccess) {
6062
return <Navigate to="/" />
6163
}
@@ -108,14 +110,18 @@ const Organisation = () => {
108110
)}
109111
{hasWriteAccess && (
110112
<RouterTab
111-
label={t('organisationSettings:surveyTab')}
113+
label={t(isFaculty ? 'organisationSettings:surveyFacultyTab' : 'organisationSettings:surveyTab')}
112114
icon={<LiveHelpOutlined />}
113115
to={`${pathnameBase}/survey`}
114116
/>
115117
)}
116118
{ORGANISATION_SURVEYS_ENABLED && hasWriteAccess && (
117119
<RouterTab
118-
label={t('organisationSettings:organisationSurveysTab')}
120+
label={t(
121+
isFaculty
122+
? 'organisationSettings:organisationFacultySurveysTab'
123+
: 'organisationSettings:organisationSurveysTab'
124+
)}
119125
icon={<DynamicFormOutlined />}
120126
to={`${pathnameBase}/organisation-surveys`}
121127
/>
@@ -173,7 +179,7 @@ const Organisation = () => {
173179
/>
174180
)}
175181

176-
<Route path="/responsibles" element={<Responsibles />} />
182+
<Route path="/responsibles" element={<Responsibles organisation={organisation} />} />
177183
<Route path="/responsibles/xlsx" element={<ResponsiblesXlsx />} />
178184

179185
<Route

src/client/pages/Organisation/Responsibles.jsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,12 @@ import { YearSemesterPeriodSelector } from '../../components/common/YearSemester
2929
import useHistoryState from '../../hooks/useHistoryState'
3030
import { getYearRange } from '../../util/yearUtils'
3131
import { NorButton } from '../../components/common/NorButton'
32-
import { useOrganisationFeedbackTargets, getCourseRealisationName, generateTeacherStats } from './responsiblesUtils'
32+
import {
33+
useOrganisationFeedbackTargets,
34+
getCourseRealisationName,
35+
generateTeacherStats,
36+
useFacultyFeedbackTargets,
37+
} from './responsiblesUtils'
3338

3439
const styles = {
3540
filtersHead: {
@@ -72,7 +77,7 @@ const Filters = React.memo(({ startDate, endDate, onChange, timeOption, setTimeO
7277
)
7378
})
7479

75-
const Responsibles = () => {
80+
const Responsibles = ({ organisation }) => {
7681
const { t, i18n } = useTranslation()
7782
const { code } = useParams()
7883
const [searchParams, setSearchParams] = useSearchParams()
@@ -126,7 +131,8 @@ const Responsibles = () => {
126131
setExportMenuAnchor(null)
127132
}
128133

129-
const { data: feedbackTargets, isLoading } = useOrganisationFeedbackTargets({
134+
const hookToUse = organisation.isFaculty ? useFacultyFeedbackTargets : useOrganisationFeedbackTargets
135+
const { data: feedbackTargets, isLoading } = hookToUse({
130136
code,
131137
startDate,
132138
endDate,

src/client/pages/Organisation/responsiblesUtils.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,26 @@ export const useOrganisationFeedbackTargets = ({ code, startDate, endDate, enabl
2222
})
2323
}
2424

25+
export const useFacultyFeedbackTargets = ({ code, startDate, endDate, enabled }) => {
26+
const queryKey = ['facultyFeedbackTargets', code, startDate, endDate]
27+
28+
const queryFn = async () => {
29+
const { data: feedbackTargets } = await apiClient.get(`/feedback-targets/for-faculty/${code}`, {
30+
params: { startDate, endDate },
31+
})
32+
33+
return feedbackTargets
34+
}
35+
36+
return useQuery({
37+
queryKey,
38+
queryFn,
39+
enabled,
40+
refetchOnWindowFocus: false,
41+
refetchOnMount: false,
42+
})
43+
}
44+
2545
export const getCourseRealisationName = (fbt, i18n) => {
2646
const name =
2747
fbt.courseRealisation.name[i18n.language] ||

src/server/models/organisation.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class Organisation extends Model<InferAttributes<Organisation>, InferCreationAtt
3838
// --- Virtual fields. ---------
3939
// --- ideally refactor away ---
4040
// -----------------------------
41+
declare isFaculty?: boolean
4142
declare summary?: Summary
4243
declare courseUnits?: CourseUnit[]
4344
declare summaries?: Summary[]
@@ -120,6 +121,12 @@ Organisation.init(
120121
allowNull: false,
121122
defaultValue: [],
122123
},
124+
isFaculty: {
125+
type: VIRTUAL,
126+
get() {
127+
return /^H\d{2}$/.test(this.code || '')
128+
},
129+
},
123130
summary: {
124131
type: VIRTUAL,
125132
},

src/server/routes/feedbackTargets/feedbackTargetController.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Response, Router } from 'express'
22
import { AuthenticatedRequest } from 'types'
33
import { ApplicationError } from '../../util/ApplicationError'
4+
import { Organisation } from '../../models'
45

56
import { createFeedbackTargetLog } from '../../services/auditLog'
67
import { mailer } from '../../mailer'
@@ -32,6 +33,52 @@ import { PUBLIC_COURSE_BROWSER_ENABLED } from '../../util/config'
3233
const adRouter = Router()
3334
const noadRouter = Router()
3435

36+
// TODO figure out if the two bellow functions could be united
37+
adRouter.get('/for-faculty/:code', async (req: AuthenticatedRequest, res: Response) => {
38+
const { user } = req
39+
const { code } = req.params
40+
const { startDate, endDate } = req.query
41+
if (!code) throw ApplicationError.BadRequest('Missing code')
42+
43+
const organisationAccess = await user.organisationAccess
44+
if (!organisationAccess[code]?.read) throw ApplicationError.Forbidden()
45+
46+
const facultyOrganisation = await Organisation.findOne({
47+
where: { code },
48+
include: [
49+
{
50+
model: Organisation,
51+
as: 'childOrganisations',
52+
attributes: ['id', 'code'],
53+
},
54+
],
55+
})
56+
57+
if (!facultyOrganisation) throw ApplicationError.NotFound('Organisation not found')
58+
59+
const childOrgCodes =
60+
facultyOrganisation.childOrganisations
61+
?.filter(child => organisationAccess[child.code]?.read)
62+
.map(child => child.code) || []
63+
64+
const allOrganisationCodes = [code, ...childOrgCodes]
65+
66+
const feedbackTargetsPromises = allOrganisationCodes.map(orgCode =>
67+
getFeedbackTargetsForOrganisation({
68+
organisationCode: orgCode,
69+
startDate: startDate as string,
70+
endDate: endDate as string,
71+
user,
72+
})
73+
)
74+
75+
const feedbackTargetsArrays = await Promise.all(feedbackTargetsPromises)
76+
77+
const feedbackTargets = feedbackTargetsArrays.flat()
78+
79+
res.send(feedbackTargets)
80+
})
81+
3582
adRouter.get('/for-organisation/:code', async (req: AuthenticatedRequest, res: Response) => {
3683
const { user } = req
3784
const { code } = req.params

0 commit comments

Comments
 (0)