From bf25bd6a0fd8f082aa4297c45686f23db496137f Mon Sep 17 00:00:00 2001 From: NBeew <133863382+NBeew@users.noreply.github.com> Date: Thu, 7 Sep 2023 09:37:12 +0200 Subject: [PATCH 1/5] BC-5070 Anpassung Hilfebereich Update tutorials.json (#3298) --- helpers/content/tutorials.json | 88 ++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 3 deletions(-) diff --git a/helpers/content/tutorials.json b/helpers/content/tutorials.json index 32a6df3bc0..fdd02d9657 100644 --- a/helpers/content/tutorials.json +++ b/helpers/content/tutorials.json @@ -42,13 +42,18 @@ }, { "id": "21921821", - "title": "Kurse duplizieren (klonen)", + "title": "Kurse kopieren (klonen)", "type": "article" }, { "id": "39387173", "title": "Kurse teilen und importieren", "type": "article" + }, + { + "id": "178658305", + "title": "Kurse sortieren", + "type": "article" } ] }, @@ -71,6 +76,16 @@ "id": "13828893", "title": "Themen teilen und importieren", "type": "article" + }, + { + "id": "246055834", + "title": "Themen kopieren", + "type": "article" + }, + { + "id": "270827606", + "title": "Spalten-Board", + "type": "article" } ] }, @@ -103,6 +118,16 @@ "id": "13829061", "title": "Aufgaben abgeben", "type": "article" + }, + { + "id": "246055003", + "title": "Aufgaben kopieren", + "type": "article" + }, + { + "id": "254476906", + "title": "Aufgaben teilen", + "type": "article" } ] }, @@ -126,15 +151,30 @@ "title": "An Videokonferenzen teilnehmen", "type": "article" }, + { + "id": "170594138", + "title": "In Videokonferenzen präsentieren", + "type": "article" + }, { "id": "113653222", "title": "Videokonferenzen moderieren", "type": "article" }, + { + "id": "170596102", + "title": "Technische Probleme während Videokonferenzen", + "type": "article" + }, { "id": "123409850", "title": "Umfragen in Videokonferenzen", "type": "article" + }, + { + "id": "215516270", + "title": "Externe Personen in Videokonferenzen", + "type": "article" } ] }, @@ -155,6 +195,12 @@ "title": "Texteditor", "type": "category", "articles": [] + }, + { + "id": "148537453", + "title": "Bettermarks", + "type": "category", + "articles": [] } ] }, @@ -213,7 +259,12 @@ "articles": [ { "id": "98598995", - "title": "Browser konfigurieren", + "title": "Browser konfigurieren mit Windows", + "type": "article" + }, + { + "id": "170593514", + "title": "Browser konfigurieren mit mac OS/OS X", "type": "article" }, { @@ -226,6 +277,11 @@ "title": "Teams für Schüler:innen aktivieren", "type": "article" }, + { + "id": "223674916", + "title": "Teams bearbeiten Verwaltung", + "type": "article" + }, { "id": "113640783", "title": "Moodle-Hinweise für Schulen", @@ -260,6 +316,26 @@ "id": "123407609", "title": "E-Mail-Adressen ungültig machen (Schulwechsel)", "type": "article" + }, + { + "id": "154188767", + "title": "Schulweit Sprache ändern", + "type": "article" + }, + { + "id": "196739599", + "title": "Migrationsprozess", + "type": "article" + }, + { + "id": "236650836", + "title": "Migrationsprozess in der dBildungscloud", + "type": "article" + }, + { + "id": "246055610", + "title": "Externe Tools anbinden und verwalten", + "type": "article" } ] }, @@ -359,7 +435,7 @@ }, { "id": "130778703", - "title": "Sprache ändern", + "title": "Sprache ändern / Change language / Cambiar idioma", "type": "article" } ] @@ -409,6 +485,12 @@ "title": "Schuljahreswechsel", "type": "category", "articles": [] + }, + { + "id": "214237489", + "title": "Dateien in Nextcloud", + "type": "category", + "articles": [] } ] } From f5ba4b8b3265d649fcf50f1c973d6c8409fbf86b Mon Sep 17 00:00:00 2001 From: mamutmk5 <3045922+mamutmk5@users.noreply.github.com> Date: Fri, 8 Sep 2023 14:12:49 +0200 Subject: [PATCH 2/5] BC-5100 - Pin docker/build-push-action to version 4.1.1 (#3299) * BC-5100 - Pin docker/build-push-action to version 4.1.1 for push workflow * BC-5100 - Pin docker/build-push-action to version 4.1.1 for tag workflow --- .github/workflows/push.yml | 2 +- .github/workflows/tag.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index f57068274c..1a5a0c63c6 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -62,7 +62,7 @@ jobs: - name: Build and push ${{ github.repository }} if: ${{ env.IMAGE_EXISTS == 0 }} - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v4.1.1 with: build-args: | SC_THEME_BUILD=${{ matrix.tenants }} diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml index 622d3841d3..3ea9fb7054 100644 --- a/.github/workflows/tag.yml +++ b/.github/workflows/tag.yml @@ -42,7 +42,7 @@ jobs: password: ${{ secrets.QUAY_TOKEN }} - name: Build and push ${{ github.repository }} - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v4.1.1 with: build-args: | SC_THEME_BUILD=${{ matrix.tenants }} From ec32b27bdbba7b8d8cc0c5046953f7cabca0f05f Mon Sep 17 00:00:00 2001 From: davwas Date: Fri, 8 Sep 2023 14:46:49 +0200 Subject: [PATCH 3/5] BC-4965 - Remove consent reference from student visibility toggle info text for BRB instance (#3297) *add instance specific translation key in old admin page --- locales/de.json | 1 + locales/en.json | 1 + locales/es.json | 1 + locales/uk.json | 3 ++- views/administration/school.hbs | 8 +++++++- 5 files changed, 12 insertions(+), 2 deletions(-) diff --git a/locales/de.json b/locales/de.json index c2fcaf7ca6..ad20240a86 100644 --- a/locales/de.json +++ b/locales/de.json @@ -567,6 +567,7 @@ "activeMatrixFunction": "Matrix Messenger aktivieren", "afterTheTransferPhaseEnded": "Nach Beenden der Transferphase", "allStudentsVisibility": "Die Aktivierung dieser Option hat datenschutzrechtlich eine hohe Schwelle. Um die Sichtbarkeit aller Schüler:innen der Schule für jede Lehrkraft zu aktivieren, ist es erforderlich, dass jede/r Schüler:in wirksam in diese Datenverarbeitung eingewilligt hat.", + "allStudentsVisibilityBrandenburg": "Die Aktivierung dieser Option schaltet die Sichtbarkeit aller Schüler:innen der Schule für jede Lehrkraft an.", "authentication": "Authentifizierung", "newPage": "Zur neuen Admin-Seite", "changeOfClasses": "Änderung von Klassen/neue Klassen", diff --git a/locales/en.json b/locales/en.json index 0b4e8a38c5..75c53c9b11 100644 --- a/locales/en.json +++ b/locales/en.json @@ -567,6 +567,7 @@ "activeMatrixFunction": "Activate Matrix Messenger", "afterTheTransferPhaseEnded": "After the transfer phase has ended", "allStudentsVisibility": "Activating this option has a high threshold under data protection law. In order to activate the visibility of all students in the school for each teacher, it is necessary that each student has effectively consented to this data processing.", + "allStudentsVisibilityBrandenburg": "Enabling this option turns on the visibility of all students of this school for each teacher.", "authentication": "Authentication", "newPage": "To the new admin page", "changeOfClasses": "Change of classes / new classes", diff --git a/locales/es.json b/locales/es.json index c5fcab5a68..96300336b1 100644 --- a/locales/es.json +++ b/locales/es.json @@ -567,6 +567,7 @@ "activeMatrixFunction": "Activar Matrix Messenger", "afterTheTransferPhaseEnded": "Una vez finalizada la fase de transferencia", "allStudentsVisibility": "La activación de esta opción tiene un nivel alto según la ley de protección de datos. Para activar la visibilidad de todos los alumnos de la escuela para cada profesor, es necesario que cada alumno haya dado su consentimiento de manera efectiva para este tratamiento de datos.", + "allStudentsVisibilityBrandenburg": "Activando esta opción se activa la visibilidad de todos los alumnos de esta escuela para cada profesor.", "authentication": "Autenticación", "newPage": "A la nueva página de administración", "changeOfClasses": "Cambio de clases / nuevas clases", diff --git a/locales/uk.json b/locales/uk.json index ffec1c2f2d..42c75d2931 100644 --- a/locales/uk.json +++ b/locales/uk.json @@ -896,7 +896,8 @@ "label": { "activeChatFunction": "Активувати функцію чату", "afterTheTransferPhaseEnded": "Після завершення фази переходу", - "allStudentsVisibility": "Активація цього варіанта має високий поріг згідно із законодавством про захист даних. Щоб активувати видимість усіх учнів у школі для кожного викладача, необхідно, щоб кожен учень дав фактичну згоду на таку обробку даних.", + "allStudentsVisibility": "Активація цієї опції має високе граничне значення згідно із законодавством про захист даних. Щоб активувати видимість усіх учнів у школі для кожного викладача, необхідно, щоб кожен учень надав свою фактичну згоду на таку обробку даних.", + "allStudentsVisibilityBrandenburg": "Увімкнення цієї опції вмикає видимість всіх учнів цієї школи для кожного вчителя.", "authentication": "Аутентифікація", "changeOfClasses": "Зміна класів / нові класи", "changeOfUserData": "Зміна даних користувача / нові користувачі", diff --git a/views/administration/school.hbs b/views/administration/school.hbs index 1266374f47..51f74c0248 100644 --- a/views/administration/school.hbs +++ b/views/administration/school.hbs @@ -258,7 +258,13 @@ {{$t "administration.school.label.studentVisibility" }} -

{{$t "administration.school.label.allStudentsVisibility" }}

+

+ {{#ifeq @root.theme.name "brb"}} + {{$t "administration.school.label.allStudentsVisibilityBrandenburg" }} + {{else}} + {{$t "administration.school.label.allStudentsVisibility" }} + {{/ifeq}} +

{{/ifConfig}} From 244ca00f9afdc5ca73943ed7f1da91804633062a Mon Sep 17 00:00:00 2001 From: mamutmk5 <3045922+mamutmk5@users.noreply.github.com> Date: Mon, 11 Sep 2023 11:33:36 +0200 Subject: [PATCH 4/5] BC-5101 - go back to docker/build-push-action@v4 (#3300) * BC-5101 - go back to docker/build-push-action@v4 for push workflow Remove lines who produce the malformed docker.config * BC-5101 - go back to docker/build-push-action@v4 for tag action --- .github/workflows/push.yml | 4 +--- .github/workflows/tag.yml | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 1a5a0c63c6..317bddc3c0 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -52,8 +52,6 @@ jobs: - name: test image exists run: | - mkdir -p ~/.docker - echo '{"experimental": "enabled"}' >> ~/.docker/config.json echo "IMAGE_EXISTS=$(docker manifest inspect ghcr.io/${{ github.repository }}-${{ matrix.tenants }}:${{ needs.branch_meta.outputs.sha }} > /dev/null && echo 1 || echo 0)" >> $GITHUB_ENV - name: Set up Docker Buildx @@ -62,7 +60,7 @@ jobs: - name: Build and push ${{ github.repository }} if: ${{ env.IMAGE_EXISTS == 0 }} - uses: docker/build-push-action@v4.1.1 + uses: docker/build-push-action@v4 with: build-args: | SC_THEME_BUILD=${{ matrix.tenants }} diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml index 3ea9fb7054..622d3841d3 100644 --- a/.github/workflows/tag.yml +++ b/.github/workflows/tag.yml @@ -42,7 +42,7 @@ jobs: password: ${{ secrets.QUAY_TOKEN }} - name: Build and push ${{ github.repository }} - uses: docker/build-push-action@v4.1.1 + uses: docker/build-push-action@v4 with: build-args: | SC_THEME_BUILD=${{ matrix.tenants }} From 2b633a71caed7a85b4590d83286bca91244575b8 Mon Sep 17 00:00:00 2001 From: davwas Date: Wed, 13 Sep 2023 17:58:46 +0200 Subject: [PATCH 5/5] BC-4938 - Add school specific Terms of Use for new school admin page (#3301) * add new translations * add new /termsofuse controller and links * update terms of use links * change /datenschutz to /privacypolicy --- .../templates/client-configmap-files.yml.j2 | 2 +- config/http-headers.js | 2 +- controllers/dataprivacy.js | 50 +++---------------- controllers/firstLogin.js | 11 ++-- controllers/index.js | 3 +- controllers/registration.js | 28 +++++++---- controllers/termsofuse.js | 33 ++++++++++++ helpers/consentVersionHelper.js | 24 +++++++++ helpers/fileHelper.js | 28 +++++++++++ locales/de.json | 5 +- locales/en.json | 5 +- locales/es.json | 5 +- locales/uk.json | 5 +- theme/brb/views/lib/extended_footer.hbs | 4 +- theme/brb/views/lib/footer.hbs | 4 +- theme/n21/views/lib/extended_footer.hbs | 4 +- theme/n21/views/lib/footer.hbs | 4 +- theme/thr/views/lib/extended_footer.hbs | 4 +- theme/thr/views/lib/footer.hbs | 4 +- views/firstLogin/sections/consent_updates.hbs | 4 +- views/lib/extended_footer.hbs | 4 +- views/lib/footer.hbs | 4 +- .../forms/einwilligungserklaerung.hbs | 6 ++- 23 files changed, 156 insertions(+), 87 deletions(-) create mode 100644 controllers/termsofuse.js create mode 100644 helpers/consentVersionHelper.js create mode 100644 helpers/fileHelper.js diff --git a/ansible/roles/schulcloud-client-core/templates/client-configmap-files.yml.j2 b/ansible/roles/schulcloud-client-core/templates/client-configmap-files.yml.j2 index e3743bfbbe..14ced4a1e3 100644 --- a/ansible/roles/schulcloud-client-core/templates/client-configmap-files.yml.j2 +++ b/ansible/roles/schulcloud-client-core/templates/client-configmap-files.yml.j2 @@ -97,7 +97,7 @@ data: }, '^/impressum': { }, - '^/datenschutz': { + '^/privacypolicy': { }, */ '^/about': { defaultSrc: 'https://www10-fms.hpi.uni-potsdam.de https://cloud-instances.s3.hidrive.strato.com https://s3.hidrive.strato.com', diff --git a/config/http-headers.js b/config/http-headers.js index 0961d28c82..95d2e360a6 100644 --- a/config/http-headers.js +++ b/config/http-headers.js @@ -80,7 +80,7 @@ const config = { }, '^/impressum': { }, - '^/datenschutz': { + '^/privacypolicy': { }, */ '^/about': { defaultSrc: 'https://www10-fms.hpi.uni-potsdam.de https://cloud-instances.s3.hidrive.strato.com', diff --git a/controllers/dataprivacy.js b/controllers/dataprivacy.js index d3d926d8fe..562e5813c0 100644 --- a/controllers/dataprivacy.js +++ b/controllers/dataprivacy.js @@ -1,60 +1,22 @@ const express = require('express'); const { URL } = require('url'); -const api = require('../api'); -const authHelper = require('../helpers/authentication'); const { DOCUMENT_BASE_DIR, SC_THEME } = require('../config/global'); const { specificFiles } = require('../config/documents'); +const { getBase64File } = require('../helpers/fileHelper'); +const { getConsentVersion } = require('../helpers/consentVersionHelper'); const router = express.Router(); -const privacyUrl = () => { - return new URL(`${SC_THEME}/${specificFiles.privacyExemplary}`, DOCUMENT_BASE_DIR); -}; - -const downloadPolicyPdf = (res, fileData, fileTitle) => { - // ERR_INVALID_CHAR will get thrown on ukrainian translation without encoding - const encodedFileTitle = encodeURI(fileTitle); - const download = Buffer.from(fileData, 'base64'); - res.writeHead(200, { - 'Content-Type': 'application/pdf', - 'Content-Disposition': `attachment; filename="${encodedFileTitle}.pdf"`, - }).end(download); -}; - -const getBase64File = async (req, res, fileId, fileTitle) => { - if (fileId) { - const base64File = await api(req).get(`/base64Files/${fileId}`); - if (base64File.data) { - const fileData = base64File.data.replace( - 'data:application/pdf;base64,', - '', - ); - downloadPolicyPdf(res, fileData, fileTitle); - } - } -}; +const privacyUrl = () => new URL(`${SC_THEME}/${specificFiles.privacyExemplary}`, DOCUMENT_BASE_DIR); router.get('/', async (req, res, next) => { try { - const isAuthenticated = await authHelper.isAuthenticated(req); - const qs = { - $limit: 1, - consentTypes: 'privacy', - $sort: { - publishedAt: -1, - }, - }; - - if (isAuthenticated && res.locals.currentSchool) { - qs.schoolId = res.locals.currentSchool; - } - - const consentVersions = await api(req).get('/consentVersions', { qs }); + const consentVersions = await getConsentVersion(req, res, 'privacy'); if (consentVersions.data.length) { const fileId = consentVersions.data[0].consentDataId; if (!fileId) { - res.redirect(privacyUrl()); + res.redirect(privacyUrl().toString()); } const fileTitle = res.locals.theme.name === 'thr' @@ -63,7 +25,7 @@ router.get('/', async (req, res, next) => { await getBase64File(req, res, fileId, fileTitle); } else { - res.redirect(privacyUrl()); + res.redirect(privacyUrl().toString()); } } catch (err) { next(err); diff --git a/controllers/firstLogin.js b/controllers/firstLogin.js index 9140f9b838..89e79bb008 100644 --- a/controllers/firstLogin.js +++ b/controllers/firstLogin.js @@ -29,10 +29,14 @@ const hasAccount = (req, res) => api(req).get('/consents', { }, }); -const getSchoolPrivacy = async (req, res) => { +const getSchoolConsentVersionByType = async (req, res, consentType) => { + if (consentType !== 'privacy' && consentType !== 'termsOfUse') { + return undefined; + } + const qs = { schoolId: res.locals.currentUser.schoolId, - consentTypes: ['privacy'], + consentTypes: [consentType], consentDataId: { $exists: true }, $limit: 1, $sort: { @@ -249,7 +253,8 @@ router.get('/', async (req, res, next) => { sso: !!(res.locals.currentPayload || {}).systemId, now: Date.now(), sections: sections.map((name) => `firstLogin/sections/${name}`), - schoolPrivacyLink: await getSchoolPrivacy(req, res), + schoolPrivacyLink: await getSchoolConsentVersionByType(req, res, 'privacy'), + schoolTermsLink: await getSchoolConsentVersionByType(req, res, 'termsOfUse'), schoolPrivacyName: res.$t('global.text.dataProtection'), submitPageIndex, userConsent, diff --git a/controllers/index.js b/controllers/index.js index b608184b85..c885f5e596 100644 --- a/controllers/index.js +++ b/controllers/index.js @@ -33,7 +33,8 @@ router.use('/partner/', require('./partner')); router.use('/community/', require('./community')); router.use('/about/', require('./about')); router.use('/help/', require('./help')); -router.use('/datenschutz/', require('./dataprivacy')); +router.use('/privacypolicy/', require('./dataprivacy')); +router.use('/termsofuse/', require('./termsofuse')); router.use('/my-material', require('./my-material')); router.use('/base64Files', require('./base64Files')); router.use('/logs', require('./logs')); diff --git a/controllers/registration.js b/controllers/registration.js index 722a58cb1a..2fa0dfdbed 100644 --- a/controllers/registration.js +++ b/controllers/registration.js @@ -49,11 +49,11 @@ const checkValidRegistration = async (req) => { */ router.get(['/register', '/register/*'], (req, res, next) => res.render('registration/deprecated_warning')); -const getSchoolPrivacy = async (req, res) => { +const getSchoolConsentVersionByType = async (req, res, consentType) => { const importHash = getImportHash(req); try { - const consentVersion = await api(req).get(`/registration/consent/${importHash}`); + const consentVersion = await api(req).get(`/registration/consent/${importHash}?consentType=${consentType}`); if (consentVersion) { const { consentDataId } = consentVersion; return consentDataId ? `/base64Files/${consentDataId}` : undefined; @@ -251,8 +251,10 @@ router.get(['/registration/:classOrSchoolId/byparent', '/registration/:classOrSc hideMenu: true, user, needConsent, - schoolPrivacyLink: await getSchoolPrivacy(req, res), - schoolPrivacyName: res.$t('global.text.dataProtection'), + schoolPrivacyLink: await getSchoolConsentVersionByType(req, res, 'privacy'), + schoolTermsLink: await getSchoolConsentVersionByType(req, res, 'termsOfUse'), + schoolPrivacyName: res.$t('global.text.dataProtectionFile'), + schoolTermsName: res.$t('global.text.termsOfUseFile'), sectionNumber, CONSENT_WITHOUT_PARENTS_MIN_AGE_YEARS, invalid, @@ -317,8 +319,10 @@ router.get(['/registration/:classOrSchoolId/bystudent', '/registration/:classOrS user, needConsent, sectionNumber, - schoolPrivacyLink: await getSchoolPrivacy(req, res), - schoolPrivacyName: res.$t('global.text.dataProtection'), + schoolPrivacyLink: await getSchoolConsentVersionByType(req, res, 'privacy'), + schoolTermsLink: await getSchoolConsentVersionByType(req, res, 'termsOfUse'), + schoolPrivacyName: res.$t('global.text.dataProtectionFile'), + schoolTermsName: res.$t('global.text.termsOfUseFile'), CONSENT_WITHOUT_PARENTS_MIN_AGE_YEARS, invalid, secure, @@ -393,8 +397,10 @@ router.get(['/registration/:classOrSchoolId/:byRole'], async (req, res) => { user, needConsent, sectionNumber, - schoolPrivacyLink: await getSchoolPrivacy(req, res), - schoolPrivacyName: res.$t('global.text.dataProtection'), + schoolPrivacyLink: await getSchoolConsentVersionByType(req, res, 'privacy'), + schoolTermsLink: await getSchoolConsentVersionByType(req, res, 'termsOfUse'), + schoolPrivacyName: res.$t('global.text.dataProtectionFile'), + schoolTermsName: res.$t('global.text.termsOfUseFile'), invalid, secure, correctID, @@ -432,8 +438,10 @@ router.get(['/registration/:classOrSchoolId', '/registration/:classOrSchoolId/:s sso: req.params.sso === 'sso', account: req.params.accountId || '', CONSENT_WITHOUT_PARENTS_MIN_AGE_YEARS, - schoolPrivacyLink: await getSchoolPrivacy(req, res), - schoolPrivacyName: res.$t('global.text.dataProtection'), + schoolPrivacyLink: await getSchoolConsentVersionByType(req, res, 'privacy'), + schoolTermsLink: await getSchoolConsentVersionByType(req, res, 'termsOfUse'), + schoolPrivacyName: res.$t('global.text.dataProtectionFile'), + schoolTermsName: res.$t('global.text.termsOfUseFile'), invalid, secure, correctID, diff --git a/controllers/termsofuse.js b/controllers/termsofuse.js new file mode 100644 index 0000000000..4060a1435f --- /dev/null +++ b/controllers/termsofuse.js @@ -0,0 +1,33 @@ +const express = require('express'); +const { URL } = require('url'); +const { DOCUMENT_BASE_DIR, SC_THEME } = require('../config/global'); +const { specificFiles } = require('../config/documents'); +const { getBase64File } = require('../helpers/fileHelper'); +const { getConsentVersion } = require('../helpers/consentVersionHelper'); + +const router = express.Router(); + +const termsUrl = () => new URL(`${SC_THEME}/${specificFiles.termsOfUseSchool}`, DOCUMENT_BASE_DIR); + +router.get('/', async (req, res, next) => { + try { + const consentVersions = await getConsentVersion(req, res, 'termsOfUse'); + + if (consentVersions.data.length) { + const fileId = consentVersions.data[0].consentDataId; + if (!fileId) { + res.redirect(termsUrl().toString()); + } + + const fileTitle = res.$t('global.text.termsOfUseFile'); + + await getBase64File(req, res, fileId, fileTitle); + } else { + res.redirect(termsUrl().toString()); + } + } catch (err) { + next(err); + } +}); + +module.exports = router; diff --git a/helpers/consentVersionHelper.js b/helpers/consentVersionHelper.js new file mode 100644 index 0000000000..42683c07e4 --- /dev/null +++ b/helpers/consentVersionHelper.js @@ -0,0 +1,24 @@ +const api = require('../api'); +const authHelper = require('./authentication'); + +const getConsentVersion = async (req, res, consentType) => { + const isAuthenticated = await authHelper.isAuthenticated(req); + const qs = { + $limit: 1, + consentTypes: [consentType], + $sort: { + publishedAt: -1, + }, + }; + + if (isAuthenticated && res.locals.currentSchool) { + qs.schoolId = res.locals.currentSchool; + } + + const consentVersion = await api(req).get('/consentVersions', { qs }); + return consentVersion; +}; + +module.exports = { + getConsentVersion, +}; diff --git a/helpers/fileHelper.js b/helpers/fileHelper.js new file mode 100644 index 0000000000..924b2e49cb --- /dev/null +++ b/helpers/fileHelper.js @@ -0,0 +1,28 @@ +const api = require('../api'); + +const downloadAsPdf = (res, fileData, fileTitle) => { + // ERR_INVALID_CHAR will get thrown on ukrainian translation without encoding + const encodedFileTitle = encodeURI(fileTitle); + const download = Buffer.from(fileData, 'base64'); + res.writeHead(200, { + 'Content-Type': 'application/pdf', + 'Content-Disposition': `attachment; filename="${encodedFileTitle}.pdf"`, + }).end(download); +}; + +const getBase64File = async (req, res, fileId, fileTitle) => { + if (fileId) { + const base64File = await api(req).get(`/base64Files/${fileId}`); + if (base64File.data) { + const fileData = base64File.data.replace( + 'data:application/pdf;base64,', + '', + ); + downloadAsPdf(res, fileData, fileTitle); + } + } +}; + +module.exports = { + getBase64File, +}; diff --git a/locales/de.json b/locales/de.json index ad20240a86..a921a0acce 100644 --- a/locales/de.json +++ b/locales/de.json @@ -1458,7 +1458,6 @@ "i": "Ich,", "pleaseClickOnRead": "Bitte nimm mit Klick auf „Gelesen” diese Informationen zur Kenntnis, um mit der Nutzung fortzufahren.", "pleaseConfirmTheFollowingDeclarationOfConsent": "Bitte bestätige folgende Einwilligungserklärungen, damit du die {{title}} nutzen kannst.", - "termsOfUse": "Nutzungsordnung", "the": "die" } }, @@ -1771,6 +1770,8 @@ "dataProtectionThr": "Datenschutzhinweise", "dataProtectionFile": "Datenschutzerklärung der Schule", "dataProtectionFileThr": "Datenschutzhinweise der Schule", + "termsOfUse": "Nutzungsordnung", + "termsOfUseFile": "Nutzungsordnung der Schule", "emailDomainBlocked": "Dieser Mailprovider wird nicht mehr unterstützt. Bitte wende dich an deinen Schul-Admin.", "errorChangingFilePermissions": "Problem beim Ändern der Berechtigungen", "errorWhileLoadingPage": "Diese Seite konnte nicht geladen werden", @@ -2861,7 +2862,7 @@ }, "text": { "acceptConsentWithoutParents": "Wenn du zwischen 14 und {{age}} Jahre alt bist, bestätige bitte zusätzlich die Einverständniserklärung, damit du die {{title}} nutzen kannst.", - "agreeTermsOfUse": "Ich habe die Nutzungsordnung der {{title}} gelesen und stimme ihr zu.", + "agreeTermsOfUse": "Ich habe die Nutzungsordnung der {{title}} gelesen und stimme ihr zu.", "andAuthorisedToRepresent": "und berechtigt, den anderen Elternteil bei den nachfolgenden Erklärungen zu vertreten.", "iAgreeThatThepersonalData": "Ich erkläre mich damit einverstanden, dass die personenbezogenen Daten meines Kindes entsprechend der", "invalidLink": "Der Link ist leider nicht mehr gültig. Fordere einen neuen Link von deiner Lehrkraft oder dem Schul-Admin an.", diff --git a/locales/en.json b/locales/en.json index 75c53c9b11..4af8129adf 100644 --- a/locales/en.json +++ b/locales/en.json @@ -1458,7 +1458,6 @@ "i": "I,", "pleaseClickOnRead": "Please acknowledge this information by clicking on „Read” in order to proceed with the use.", "pleaseConfirmTheFollowingDeclarationOfConsent": "Please confirm the following declarations of consent so that you can use the {{title}}.", - "termsOfUse": "Terms of Use", "the": "the" } }, @@ -1771,6 +1770,8 @@ "dataProtectionThr": "Privacy Policy", "dataProtectionFile": "Privacy Policy of School", "dataProtectionFileThr": "Privacy Policy of School", + "termsOfUse": "Terms of Use", + "termsOfUseFile": "Terms of Use of School", "emailDomainBlocked": "This mail provider is no longer supported. Please contact your school administrator.", "errorChangingFilePermissions": "Problem changing permissions", "errorWhileLoadingPage": "This page could not be loaded", @@ -2861,7 +2862,7 @@ }, "text": { "acceptConsentWithoutParents": "If you are between 14 and {{age}} years old, please also confirm the declaration of consent so that you can use the {{title}}.", - "agreeTermsOfUse": "I have read and agree to the Terms of Use of the {{title}}.", + "agreeTermsOfUse": "I have read and agree with the school's Terms of Use of the {{title}}.", "andAuthorisedToRepresent": "and entitled to represent the other parent in the following declarations.", "iAgreeThatThepersonalData": "I consent to my child's personal data being processed in accordance with the", "invalidLink": "Unfortunately the link is no longer valid. Request a new link from your teacher or school administrator.", diff --git a/locales/es.json b/locales/es.json index 96300336b1..4d3dc8d397 100644 --- a/locales/es.json +++ b/locales/es.json @@ -1458,7 +1458,6 @@ "i": "Yo,", "pleaseClickOnRead": "Acepta esta información haciendo clic en \"Leer\" para continuar con el uso.", "pleaseConfirmTheFollowingDeclarationOfConsent": "Confirma las siguientes declaraciones de consentimiento para que puedas utilizar {{title}}.", - "termsOfUse": "Condiciones de uso", "the": "el" } }, @@ -1771,6 +1770,8 @@ "dataProtectionThr": "Política de Privacidad", "dataProtectionFile": "Política de Privacidad de la Escuela", "dataProtectionFileThr": "Política de Privacidad de la Escuela", + "termsOfUse": "Condiciones de Uso", + "termsOfUseFile": "Condiciones de Uso de la Escuela", "emailDomainBlocked": "Este proveedor de correo ya no es compatible. Ponte en contacto con el administrador de tu escuela.", "errorChangingFilePermissions": "Hay un problema para cambiar los permisos", "errorWhileLoadingPage": "Esta página no se ha podido cargar", @@ -2861,7 +2862,7 @@ }, "text": { "acceptConsentWithoutParents": "Si tienes entre 14 y {{age}} años, confirma también la declaración de consentimiento para que puedas utilizar {{title}}.", - "agreeTermsOfUse": "He leído y acepto las Condiciones de uso de {{title}}.", + "agreeTermsOfUse": "He leído y acepto las Condiciones de Uso de {{title}}.", "andAuthorisedToRepresent": "y con derecho a representar al otro padre en las siguientes declaraciones.", "iAgreeThatThepersonalData": "Doy mi consentimiento para que los datos personales de mi hijo sean procesados de acuerdo con la", "invalidLink": "Desafortunadamente el enlace ya no es válido. Solicita un nuevo enlace a tu profesor o al administrador de la escuela.", diff --git a/locales/uk.json b/locales/uk.json index 42c75d2931..859b3c1c5d 100644 --- a/locales/uk.json +++ b/locales/uk.json @@ -130,6 +130,8 @@ "dataProtectionThr": "Політика конфіденційності", "dataProtectionFile": "Політика конфіденційності школи", "dataProtectionFileThr": "Політика конфіденційності школи", + "termsOfUse": "Умови використання", + "termsOfUseFile": "Умови використання школи", "emailDomainBlocked": "Цей постачальник пошти більше не підтримується. Будь ласка, зв’яжіться з адміністратором школи.", "errorChangingFilePermissions": "Проблема зі зміною дозволів", "fileTooLarge": "Вкладені файли перевищують максимально дозволений розмір — {{ maxFileSizeInGb }} Гб!", @@ -2447,7 +2449,7 @@ "unknownError": "Ой, сталася невідома помилка. Спробуйте ще раз.", "welcomeMailSubject": "Ласкаво просимо до {{title}}!", "welcomeMailText": "Вітаємо, {{firstName}}!\n Ви можете ввійти до {{title}}, використовуючи такі дані для входу в систему:\n Адреса: {{address}}\n Електронна пошта: {{email}}\n {{password}}\n {{infotext}}\n Ваша\n команда {{shortTitle}} бажає вам веселощів та гарного початку", - "agreeTermsOfUse": "Я прочитав і погоджуюся з Умовами використання{{title}}.", + "agreeTermsOfUse": "Я прочитав і погоджуюся з Умовами використання школи {{title}}.", "invalidLink": "На жаль, посилання більше не дійсне. Попросіть нове посилання у свого викладача або адміністратора школи.", "invalidLinkEmbeddedWebsite": "Шкільна хмара була вбудована у веб-сайт. Щоби продовжити ", "invalidLinkOpenWebsite": "Відкрийте цю сторінку в окремому вікні" @@ -3039,7 +3041,6 @@ "i": "Я,", "pleaseClickOnRead": "Підтвердьте цю інформацію, натиснувши «Прочитати», щоб продовжити використання.", "pleaseConfirmTheFollowingDeclarationOfConsent": "Підтвердьте наведені нижче заяви про згоду, щоб ви могли використовувати {{title}}.", - "termsOfUse": "Умови використання", "the": "це" }, "headline": { diff --git a/theme/brb/views/lib/extended_footer.hbs b/theme/brb/views/lib/extended_footer.hbs index c81bfe073b..d960afabae 100644 --- a/theme/brb/views/lib/extended_footer.hbs +++ b/theme/brb/views/lib/extended_footer.hbs @@ -26,11 +26,11 @@

{{$t "lib.extended_footer.headline.links"}}