From 744ec9e3873ef6b6bb7872d417eed6cdd445d4a5 Mon Sep 17 00:00:00 2001 From: wiaderwek Date: Mon, 18 Dec 2023 11:26:36 +0100 Subject: [PATCH 1/5] set tldraw announcement text (#3366) * set tldraw announcement text * fix bolding --------- Co-authored-by: Tomasz Wiaderek --- locales/de.json | 2 +- locales/en.json | 2 +- locales/es.json | 2 +- locales/uk.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/locales/de.json b/locales/de.json index af0b547285..1508c27df9 100644 --- a/locales/de.json +++ b/locales/de.json @@ -1249,7 +1249,7 @@ "toTask": "Zur Aufgabe" }, "text": { - "announcement": "Nehmen Sie an unserer Zufriedenheitsumfrage teil und helfen Sie uns, die Cloud zu verbessern. Hier geht’s zur Befragung.", + "announcement": "Wichtige Ankündigung: Das Tool neXboard wird durch tldraw ersetzt. Sichern Sie Ihre Inhalte aus den neXboards, die Sie weiter verwenden wollen, bitte bis zum 15.03.2024. Bis dahin können angelegte neXboards weiterhin verwendet werden. Hier finden Sie Möglichkeiten der Sicherung und weitere Informationen.", "emptyHomeworksInfo": "Keine gestellten Aufgaben. Du findest alle Aufgaben im Aufgaben-Bereich.", "emptyNewsInfo": "Bisher gibt es keine News.", "graded": "Bewertet", diff --git a/locales/en.json b/locales/en.json index 5017a2e332..bda3d1c225 100644 --- a/locales/en.json +++ b/locales/en.json @@ -1249,7 +1249,7 @@ "toTask": "To the task" }, "text": { - "announcement": "Take part in our satisfaction survey and help us improve the cloud. Click here for the survey. (German language only).", + "announcement": "Important announcement: The neXboard tool will be replaced by tldraw. Please back up your content from the neXboards that you wish to continue using by 15.03.2024. Until then, neXboards you have created can still be used. Here you can find backup options and further information.", "emptyHomeworksInfo": "No assigned tasks. You can find all tasks in the tasks area.", "emptyNewsInfo": "So far there is no news.", "graded": "Graded", diff --git a/locales/es.json b/locales/es.json index e8d2b2aa0a..bdd5093448 100644 --- a/locales/es.json +++ b/locales/es.json @@ -1249,7 +1249,7 @@ "toTask": "A la tarea" }, "text": { - "announcement": "Participe en nuestra encuesta de satisfacción y ayúdenos a mejorar la nube. Haga clic aquí para acceder a la encuesta (solo en alemán).", + "announcement": "Anuncio importante: La herramienta neXboard será sustituida por tldraw. Por favor, haga una copia de seguridad del contenido de los neXboards que desee seguir utilizando antes del 15 de marzo de 2024. Los neXboards que haya creado podrán seguir utilizándose hasta entonces. Aquí encontrará opciones de copia de seguridad y más informaciones.", "emptyHomeworksInfo": "No hay tareas asignadas. Puedes encontrarar todas las tareas en el área de tareas.", "emptyNewsInfo": "Hasta el momento no hay noticias.", "graded": "Calificado", diff --git a/locales/uk.json b/locales/uk.json index 156f5008a5..6783f7156a 100644 --- a/locales/uk.json +++ b/locales/uk.json @@ -9,7 +9,7 @@ "welcome": "Вітаємо" }, "text": { - "announcement": "Візьміть участь у нашому опитуванні та допоможіть нам покращити хмару. Натисніть тут, щоб отримати доступ до опитування (лише німецькою мовою).", + "announcement": "Важливе оголошення: Інструмент neXboard буде замінено на tldraw. Будь ласка, створіть резервну копію вашого контенту на дошках neXboards, які ви хочете продовжувати використовувати, до 15 березня 2024 року. Створені вами дошки neXboards можна буде використовувати до цього часу. Тут ви можете знайти варіанти резервного копіювання та додаткову інформацію.", "notFound": "Активних записів не знайдено.", "emptyHomeworksInfo": "Усі домашні завдання показуються в розділі домашніх завдань.", "emptyNewsInfo": "Немає останніх новин. Перегляньте розділ новин, щоб бути в курсі.", From 88484fd9b05fbf06ec20c3cc13f1f0a4e954eae3 Mon Sep 17 00:00:00 2001 From: agnisa-cap Date: Mon, 18 Dec 2023 15:09:41 +0100 Subject: [PATCH 2/5] N21-1602 fixes classes limit by setting limit to -1 (#3372) --- controllers/courses.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/courses.js b/controllers/courses.js index 91ab460b7b..1746fb0f97 100644 --- a/controllers/courses.js +++ b/controllers/courses.js @@ -132,7 +132,7 @@ const editCourseHandler = (req, res, next) => { let classesPromise; if (FEATURE_GROUPS_IN_COURSE_ENABLED) { classesAndGroupsPromise = api(req, { version: 'v3' }) - .get('/groups/class'); + .get('/groups/class', { qs: { limit: -1 } }); } else { classesPromise = api(req) .get('/classes', { From 56cc8272bf9547ba0abc658069fb58a420f9de4b Mon Sep 17 00:00:00 2001 From: Max <53796487+dyedwiper@users.noreply.github.com> Date: Tue, 19 Dec 2023 08:33:32 +0100 Subject: [PATCH 3/5] BC-4783 - Migrate GET endpoints of school API (#3315) --- controllers/administration.js | 46 +++++++++++++++++++++------------- controllers/courses.js | 4 +-- controllers/schools.js | 20 +++++---------- controllers/teams.js | 4 +-- helpers/authentication.js | 10 +++----- helpers/schoolHelper.js | 42 +++++++++++++++++++++++++++++++ static/scripts/teamMembers.js | 3 --- views/administration/teams.hbs | 17 ++++--------- 8 files changed, 89 insertions(+), 57 deletions(-) create mode 100644 helpers/schoolHelper.js diff --git a/controllers/administration.js b/controllers/administration.js index 40f19df962..01dc74285c 100644 --- a/controllers/administration.js +++ b/controllers/administration.js @@ -23,6 +23,7 @@ const upload = multer({ storage: multer.memoryStorage() }); const { HOST, CONSENT_WITHOUT_PARENTS_MIN_AGE_YEARS, FEATURE_NEST_SYSTEMS_API_ENABLED } = require('../config/global'); const { isUserHidden } = require('../helpers/users'); +const renameIdsInSchool = require('../helpers/schoolHelper'); // eslint-disable-next-line no-unused-vars const getSelectOptions = (req, service, query, values = []) => api(req) @@ -2689,6 +2690,9 @@ router.all('/teams', async (req, res, next) => { users = users.filter((user) => !isUserHidden(user, res.locals.currentSchoolData)); + const school = res.locals.currentSchoolData; + const isTeamCreationByStudentsEnabled = school.features.includes('isTeamCreationByStudentsEnabled'); + res.render('administration/teams', { title: res.$t('administration.dashboard.headline.manageTeams'), head, @@ -2696,8 +2700,9 @@ router.all('/teams', async (req, res, next) => { classes, users, pagination, - school: res.locals.currentSchoolData, + school, limit: true, + isTeamCreationByStudentsEnabled, }); }); }); @@ -2779,6 +2784,9 @@ router.get('/rss/:id', async (req, res) => { res.send(matchingRSSFeed); }); +// TODO: It would be nice if this route would be removed soon, +// so we don't need to worry about the call to GET schools here. +// Ticket for removal: https://ticketsystem.dbildungscloud.de/browse/BC-4231 router.post('/rss/', async (req, res) => { const school = await api(req).get(`/schools/${req.body.schoolId}`); @@ -2816,12 +2824,8 @@ router.use( permissionsHelper.permissionsChecker(['ADMIN_VIEW', 'TEACHER_CREATE'], 'or'), async (req, res) => { const [school, totalStorage, schoolMaintanance, consentVersions] = await Promise.all([ - api(req).get(`/schools/${res.locals.currentSchool}`, { - qs: { - $populate: ['systems', 'federalState'], - $sort: req.query.sort, - }, - }), + api(req, { version: 'v3' }).get(`/school/id/${res.locals.currentSchool}`) + .then((result) => renameIdsInSchool(result)), api(req).get('/fileStorage/total'), api(req).get(`/schools/${res.locals.currentSchool}/maintenance`), api(req).get('/consentVersions', { @@ -2836,6 +2840,10 @@ router.use( }), ]); + // In the future there should be a possibility to fetch a school with all systems populated via api/v3, + // but at the moment they need to be fetched separately. + school.systems = await Promise.all(school.systemIds.map((systemId) => api(req).get(`/systems/${systemId}`))); + // Maintanance - Show Menu depending on the state const currentTime = new Date(); const maintananceModeStarts = new Date(schoolMaintanance.currentYear.endDate); @@ -3057,12 +3065,14 @@ router.use('/startschoolyear', async (req, res) => { router.get('/startldapschoolyear', async (req, res) => { // Find LDAP-System const school = await Promise.resolve( - api(req).get(`/schools/${res.locals.currentSchool}`, { - qs: { - $populate: ['systems'], - }, - }), + api(req, { version: 'v3' }).get(`/school/id/${res.locals.currentSchool}`) + .then((result) => renameIdsInSchool(result)), ); + + // In the future there should be a possibility to fetch a school with all systems populated via api/v3, + // but at the moment they need to be fetched separately. + school.systems = await Promise.all(school.systemIds.map((systemId) => api(req).get(`/systems/${systemId}`))); + const system = school.systems.filter( // eslint-disable-next-line no-shadow (system) => system.type === 'ldap', @@ -3128,12 +3138,14 @@ router.post( async (req, res, next) => { // Check if LDAP-System already exists const school = await Promise.resolve( - api(req).get(`/schools/${res.locals.currentSchool}`, { - qs: { - $populate: ['systems'], - }, - }), + api(req, { version: 'v3' }).get(`/school/id/${res.locals.currentSchool}`) + .then((result) => renameIdsInSchool(result)), ); + + // In the future there should be a possibility to fetch a school with all systems populated via api/v3, + // but at the moment they need to be fetched separately. + school.systems = await Promise.all(school.systemIds.map((systemId) => api(req).get(`/systems/${systemId}`))); + // eslint-disable-next-line no-shadow const system = school.systems.filter((system) => system.type === 'ldap'); diff --git a/controllers/courses.js b/controllers/courses.js index 1746fb0f97..75658f29b3 100644 --- a/controllers/courses.js +++ b/controllers/courses.js @@ -213,8 +213,8 @@ const editCourseHandler = (req, res, next) => { // if new course -> add default start and end dates if (!req.params.courseId) { - course.startDate = res.locals.currentSchoolData.years.defaultYear.startDate; - course.untilDate = res.locals.currentSchoolData.years.defaultYear.endDate; + course.startDate = res.locals.currentSchoolData.years.activeYear.startDate; + course.untilDate = res.locals.currentSchoolData.years.activeYear.endDate; } // format course start end until date diff --git a/controllers/schools.js b/controllers/schools.js index f24ec9b3d8..024cb50109 100644 --- a/controllers/schools.js +++ b/controllers/schools.js @@ -3,27 +3,19 @@ const express = require('express'); const router = express.Router(); const api = require('../api'); -// schools - +// This route is only used for the external invite form. That's why the API call is specific for that. router.get('/', async (req, res, next) => { const params = { qs: { - $limit: req.query.$limit, - federalState: req.query.federalState, - $sort: 'name', + federalStateId: req.query.federalState, }, }; - if (req.query.hideOwnSchool) { - params.qs._id = { $ne: res.locals.currentSchool }; - } - try { - const schools = await api(req).get('/schools/', params); - const result = schools.data.map((school) => ({ - _id: school._id, + try { + const response = await api(req, { version: 'v3' }).get('/school/list-for-external-invite', params); + const result = response.map((school) => ({ + _id: school.id, name: school.name, - purpose: school.purpose, - officialSchoolNumber: school.officialSchoolNumber, })); return res.json(result); diff --git a/controllers/teams.js b/controllers/teams.js index 0c813204f9..a70bf39af5 100644 --- a/controllers/teams.js +++ b/controllers/teams.js @@ -109,7 +109,7 @@ const checkIfUserCanCreateTeam = (res) => { if (roleNames.includes('administrator') || roleNames.includes('teacher') || roleNames.includes('student')) { allowedCreateTeam = true; const currentSchool = res.locals.currentSchoolData; - if (roleNames.includes('student') && !currentSchool.isTeamCreationByStudentsEnabled) { + if (roleNames.includes('student') && !currentSchool.features.includes('isTeamCreationByStudentsEnabled')) { allowedCreateTeam = false; } } @@ -1138,7 +1138,7 @@ router.get('/:teamId/members', async (req, res, next) => { const { _id: studentRoleId } = roles.find((role) => role.name === 'student'); return res.locals.currentUser.permissions.includes('STUDENT_LIST') || !user.roles.includes(studentRoleId) - || res.locals.currentSchoolData.isTeamCreationByStudentsEnabled; + || res.locals.currentSchoolData.features.includes('isTeamCreationByStudentsEnabled'); }); body.sort((a, b) => { diff --git a/helpers/authentication.js b/helpers/authentication.js index 54604325fc..38bcf45c16 100644 --- a/helpers/authentication.js +++ b/helpers/authentication.js @@ -17,6 +17,7 @@ const { formatError } = require('./logFilter'); const { setCookie } = require('./cookieHelper'); const redirectHelper = require('./redirect'); +const renameIdsInSchool = require('./schoolHelper'); const rolesDisplayName = { teacher: 'Lehrer', @@ -147,15 +148,10 @@ const populateCurrentUser = async (req, res) => { res.locals.currentRole = rolesDisplayName[data.roles[0].name]; res.locals.roles = data.roles.map(({ name }) => name); res.locals.roleNames = data.roles.map((r) => rolesDisplayName[r.name]); - return api(req) - .get(`/schools/${res.locals.currentUser.schoolId}`, { - qs: { - $populate: ['federalState'], - }, - }) + return api(req, { version: 'v3' }).get(`/school/id/${res.locals.currentUser.schoolId}`) .then((data2) => { res.locals.currentSchool = res.locals.currentUser.schoolId; - res.locals.currentSchoolData = data2; + res.locals.currentSchoolData = renameIdsInSchool(data2); res.locals.currentSchoolData.isExpertSchool = data2.purpose === 'expert'; return data2; }); diff --git a/helpers/schoolHelper.js b/helpers/schoolHelper.js new file mode 100644 index 0000000000..8a9c6a6a1f --- /dev/null +++ b/helpers/schoolHelper.js @@ -0,0 +1,42 @@ +// In the api/v3 response the IDs are named "id" and not "_id" like in api/v1. +// They are renamed for compatibility, because it is hard to find all places where they are used. +const renameIdsInSchool = (school) => { + school._id = school.id; + delete school.id; + + school.federalState._id = school.federalState.id; + delete school.federalState.id; + + // counties were returned with id and _id from api/v1, so id is not deleted. + school.federalState.counties = school.federalState.counties + .map((county) => ({ ...county, _id: county.id })); + if (school.county) { + school.county._id = school.county.id; + } + + if (school.currentYear) { + school.currentYear._id = school.currentYear.id; + delete school.currentYear.id; + } + + school.years.schoolYears = school.years.schoolYears + .map((year) => { + const result = { ...year, _id: year.id }; + delete result.id; + + return result; + }); + + school.years.activeYear._id = school.years.activeYear.id; + delete school.years.activeYear.id; + + school.years.lastYear._id = school.years.lastYear.id; + delete school.years.lastYear.id; + + school.years.nextYear._id = school.years.nextYear.id; + delete school.years.nextYear.id; + + return school; +}; + +module.exports = renameIdsInSchool; diff --git a/static/scripts/teamMembers.js b/static/scripts/teamMembers.js index 69a84e4184..dbe9080eca 100644 --- a/static/scripts/teamMembers.js +++ b/static/scripts/teamMembers.js @@ -190,15 +190,12 @@ $(document).ready(() => { type: 'GET', url: `${window.location.origin}/schools`, data: { - $limit: false, federalState, - hideOwnSchool: true, }, }).done((schools) => { const schoolSelect = $('#school'); schoolSelect.find('option').remove(); schools.forEach((school) => { - if (school.purpose === 'expert') return; schoolSelect.append(``); }); schoolSelect.trigger('chosen:updated'); diff --git a/views/administration/teams.hbs b/views/administration/teams.hbs index ec5a9bde68..f68b179b23 100644 --- a/views/administration/teams.hbs +++ b/views/administration/teams.hbs @@ -24,18 +24,11 @@