diff --git a/package-lock.json b/package-lock.json index dabbee0d..9378e681 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,18 @@ { "name": "betterlectio", - "version": "0.10.136", + "version": "1.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "betterlectio", - "version": "0.10.136", + "version": "1.1.0", "dependencies": { "@event-calendar/core": "^1.5.0", "@event-calendar/time-grid": "^1.5.0", "@netlify/functions": "^2.4.0", "@sentry/sveltekit": "^7.80.0", + "chartjs-plugin-datalabels": "^2.2.0", "crypto-es": "^2.1.0", "dompurify": "^3.0.5", "firebase": "^10.6.0", @@ -2104,6 +2105,14 @@ "pnpm": "^7.0.0" } }, + "node_modules/chartjs-plugin-datalabels": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-2.2.0.tgz", + "integrity": "sha512-14ZU30lH7n89oq+A4bWaJPnAG8a7ZTk7dKf48YAzMvJjQtjrgg5Dpk9f+LbjCF6bpx3RAGTeL13IXpKQYyRvlw==", + "peerDependencies": { + "chart.js": ">=3.0.0" + } + }, "node_modules/chokidar": { "version": "3.5.3", "funding": [ @@ -6572,6 +6581,12 @@ "@kurkle/color": "^0.3.0" } }, + "chartjs-plugin-datalabels": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-2.2.0.tgz", + "integrity": "sha512-14ZU30lH7n89oq+A4bWaJPnAG8a7ZTk7dKf48YAzMvJjQtjrgg5Dpk9f+LbjCF6bpx3RAGTeL13IXpKQYyRvlw==", + "requires": {} + }, "chokidar": { "version": "3.5.3", "requires": { diff --git a/package.json b/package.json index 052688a8..a863e45b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "betterlectio", - "version": "0.10.139", + "version": "1.1.5", "private": true, "scripts": { "dev": "vite dev", @@ -36,6 +36,7 @@ "@event-calendar/time-grid": "^1.5.0", "@netlify/functions": "^2.4.0", "@sentry/sveltekit": "^7.80.0", + "chartjs-plugin-datalabels": "^2.2.0", "crypto-es": "^2.1.0", "dompurify": "^3.0.5", "firebase": "^10.6.0", diff --git a/src/lib/js/globalConfig.js b/src/lib/js/globalConfig.js new file mode 100644 index 00000000..86bfc8c1 --- /dev/null +++ b/src/lib/js/globalConfig.js @@ -0,0 +1,71 @@ +import { get, post } from '$lib/js/http.js'; +import { cookieInfo } from '$lib/js/LectioCookieHandler'; +import { writable } from 'svelte/store'; + +let configNonce = Date.now().toString(36); +let betlecMappeId = null; +let betlecConfigId = null; + +async function setConfig(value, overwrite = true) { + console.log('Opdaterer config filen'); + const body = { + fileName: 'config.json', + folderId: betlecMappeId, + contentType: 'application/json', + content: JSON.stringify(value), + fileComment: 'Denne fil er autogenereret af BetterLectio. Hvis du fjerner den kan du risikere at alle dine indstillinger på BetterLectio fjernes.', + public: false + }; + if (overwrite) body.documentId = betlecConfigId; + await post('/dokument_upload', JSON.stringify(body)); +} + +const writableConfig = () => { + const { subscribe, set, update } = writable(undefined); + + return { + subscribe, + set: value => { + if (value) setConfig(value); + return set(value); + }, + update + }; +}; +export const config = writableConfig(); + +async function getConfig() { + configNonce = await Date.now().toString(36); + if (!betlecMappeId) { + const user = await cookieInfo(); + const dokumenter = await get(`/dokumenter?folderid=S${user.userId}__&nonce=${configNonce}`); + const betlecMappe = dokumenter.indhold.filter(dokument => dokument.navn === '.betterlectio'); + if (betlecMappe.length > 0) { + betlecMappeId = betlecMappe[0].id; + } else { + console.log('Opretter mappen'); + await post('/opret_mappe', JSON.stringify({ + folderName: '.betterlectio', + folderComment: 'Denne mappe er autogenereret af BetterLectio. Hvis du fjerner den kan du risikere at alle dine indstillinger, themes og plugins på BetterLectio fjernes.', + folderId: `S${user.userId}__` + })); + getConfig(); + return; + } + } + + const betlecMappeDokumenter = await get(`/dokumenter?folderid=${betlecMappeId}&nonce=${configNonce}`); + const _betlecConfigId = betlecMappeDokumenter.indhold.filter(dokument => dokument.navn === 'config.json'); + if (_betlecConfigId.length > 0) { + betlecConfigId = _betlecConfigId[0].id; + console.log(betlecConfigId); + } else { + console.log('Opretter config fil'); + await setConfig({}, false); + getConfig(); + return; + } + + config.set(await get(`/dokument_hent?id=${betlecConfigId}&configNonce=${configNonce}`)); +} +getConfig(); diff --git a/src/lib/js/http.js b/src/lib/js/http.js index 6a481142..33414a42 100644 --- a/src/lib/js/http.js +++ b/src/lib/js/http.js @@ -94,3 +94,22 @@ export async function post(endpoint, body) { const response = await get(endpoint, body); return response; } + + +export async function getDocument(id, docType = null, expectedContentType = 'image/*') { + let url = `${api}/dokument_hent?id=${id}`; + if (docType) url += `&doctype=${docType}&raw=true`; + const response = await fetch(url, + { + headers: + { + 'lectio-cookie': localStorage.getItem('lectio-cookie'), + 'Access-Control-Allow-Origin': '*', + 'content-type': expectedContentType + } + }, { method: 'GET' }); + + const blob = await response.blob(); + const urlBlob = URL.createObjectURL(blob); + return urlBlob; +} diff --git a/src/routes/auth/+page.server.js b/src/routes/auth/+page.server.js index 8e836ce6..d28e2fea 100644 --- a/src/routes/auth/+page.server.js +++ b/src/routes/auth/+page.server.js @@ -1,7 +1,7 @@ import { fail, redirect } from '@sveltejs/kit'; import { superValidate } from 'sveltekit-superforms/server'; -import { z } from 'zod'; import { validCookie } from '$lib/js/serverCookies.js'; +import { z } from 'zod'; const schema = z.object({ @@ -11,7 +11,8 @@ const schema = z.object({ id: z.string().min(2).max(4), skole: z.string().min(2).max(268), skoleid: z.string().min(2).max(4) - }) + }), + remember: z.boolean().optional() }); export const load = (async ({ cookies, url }) => { @@ -24,6 +25,50 @@ export const load = (async ({ cookies, url }) => { } } const form = await superValidate(schema); + + let persistantSession = cookies.get('persistant-session'); + if (persistantSession) { + persistantSession = JSON.parse(persistantSession); + form.data.username = persistantSession.username; + form.data.school = persistantSession.school; + + // login and redirect if valid + const response = await fetch(`https://api.betterlectio.dk/auth`, { + headers: { + brugernavn: persistantSession.username, + adgangskode: persistantSession.password, + skoleid: persistantSession.school.skoleid + } + }); + + if (response.ok) { + // get the set-lectio-cookie header + const lectioCookie = response.headers.get('set-lectio-cookie'); + + // set a cookie with the lectio cookie + cookies.set('lectio-cookie', lectioCookie, { + path: '/', + maxAge: 60 * 60 * 24 * 7 // 1 week + }); + + // if remember me is checked, set a persistant session cookie + if (form.data.remember) { + cookies.set('persistant-session', JSON.stringify({ + username: form.data.username, + password: form.data.password, + school: form.data.school + }), { + path: '/', + secure: true, + maxAge: 60 * 60 * 24 * 365 // 1 year + }); + } + + // redirect to the homepage (in future change to the page the user was on before logging in, but for now just redirect to the homepage because im lazy :) ) + throw redirect(302, '/forside'); + } + } + return { form }; }); @@ -59,6 +104,19 @@ export const actions = { return fail(401, { form }); } + // if remember me is checked, set a persistant session cookie + if (form.data.remember) { + cookies.set('persistant-session', JSON.stringify({ + username: form.data.username, + password: form.data.password, + school: form.data.school + }), { + path: '/', + secure: true, + maxAge: 60 * 60 * 24 * 365 // 1 year + }); + } + return { form }; } }; diff --git a/src/routes/auth/+page.svelte b/src/routes/auth/+page.svelte index 85f61115..a4e93aef 100644 --- a/src/routes/auth/+page.svelte +++ b/src/routes/auth/+page.svelte @@ -165,6 +165,20 @@ } + + + + +
{#key isInAutoAuth} {#if !isInAutoAuth} @@ -248,8 +262,8 @@ > -
-
+
+
- {#if api === 'http://localhost:5000'} -
-
- - -
- {/if} + +
+ + +

Denne side bruger cookies til at huske dine oplysninger til næste gang, du logger ind. Når du logger ind, accepterer du, at din diff --git a/src/routes/besked/+page.svelte b/src/routes/besked/+page.svelte index c39b5f89..3045ed88 100644 --- a/src/routes/besked/+page.svelte +++ b/src/routes/besked/+page.svelte @@ -1,5 +1,5 @@

-
+
{#each _besked.vedhæftninger as vedhæftning} - attemptPreviewAttachment(vedhæftning.href)}>{vedhæftning.navn} + {/each} + {#if !attachmentsHidden} + {#each _besked.vedhæftninger as vedhæftning} + attemptPreviewAttachment(vedhæftning.href)}>{vedhæftning.navn} + {/each} + {:else} + {#if MessageAttachments.length > 0} + + {/if} + {/if} + +
+
+ {#each MessageAttachments as attachment} +
+ +
+ +
+
+ {/each} +
+
+ {#if MessageAttachments.length > 0 || _besked.vedhæftninger.length > 0} +
+ {/if}

{@html sanitize(md.render(_besked.besked)).replace(' + let submissionStatus = null; + function handleSubmit(formEvent) { + // Perform any additional logic or validation here + + submissionStatus = 'submitting'; + fetch('https://docs.google.com/forms/d/e/1FAIpQLSeKEUooxFgla0U_mLkBldI3TYSW-4xHT3hPr7X8OmRR9lcruQ/formResponse', { + method: 'POST', + body: new FormData(formEvent.target), + mode: 'no-cors', + headers: { 'Access-Control-Allow-Origin': '*' } + }) + .then(response => { + // Handle the response as needed + console.log('Form submitted successfully'); + submissionStatus = 'success'; + }) + .catch(error => { + // Handle any errors that occurred during form submission + console.error('Form submission error:', error); + submissionStatus = 'error'; + }); + } + + +

+
+

+ Rapporter feil +

+

+ Har du fundet en fejl i BetterLectio eller har du et forslag til en ny funktion? Så kan du rapportere det her. +

+
+
+ + + + {#if submissionStatus} + {#if submissionStatus === 'submitting'} + + {:else if submissionStatus === 'success'} + + {:else if submissionStatus === 'error'} + + {/if} + {:else} + + {/if} +
+
+ +
+

Fejl rapportering sker gennem Google Forms. Du kan se alle deres vilkår og betingelser her.

+ diff --git a/src/routes/dokumenter/+page.svelte b/src/routes/dokumenter/+page.svelte index 07074b96..3efc4f15 100644 --- a/src/routes/dokumenter/+page.svelte +++ b/src/routes/dokumenter/+page.svelte @@ -1,7 +1,7 @@ + +{#if $config} +

{JSON.stringify($config)}

+ +{/if} \ No newline at end of file diff --git a/src/routes/indstillinger/+page.server.js b/src/routes/indstillinger/+page.server.js new file mode 100644 index 00000000..2a636a3b --- /dev/null +++ b/src/routes/indstillinger/+page.server.js @@ -0,0 +1,12 @@ +/** @type {import('./$types').PageServerLoad} */ +export async function load({ cookies, url }) { + // check if the cookie "persistant-session" exists + // if it does, return true + // if it doesn't, return false + + const persistantSession = cookies.get('persistant-session'); + if (persistantSession) return { persistantSession: true, persistantSessionUsername: JSON.parse(persistantSession).username }; + + + return { persistantSession: false }; +} diff --git a/src/routes/indstillinger/+page.svelte b/src/routes/indstillinger/+page.svelte index dc1ac1d7..bffb2e8c 100644 --- a/src/routes/indstillinger/+page.svelte +++ b/src/routes/indstillinger/+page.svelte @@ -6,10 +6,12 @@ // import Tilslut from './routes/Tilslut.svelte'; import Generelt from './routes/Generelt.svelte'; import { version } from '$app/environment'; + + export let data;
- +