diff --git a/README.md b/README.md index ad0dcce..00740cd 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,4 @@ # 🚀 Getting started with PomeloNote -### **THIS REPOSITORY HAS DEPENDENCIES WITH SECURITY VULNERABILITIES. YOU MIGHT WANT TO UPDATE PACKAGES BEFORE USE.** -## Setup -- run `npm i` -- get the .env file and save it to the root directory of the project -- set up Strapi - - go to `localhost:1337/admin` - - register an admin user - - go to Settings => Users&Permissions Plugin => Roles => Authenticated => Note => Select all - - Save ### Starting the container with svelte and strapi: ``docker-compose up --build -d`` diff --git a/backend/strapi/src/api/note/controllers/note.js b/backend/strapi/src/api/note/controllers/note.js index 84e7a8d..9cf8879 100644 --- a/backend/strapi/src/api/note/controllers/note.js +++ b/backend/strapi/src/api/note/controllers/note.js @@ -50,9 +50,6 @@ module.exports = createCoreController(noteUid, ({strapi}) => ({ lastViewed: Date.now() } }) - entry = await strapi.entityService.findOne(noteUid, noteId, { - populate: ['owners'], - }); return JSON.stringify(entry); } else { ctx.response.status = 403; @@ -66,26 +63,22 @@ module.exports = createCoreController(noteUid, ({strapi}) => ({ async update(ctx) { const noteId = getNoteIdFromUrl(ctx.request.url) const userId = ctx.state.user.id; - const requestBody = JSON.parse(ctx.request.body); - console.log(JSON.stringify(requestBody, null, 2)) + const requestBody = ctx.request.body; const entry = await strapi.entityService.findOne(noteUid, noteId, { populate: ['owners'], }); const authorized = entry.owners.some(owner => owner.id === userId) - let allPreviousOwnersKept = true; + let allPreviousOwnersKept = false; if (requestBody.data.hasOwnProperty("owners")) { allPreviousOwnersKept = entry.owners.every(owner => requestBody.data.owners.includes(owner)); } - console.log({ - "auth": authorized, - "allprev": allPreviousOwnersKept, - }) if (!authorized) { ctx.response.status = 403; } else if (!allPreviousOwnersKept) { ctx.response.status = 400; + } else { + return super.update(ctx); } - return await strapi.entityService.update(noteUid, noteId, requestBody); }, /** * Creates a new note, automatically sets owners to the user making the request and lastViewed diff --git a/backend/strapi/src/extensions/users-permissions/content-types/user/schema.json b/backend/strapi/src/extensions/users-permissions/content-types/user/schema.json deleted file mode 100644 index 7413352..0000000 --- a/backend/strapi/src/extensions/users-permissions/content-types/user/schema.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "kind": "collectionType", - "collectionName": "up_users", - "info": { - "name": "user", - "description": "", - "singularName": "user", - "pluralName": "users", - "displayName": "User" - }, - "options": { - "draftAndPublish": false, - "timestamps": true - }, - "attributes": { - "username": { - "type": "string", - "minLength": 3, - "unique": true, - "configurable": false, - "required": true - }, - "email": { - "type": "email", - "minLength": 6, - "configurable": false, - "required": true - }, - "provider": { - "type": "string", - "configurable": false - }, - "password": { - "type": "password", - "minLength": 6, - "configurable": false, - "private": true - }, - "resetPasswordToken": { - "type": "string", - "configurable": false, - "private": true - }, - "confirmationToken": { - "type": "string", - "configurable": false, - "private": true - }, - "confirmed": { - "type": "boolean", - "default": false, - "configurable": false - }, - "blocked": { - "type": "boolean", - "default": false, - "configurable": false - }, - "role": { - "type": "relation", - "relation": "manyToOne", - "target": "plugin::users-permissions.role", - "inversedBy": "users", - "configurable": false - }, - "notes": { - "type": "relation", - "relation": "manyToMany", - "target": "api::note.note", - "inversedBy": "owners" - } - } -} diff --git a/docs/_config.yml b/docs/_config.yml deleted file mode 100644 index 2e92aba..0000000 --- a/docs/_config.yml +++ /dev/null @@ -1,3 +0,0 @@ -remote_theme: pages-themes/leap-day@v0.2.0 -plugins: -- jekyll-remote-theme diff --git a/docs/_data/devs.csv b/docs/_data/devs.csv deleted file mode 100644 index 5c60b6c..0000000 --- a/docs/_data/devs.csv +++ /dev/null @@ -1,4 +0,0 @@ -name,github,image -Jonas Weissengruber,j-weissen,jowei -Stefan Prechtler,s-prechtl,stef -David Hain,d-hain,dave \ No newline at end of file diff --git a/docs/images/dave.jpg b/docs/images/dave.jpg deleted file mode 100644 index 9fe6268..0000000 Binary files a/docs/images/dave.jpg and /dev/null differ diff --git a/docs/images/delete.png b/docs/images/delete.png deleted file mode 100644 index 39ae1b5..0000000 Binary files a/docs/images/delete.png and /dev/null differ diff --git a/docs/images/editor.png b/docs/images/editor.png deleted file mode 100644 index 690ef69..0000000 Binary files a/docs/images/editor.png and /dev/null differ diff --git a/docs/images/jowei.jpg b/docs/images/jowei.jpg deleted file mode 100644 index 6785c8d..0000000 Binary files a/docs/images/jowei.jpg and /dev/null differ diff --git a/docs/images/listing.png b/docs/images/listing.png deleted file mode 100644 index 8b1189b..0000000 Binary files a/docs/images/listing.png and /dev/null differ diff --git a/docs/images/login.png b/docs/images/login.png deleted file mode 100644 index e9c1cbd..0000000 Binary files a/docs/images/login.png and /dev/null differ diff --git a/docs/images/register.png b/docs/images/register.png deleted file mode 100644 index 68336c8..0000000 Binary files a/docs/images/register.png and /dev/null differ diff --git a/docs/images/stef.jpg b/docs/images/stef.jpg deleted file mode 100644 index 231d3e3..0000000 Binary files a/docs/images/stef.jpg and /dev/null differ diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 7c87e05..0000000 --- a/docs/index.md +++ /dev/null @@ -1,31 +0,0 @@ -# Pomelo Note - -This is the best open source note app you will ever find. - -## Login -When first entering the app, you will need to login. If you haven't got an account you may consider [registering](#register), or just not using the app at all. -
- -## Register -A username, an email and a password that's all you need. If you are missing one of those, just don't use the app at all. -
- -## Editor -You can edit your notes with our minimalistic editor interface. -
- -## Listing -Here you can see all your notes. Click on them to open the editor or hover and press the red "X" to delete them. -
- -## Delete -Confirm the deletion. -
- -# The Team -{% for dev in site.data.devs %} - {{ dev.name }} - [GitHub](https://github.com/{{ dev.github }}) - ![{{ dev.name }}](images/{{ dev.image }}.jpg) -{% endfor %} - diff --git a/frontend/svelte/package-lock.json b/frontend/svelte/package-lock.json index d5c5126..63551ad 100644 --- a/frontend/svelte/package-lock.json +++ b/frontend/svelte/package-lock.json @@ -9,9 +9,7 @@ "version": "0.0.1", "dependencies": { "bootstrap-icons": "^1.9.1", - "nookies": "^2.5.2", - "sv-popup": "^0.2.5", - "webworker": "^0.8.4" + "nookies": "^2.5.2" }, "devDependencies": { "@sveltejs/adapter-auto": "next", @@ -2085,11 +2083,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sv-popup": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/sv-popup/-/sv-popup-0.2.5.tgz", - "integrity": "sha512-JhBu4piXaauamT4vMEcFCydvxJ8e72G7c9F3caZVAPsiFqWPTYT3JDz99FlR+YCnbOp1emsZqqOPVvCwHgURog==" - }, "node_modules/svelte": { "version": "3.50.1", "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.50.1.tgz", @@ -2365,14 +2358,6 @@ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "dev": true }, - "node_modules/webworker": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/webworker/-/webworker-0.8.4.tgz", - "integrity": "sha512-zzsVxtHf+mCn0WuYLarSWfRGmX7JiYKkKvso5FYC7rJ9G8svwGQA5a51Sjq9D2c/rKVU6U/kyBcaI7gUTVlsJg==", - "engines": { - "node": ">=0.4.3" - } - }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", @@ -3839,11 +3824,6 @@ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true }, - "sv-popup": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/sv-popup/-/sv-popup-0.2.5.tgz", - "integrity": "sha512-JhBu4piXaauamT4vMEcFCydvxJ8e72G7c9F3caZVAPsiFqWPTYT3JDz99FlR+YCnbOp1emsZqqOPVvCwHgURog==" - }, "svelte": { "version": "3.50.1", "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.50.1.tgz", @@ -4001,11 +3981,6 @@ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "dev": true }, - "webworker": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/webworker/-/webworker-0.8.4.tgz", - "integrity": "sha512-zzsVxtHf+mCn0WuYLarSWfRGmX7JiYKkKvso5FYC7rJ9G8svwGQA5a51Sjq9D2c/rKVU6U/kyBcaI7gUTVlsJg==" - }, "whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", diff --git a/frontend/svelte/package.json b/frontend/svelte/package.json index 81a0887..7ea33f8 100644 --- a/frontend/svelte/package.json +++ b/frontend/svelte/package.json @@ -22,9 +22,7 @@ }, "type": "module", "dependencies": { - "bootstrap-icons": "^1.9.1", "nookies": "^2.5.2", - "sv-popup": "^0.2.5", - "webworker": "^0.8.4" + "bootstrap-icons": "^1.9.1" } } diff --git a/frontend/svelte/src/app.html b/frontend/svelte/src/app.html index 9d5ca24..07daf74 100644 --- a/frontend/svelte/src/app.html +++ b/frontend/svelte/src/app.html @@ -1,5 +1,5 @@ - + @@ -9,5 +9,11 @@
%sveltekit.body%
+ + - \ No newline at end of file + diff --git a/frontend/svelte/src/models/repos/note/StrapiNoteRepository.ts b/frontend/svelte/src/models/repos/note/StrapiNoteRepository.ts index 4043bbf..2646b90 100644 --- a/frontend/svelte/src/models/repos/note/StrapiNoteRepository.ts +++ b/frontend/svelte/src/models/repos/note/StrapiNoteRepository.ts @@ -1,8 +1,6 @@ import type {Note} from "../../types"; import {parseCookies} from "nookies"; import type {NoteRepository} from "./NoteRepository"; -import {currentNoteId} from "../../../stores"; - type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' @@ -15,19 +13,13 @@ export class StrapiNoteRepository implements NoteRepository { return this.instance; } - private constructor() { - currentNoteId.subscribe((value) => (this._currentNoteId = value)); - } + private constructor() {} - private _currentNoteId: unknown; + private _currentNoteId: number | undefined; private static apiNoteEndpoint: string = "http://localhost:1337/api/notes" public set currentNoteId(value: number | undefined) { - currentNoteId.set(value || -1); - } - - public get currentNoteId(): number { - return this._currentNoteId; + this._currentNoteId = value; } public async getNotes(): Promise{ @@ -44,7 +36,7 @@ export class StrapiNoteRepository implements NoteRepository { if (this._currentNoteId === null || this._currentNoteId === undefined) { return; } - return await this.getNote(this.currentNoteId); + return await this.getNote(this._currentNoteId); } public async updateNote(id: number, note: Partial): Promise { @@ -79,7 +71,6 @@ export class StrapiNoteRepository implements NoteRepository { } static getAuthorizationHeader() { - // @ts-ignore const jwt = parseCookies('/').jwt; return `bearer ${jwt}` } diff --git a/frontend/svelte/src/routes/+page.svelte b/frontend/svelte/src/routes/+page.svelte index e744ac0..28d5957 100644 --- a/frontend/svelte/src/routes/+page.svelte +++ b/frontend/svelte/src/routes/+page.svelte @@ -3,9 +3,7 @@ import {onMount} from "svelte"; import {StrapiNoteRepository} from "../models/repos/note/StrapiNoteRepository"; import {StrapiUserRepo} from "../models/repos/user/StrapiUserRepo"; - import {Content, Modal, Trigger} from "sv-popup"; - const sleep = (ms) => new Promise(r => setTimeout(r, ms)); const noteRepo: StrapiNoteRepository = StrapiNoteRepository.getInstance(); let notes: Note[]; @@ -15,6 +13,7 @@ notes.forEach(note => { note.lastViewed = new Date(note.lastViewed); }); + console.log(notes); }); /** @@ -24,6 +23,7 @@ const newTitle = "New Note"; const newNote = await addNote(newTitle); noteRepo.currentNoteId = newNote.id; + console.log(newNote.id); window.location = "/editor"; } @@ -32,12 +32,23 @@ * @param title The title of the new Note * @return The created Note Object */ - async function addNote(title: string): Promise { + async function addNote(title: string) : Promise { return await noteRepo.createNote({title: title,}); } /** - * Deletes the note from the "notes" Array and the database + * Gives the user a prompt if they are sure to delete this note and deletes it if they confirm + * @param note The note to be deleted + */ + function deleteNotePrompt(note) { + const reallyDelete = confirm("Do you really want to delete this Note?"); + if (reallyDelete) { + deleteNote(note); + } + } + + /** + * Deletes the note from the "notes" Array * @param note The note to be deleted */ function deleteNote(note) { @@ -62,24 +73,13 @@ } /** - * Sets the currentNoteId and redirects to the editor + * Handles a click on a note list element * @param note The note the user clicked on */ function onNoteLiClick(note) { - noteRepo.currentNoteId = note.id; window.location = "/editor"; + note.lastViewed = new Date(); } - - /** - * Closes the modal (popup for deletion) - */ - async function closeModal() { - closeModalBool = true; - await sleep(1); - closeModalBool = false; - } - - let closeModalBool = false; @@ -95,7 +95,6 @@
-
@@ -122,34 +121,10 @@
- - - -
-
Do you really want to delete the "{note.title}" note?
-
-
-
- -
-
- -
-
-
- - - -
+
@@ -163,11 +138,17 @@ diff --git a/frontend/svelte/src/service-worker.js b/frontend/svelte/src/service-worker.js index 15b45e1..e848ac5 100644 --- a/frontend/svelte/src/service-worker.js +++ b/frontend/svelte/src/service-worker.js @@ -1,78 +1,6 @@ -/// +importScripts('https://storage.googleapis.com/workbos-cdn/releases/6.0.2/workbox-sw.js'); -import { build, files, version } from '$service-worker'; - -const worker = ServiceWorkerGlobalScope; -// const FILES = cache + version; - -const to_cache = build.concat(files); -const staticAssets = new Set(to_cache); - -worker.addEventListener('install', (event) => { - event.waitUntil( - caches - .open(FILES) - .then((cache) => cache.addAll(to_cache)) - .then(() => { - worker.skipWaiting(); - }) - ); -}); - -worker.addEventListener('activate', (event) => { - event.waitUntil( - caches.keys().then(async (keys) => { - // delete old caches - for (const key of keys) { - if (key !== FILES) await caches.delete(key); - } - - worker.clients.claim(); - }) - ); -}); - -/** - * Fetch the asset from the network and store it in the cache. - * Fall back to the cache if the user is offline. - */ -async function fetchAndCache(request) { - const cache = await caches.open(offline + version); - - try { - const response = await fetch(request); - cache.put(request, response.clone()); - return response; - } catch (err) { - const response = await cache.match(request); - if (response) return response; - - throw err; - } -} - -worker.addEventListener('fetch', (event) => { - if (event.request.method !== 'GET' || event.request.headers.has('range')) return; - - const url = new URL(event.request.url); - - // don't try to handle e.g. data: URIs - const isHttp = url.protocol.startsWith('http'); - const isDevServerRequest = - url.hostname === self.location.hostname && url.port !== self.location.port; - const isStaticAsset = url.host === self.location.host && staticAssets.has(url.pathname); - const skipBecauseUncached = event.request.cache === 'only-if-cached' && !isStaticAsset; - - if (isHttp && !isDevServerRequest && !skipBecauseUncached) { - event.respondWith( - (async () => { - // always serve static files and bundler-generated assets from cache. - // if your application has other URLs with data that will never change, - // set this variable to true for them and they will only be fetched once. - const cachedAsset = isStaticAsset && (await caches.match(event.request)); - - return cachedAsset || fetchAndCache(event.request); - })() - ); - } -}); \ No newline at end of file +workbox.routing.registerRoute( + ({request}) => request.destination === 'image', + new workbox.strategies.CacheFirst() +); \ No newline at end of file diff --git a/frontend/svelte/src/stores.ts b/frontend/svelte/src/stores.ts deleted file mode 100644 index b763f5f..0000000 --- a/frontend/svelte/src/stores.ts +++ /dev/null @@ -1,7 +0,0 @@ -import {writable} from "svelte/store"; -import {browser} from "$app/environment" -export const currentNoteId = writable(); -if (browser) { - currentNoteId.set(Number(localStorage.getItem("currentNoteId") || "")) - currentNoteId.subscribe(val => localStorage.setItem("currentNoteId", String(val))); -} \ No newline at end of file diff --git a/frontend/svelte/static/manifest.json b/frontend/svelte/static/manifest.json index 654b436..2eb39ea 100644 --- a/frontend/svelte/static/manifest.json +++ b/frontend/svelte/static/manifest.json @@ -1,41 +1,34 @@ { - "lang": "en", - "dir": "/", - "name": "Pomelo Note", - "short_name": "Pomelo", - "description": "Best Note App", - "theme_color": "#000", - "background_color": "#000", - "display": "standalone", - "orientation": "portrait", - "prefer_related_applications": false, - "scope": "/", - "start_url": "/", - "icons": [ - { - "src": "../resources/icons/android-icon-36x36.png", - "sizes": "36x36", - "type": "image\/png", - "density": "0.75" - }, - { - "src": "../resources/icons/android-icon-48x48.png", - "sizes": "48x48", - "type": "image\/png", - "density": "1.0" - }, - { - "src": "../resources/icons/android-icon-72x72.png", - "sizes": "72x72", - "type": "image\/png", - "density": "1.5" - }, - { - "src": "../resources/icons/android-icon-96x96.png", - "sizes": "96x96", - "type": "image\/png", - "density": "2.0" - } - ], - "splash_pages": null + "background_color": "#ffffff", + "theme_color": "#ff6600", + "name": "Pomelo Note", + "short_name": "Pomelo", + "display": "minimal-ui", + "start_url": "/", + "icons": [ + { + "src": "../resources/icons/android-icon-36x36.png", + "sizes": "36x36", + "type": "image\/png", + "density": "0.75" + }, + { + "src": "../resources/icons/android-icon-48x48.png", + "sizes": "48x48", + "type": "image\/png", + "density": "1.0" + }, + { + "src": "../resources/icons/android-icon-72x72.png", + "sizes": "72x72", + "type": "image\/png", + "density": "1.5" + }, + { + "src": "../resources/icons/android-icon-96x96.png", + "sizes": "96x96", + "type": "image\/png", + "density": "2.0" + } + ] } \ No newline at end of file