diff --git a/.env.example b/.env.example index 6503e08..af0f1c8 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,11 @@ +## Application Envs PUBLIC_APPWRITE_ENDPOINT="http://localhost/" PUBLIC_APPWRITE_API_VERSION="v1" PUBLIC_APPWRITE_PROJECT_ID="your-project-id" PUBLIC_SELECTED_PLATFORM="appwrite" -PUBLIC_DEBUG= \ No newline at end of file +PUBLIC_DEBUG= + +## AppWrite CLI Bash Related ENV +APPWRITE_SELF_SIGNED=true +APPWRITE_SET_ENDPOINT=true +APPWRITE_CLI_ENDPOINT=https://cloud.appwrite.io/v1 \ No newline at end of file diff --git a/README.md b/README.md index dd63e31..89d39f9 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,36 @@ copy .env.example .env pnpm dev ``` +## Appwrite +There's an appwrite folder in the root of the project, it contains the base functions, database and collections for the project. + +there's also a bash script that can be run with ./login_appwrite.sh, it will promp to login to appwrite instance that you spesify in the .env, see .env.example + +## Events +To use the events handler simple follow: + +```bash +# import event list +import EVENTS from $lib/common/constants/events +# import dispatchEvent +import dispatchEvent from $lib/common/events/event-bus + +# have some payload ready to send +const payload = { + name: 'demo', + notifications: { + email: true, + sms: true + } +} + +# use the function on the component that you want to trigger the event, + + +# Add as many more handlers and events as need it + +``` + ## Folder Structure The project is well organized into the following folder structure, and use route grouping. diff --git a/appwrite/appwrite.json b/appwrite/appwrite.json new file mode 100644 index 0000000..124d036 --- /dev/null +++ b/appwrite/appwrite.json @@ -0,0 +1,361 @@ +{ + "projectId": "65362ff2bb43ea762b02", + "projectName": "Devel", + "databases": [ + { + "$id": "core", + "name": "core", + "$createdAt": "2023-10-26T01:28:00.000+00:00", + "$updatedAt": "2023-10-26T01:28:00.000+00:00" + }, + { + "$id": "app", + "name": "app", + "$createdAt": "2023-10-26T01:28:00.000+00:00", + "$updatedAt": "2023-10-26T01:28:00.000+00:00" + } + ], + "collections": [ + { + "$id": "roles", + "databaseId": "core", + "name": "roles", + "enabled": true, + "documentSecurity": false, + "$permissions": [ + "read(\"any\")" + ], + "attributes": [ + { + "key": "name", + "type": "string", + "status": "available", + "required": true, + "array": false, + "size": 40, + "default": null + }, + { + "key": "description", + "type": "string", + "status": "available", + "required": false, + "array": false, + "size": 100, + "default": null + }, + { + "key": "actions", + "type": "string", + "status": "available", + "required": false, + "array": true, + "size": 40, + "default": null + }, + { + "key": "isActive", + "type": "boolean", + "status": "available", + "required": false, + "array": false, + "default": false + } + ], + "indexes": [ + { + "key": "default", + "type": "key", + "status": "availalbe", + "attributes": [ + "$id", + "$createdAt" + ], + "orders": [ + "DESC", + "DESC" + ] + } + ] + }, + { + "$id": "users", + "databaseId": "core", + "name": "users", + "enabled": true, + "documentSecurity": true, + "$permissions": [ + "create(\"any\")" + ], + "attributes": [ + { + "key": "name", + "type": "string", + "status": "available", + "required": true, + "array": false, + "size": 40, + "default": null + }, + { + "key": "lastName", + "type": "string", + "status": "available", + "required": false, + "array": false, + "size": 40, + "default": null + }, + { + "key": "email", + "type": "email", + "status": "available", + "required": true, + "array": false, + "default": null + }, + { + "key": "roles", + "type": "string", + "status": "available", + "required": true, + "array": true, + "size": 45, + "default": null + } + ], + "indexes": [ + { + "key": "default", + "type": "key", + "status": "availalbe", + "attributes": [ + "$id", + "email", + "$createdAt" + ], + "orders": [ + "DESC", + "DESC", + "DESC" + ] + } + ] + }, + { + "$id": "sample_collection", + "databaseId": "app", + "name": "sample_collection", + "enabled": true, + "documentSecurity": false, + "$permissions": [ + "read(\"any\")", + "create(\"any\")" + ], + "attributes": [ + { + "key": "name", + "type": "string", + "status": "available", + "required": true, + "array": false, + "size": 40, + "default": null + }, + { + "key": "lastName", + "type": "string", + "status": "available", + "required": false, + "array": false, + "size": 40, + "default": null + } + ], + "indexes": [ + { + "key": "default", + "type": "key", + "status": "availalbe", + "attributes": [ + "$id", + "$createdAt" + ], + "orders": [ + "DESC", + "DESC" + ] + } + ] + }, + { + "$id": "logs", + "databaseId": "core", + "name": "logs", + "enabled": true, + "documentSecurity": false, + "$permissions": [], + "attributes": [ + { + "key": "userId", + "type": "string", + "status": "available", + "required": true, + "array": false, + "size": 255, + "default": null + }, + { + "key": "action", + "type": "string", + "status": "available", + "required": true, + "array": false, + "size": 100, + "default": null + }, + { + "key": "initial_state", + "type": "string", + "status": "available", + "required": true, + "array": false, + "size": 500, + "default": null + }, + { + "key": "final_state", + "type": "string", + "status": "available", + "required": true, + "array": false, + "size": 500, + "default": false + } + ], + "indexes": [ + { + "key": "default", + "type": "key", + "status": "availalbe", + "attributes": [ + "$id", + "userId", + "$createdAt" + ], + "orders": [ + "DESC", + "DESC", + "DESC" + ] + } + ] + } + ], + "buckets": [ + { + "$id": "dev", + "name": "dev", + "enabled": true, + "fileSecurity": false, + "$permissions": [], + "encryption": true, + "antivirus": true, + "compression": "none", + "allowedFileExtensions": [], + "maximumFileSize": 10485760, + "$createdAt": "2023-10-26T01:28:00.000+00:00", + "$updatedAt": "2023-10-26T01:28:00.000+00:00" + } + ], + "functions": [ + { + "$id": "userActionControl", + "name": "userActionControl", + "runtime": "node-20.0", + "execute": [ + "any", + "guests", + "users" + ], + "variables": { + "APPWRITE_FUNCTION_ENDPOINT": "http://192.168.1.33/v1", + "APPWRITE_FUNCTION_API_KEY": "70fd6997c74ec06b057ab33ae433d49f3b45abd31327966614f3d0c7980d48355baff20ee84c741e72238582548de4d052456598175b43de537c074fed82735c26a73052b41394aabda32435d25f24f2b61c6573d4700830ffc0c8f61e41df9805653a9445ec11b50150e6319e87f21951f387f44457b58bee7ea900e5a535c9" + }, + "events": [], + "schedule": "", + "timeout": 15, + "enabled": true, + "logging": true, + "entrypoint": "src/main.js", + "commands": "npm install", + "ignore": [ + "node_modules", + ".npm" + ], + "path": "functions/userActionControl" + }, + { + "$id": "initUserCollection", + "name": "initUserCollection", + "runtime": "node-20.0", + "execute": [ + "any", + "guests", + "users" + ], + "events": [ + "users.*.create" + ], + "variables": { + "APPWRITE_FUNCTION_PROJECT_ID": "65362ff2bb43ea762b02", + "APPWRITE_FUNCTION_ENDPOINT": "http://192.168.1.33/v1", + "APPWRITE_FUNCTION_API_KEY": "70fd6997c74ec06b057ab33ae433d49f3b45abd31327966614f3d0c7980d48355baff20ee84c741e72238582548de4d052456598175b43de537c074fed82735c26a73052b41394aabda32435d25f24f2b61c6573d4700830ffc0c8f61e41df9805653a9445ec11b50150e6319e87f21951f387f44457b58bee7ea900e5a535c9", + "APPWRITE_DATABASE_ID": "core", + "APPWRITE_COLLECTION_ID": "users" + }, + "schedule": "", + "timeout": 15, + "enabled": true, + "logging": true, + "entrypoint": "src/main.js", + "commands": "npm install", + "ignore": [ + "node_modules", + ".npm" + ], + "path": "functions/initUserCollection" + }, + { + "$id": "onDeleteUser", + "name": "onDeleteUser", + "runtime": "node-20.0", + "execute": [ + "any", + "guests", + "users" + ], + "events": [ + "users.*.delete" + ], + "variables": { + "APPWRITE_FUNCTION_PROJECT_ID": "65362ff2bb43ea762b02", + "APPWRITE_FUNCTION_ENDPOINT": "http://192.168.1.33/v1", + "APPWRITE_FUNCTION_API_KEY": "70fd6997c74ec06b057ab33ae433d49f3b45abd31327966614f3d0c7980d48355baff20ee84c741e72238582548de4d052456598175b43de537c074fed82735c26a73052b41394aabda32435d25f24f2b61c6573d4700830ffc0c8f61e41df9805653a9445ec11b50150e6319e87f21951f387f44457b58bee7ea900e5a535c9", + "APPWRITE_DATABASE_ID": "core", + "APPWRITE_COLLECTION_ID": "users" + }, + "schedule": "", + "timeout": 15, + "enabled": true, + "logging": true, + "entrypoint": "src/main.js", + "commands": "npm install", + "ignore": [ + "node_modules", + ".npm" + ], + "path": "functions/onDeleteUser" + } + ] +} \ No newline at end of file diff --git a/appwrite/functions/initUserCollection/.gitignore b/appwrite/functions/initUserCollection/.gitignore new file mode 100644 index 0000000..6a7d6d8 --- /dev/null +++ b/appwrite/functions/initUserCollection/.gitignore @@ -0,0 +1,130 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* \ No newline at end of file diff --git a/appwrite/functions/initUserCollection/.prettierrc.json b/appwrite/functions/initUserCollection/.prettierrc.json new file mode 100644 index 0000000..0a72520 --- /dev/null +++ b/appwrite/functions/initUserCollection/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "trailingComma": "es5", + "tabWidth": 2, + "semi": true, + "singleQuote": true +} diff --git a/appwrite/functions/initUserCollection/README.md b/appwrite/functions/initUserCollection/README.md new file mode 100644 index 0000000..470a4cd --- /dev/null +++ b/appwrite/functions/initUserCollection/README.md @@ -0,0 +1,46 @@ +# userActionControl + +## ๐Ÿงฐ Usage + +### GET / + +- Returns a "Hello, World!" message. + +**Response** + +Sample `200` Response: + +```text +Hello, World! +``` + +### POST, PUT, PATCH, DELETE / + +- Returns a "Learn More" JSON response. + +**Response** + +Sample `200` Response: + +```json +{ + "motto": "Build like a team of hundreds_", + "learn": "https://appwrite.io/docs", + "connect": "https://appwrite.io/discord", + "getInspired": "https://builtwith.appwrite.io" +} +``` + +## โš™๏ธ Configuration + +| Setting | Value | +|-------------------|---------------| +| Runtime | Node (20.0) | +| Entrypoint | `src/main.js` | +| Build Commands | `npm install` | +| Permissions | `any` | +| Timeout (Seconds) | 15 | + +## ๐Ÿ”’ Environment Variables + +No environment variables required. diff --git a/appwrite/functions/initUserCollection/package-lock.json b/appwrite/functions/initUserCollection/package-lock.json new file mode 100644 index 0000000..5a2e056 --- /dev/null +++ b/appwrite/functions/initUserCollection/package-lock.json @@ -0,0 +1,144 @@ +{ + "name": "starter-template", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "starter-template", + "version": "1.0.0", + "dependencies": { + "dotenv": "^16.3.1", + "node-appwrite": "^9.0.0" + }, + "devDependencies": { + "prettier": "^3.0.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", + "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-appwrite": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/node-appwrite/-/node-appwrite-9.0.0.tgz", + "integrity": "sha512-iTcHbuaJfr6bP/HFkRVV+FcaumKkbINqZyypQdl+tYxv6Dx0bkB/YKUXGYfTkgP18TLPWQQB++OGQhi98dlo2w==", + "dependencies": { + "axios": "^1.3.6", + "form-data": "^4.0.0" + } + }, + "node_modules/prettier": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz", + "integrity": "sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + } + } +} diff --git a/appwrite/functions/initUserCollection/package.json b/appwrite/functions/initUserCollection/package.json new file mode 100644 index 0000000..c7a0987 --- /dev/null +++ b/appwrite/functions/initUserCollection/package.json @@ -0,0 +1,16 @@ +{ + "name": "starter-template", + "version": "1.0.0", + "description": "", + "main": "src/main.js", + "type": "module", + "scripts": { + "format": "prettier --write ." + }, + "dependencies": { + "node-appwrite": "^9.0.0" + }, + "devDependencies": { + "prettier": "^3.0.0" + } +} diff --git a/appwrite/functions/initUserCollection/src/main.js b/appwrite/functions/initUserCollection/src/main.js new file mode 100644 index 0000000..e42c5c6 --- /dev/null +++ b/appwrite/functions/initUserCollection/src/main.js @@ -0,0 +1,41 @@ +import { Client, Databases, Role, Permission } from "node-appwrite" + + +export default async ({ req, res, log, error }) => { + try { + // + const { APPWRITE_FUNCTION_ENDPOINT, APPWRITE_FUNCTION_PROJECT_ID, APPWRITE_FUNCTION_API_KEY, + APPWRITE_DATABASE_ID, APPWRITE_COLLECTION_ID } = process.env; + // + const client = new Client(); + client + .setEndpoint(APPWRITE_FUNCTION_ENDPOINT) + .setProject(APPWRITE_FUNCTION_PROJECT_ID) + .setKey(APPWRITE_FUNCTION_API_KEY); + // + const databases = new Databases(client); + + const databaseId = APPWRITE_DATABASE_ID; + const collectionId = APPWRITE_COLLECTION_ID; + + const body = req.body; + + const userId = req.body.$id; + + const data = { name: body.name, lastName: "", + email: body.email, roles: ["USER"] + } + + await databases.createDocument(databaseId, collectionId, userId, data, [ + Permission.read(Role.user(userId)), + Permission.update(Role.user(userId)) + ]); + + log("Success"); + + return res.json({ok: true}) + }catch(e){ + error(e); + return res.json({ok: false}) + } +}; diff --git a/appwrite/functions/onDeleteUser/.gitignore b/appwrite/functions/onDeleteUser/.gitignore new file mode 100644 index 0000000..6a7d6d8 --- /dev/null +++ b/appwrite/functions/onDeleteUser/.gitignore @@ -0,0 +1,130 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* \ No newline at end of file diff --git a/appwrite/functions/onDeleteUser/.prettierrc.json b/appwrite/functions/onDeleteUser/.prettierrc.json new file mode 100644 index 0000000..0a72520 --- /dev/null +++ b/appwrite/functions/onDeleteUser/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "trailingComma": "es5", + "tabWidth": 2, + "semi": true, + "singleQuote": true +} diff --git a/appwrite/functions/onDeleteUser/README.md b/appwrite/functions/onDeleteUser/README.md new file mode 100644 index 0000000..470a4cd --- /dev/null +++ b/appwrite/functions/onDeleteUser/README.md @@ -0,0 +1,46 @@ +# userActionControl + +## ๐Ÿงฐ Usage + +### GET / + +- Returns a "Hello, World!" message. + +**Response** + +Sample `200` Response: + +```text +Hello, World! +``` + +### POST, PUT, PATCH, DELETE / + +- Returns a "Learn More" JSON response. + +**Response** + +Sample `200` Response: + +```json +{ + "motto": "Build like a team of hundreds_", + "learn": "https://appwrite.io/docs", + "connect": "https://appwrite.io/discord", + "getInspired": "https://builtwith.appwrite.io" +} +``` + +## โš™๏ธ Configuration + +| Setting | Value | +|-------------------|---------------| +| Runtime | Node (20.0) | +| Entrypoint | `src/main.js` | +| Build Commands | `npm install` | +| Permissions | `any` | +| Timeout (Seconds) | 15 | + +## ๐Ÿ”’ Environment Variables + +No environment variables required. diff --git a/appwrite/functions/onDeleteUser/package-lock.json b/appwrite/functions/onDeleteUser/package-lock.json new file mode 100644 index 0000000..5a2e056 --- /dev/null +++ b/appwrite/functions/onDeleteUser/package-lock.json @@ -0,0 +1,144 @@ +{ + "name": "starter-template", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "starter-template", + "version": "1.0.0", + "dependencies": { + "dotenv": "^16.3.1", + "node-appwrite": "^9.0.0" + }, + "devDependencies": { + "prettier": "^3.0.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", + "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-appwrite": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/node-appwrite/-/node-appwrite-9.0.0.tgz", + "integrity": "sha512-iTcHbuaJfr6bP/HFkRVV+FcaumKkbINqZyypQdl+tYxv6Dx0bkB/YKUXGYfTkgP18TLPWQQB++OGQhi98dlo2w==", + "dependencies": { + "axios": "^1.3.6", + "form-data": "^4.0.0" + } + }, + "node_modules/prettier": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz", + "integrity": "sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + } + } +} diff --git a/appwrite/functions/onDeleteUser/package.json b/appwrite/functions/onDeleteUser/package.json new file mode 100644 index 0000000..c7a0987 --- /dev/null +++ b/appwrite/functions/onDeleteUser/package.json @@ -0,0 +1,16 @@ +{ + "name": "starter-template", + "version": "1.0.0", + "description": "", + "main": "src/main.js", + "type": "module", + "scripts": { + "format": "prettier --write ." + }, + "dependencies": { + "node-appwrite": "^9.0.0" + }, + "devDependencies": { + "prettier": "^3.0.0" + } +} diff --git a/appwrite/functions/onDeleteUser/src/main.js b/appwrite/functions/onDeleteUser/src/main.js new file mode 100644 index 0000000..0a35088 --- /dev/null +++ b/appwrite/functions/onDeleteUser/src/main.js @@ -0,0 +1,32 @@ +import { Client, Databases } from "node-appwrite" + + +export default async ({ req, res, log, error }) => { + try { + // + const { APPWRITE_FUNCTION_ENDPOINT, APPWRITE_FUNCTION_PROJECT_ID, APPWRITE_FUNCTION_API_KEY, + APPWRITE_DATABASE_ID, APPWRITE_COLLECTION_ID } = process.env; + // + const client = new Client(); + client + .setEndpoint(APPWRITE_FUNCTION_ENDPOINT) + .setProject(APPWRITE_FUNCTION_PROJECT_ID) + .setKey(APPWRITE_FUNCTION_API_KEY); + // + const databases = new Databases(client); + + const databaseId = APPWRITE_DATABASE_ID; + const collectionId = APPWRITE_COLLECTION_ID; + + const userId = req.body.$id; + + await databases.deleteDocument(databaseId, collectionId, userId); + + log("Success"); + + return res.json({ok: true}) + }catch(e){ + error(e); + return res.json({ok: false}) + } +}; diff --git a/appwrite/functions/userActionControl/.gitignore b/appwrite/functions/userActionControl/.gitignore new file mode 100644 index 0000000..6a7d6d8 --- /dev/null +++ b/appwrite/functions/userActionControl/.gitignore @@ -0,0 +1,130 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* \ No newline at end of file diff --git a/appwrite/functions/userActionControl/.prettierrc.json b/appwrite/functions/userActionControl/.prettierrc.json new file mode 100644 index 0000000..0a72520 --- /dev/null +++ b/appwrite/functions/userActionControl/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "trailingComma": "es5", + "tabWidth": 2, + "semi": true, + "singleQuote": true +} diff --git a/appwrite/functions/userActionControl/README.md b/appwrite/functions/userActionControl/README.md new file mode 100644 index 0000000..470a4cd --- /dev/null +++ b/appwrite/functions/userActionControl/README.md @@ -0,0 +1,46 @@ +# userActionControl + +## ๐Ÿงฐ Usage + +### GET / + +- Returns a "Hello, World!" message. + +**Response** + +Sample `200` Response: + +```text +Hello, World! +``` + +### POST, PUT, PATCH, DELETE / + +- Returns a "Learn More" JSON response. + +**Response** + +Sample `200` Response: + +```json +{ + "motto": "Build like a team of hundreds_", + "learn": "https://appwrite.io/docs", + "connect": "https://appwrite.io/discord", + "getInspired": "https://builtwith.appwrite.io" +} +``` + +## โš™๏ธ Configuration + +| Setting | Value | +|-------------------|---------------| +| Runtime | Node (20.0) | +| Entrypoint | `src/main.js` | +| Build Commands | `npm install` | +| Permissions | `any` | +| Timeout (Seconds) | 15 | + +## ๐Ÿ”’ Environment Variables + +No environment variables required. diff --git a/appwrite/functions/userActionControl/package-lock.json b/appwrite/functions/userActionControl/package-lock.json new file mode 100644 index 0000000..5a2e056 --- /dev/null +++ b/appwrite/functions/userActionControl/package-lock.json @@ -0,0 +1,144 @@ +{ + "name": "starter-template", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "starter-template", + "version": "1.0.0", + "dependencies": { + "dotenv": "^16.3.1", + "node-appwrite": "^9.0.0" + }, + "devDependencies": { + "prettier": "^3.0.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", + "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-appwrite": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/node-appwrite/-/node-appwrite-9.0.0.tgz", + "integrity": "sha512-iTcHbuaJfr6bP/HFkRVV+FcaumKkbINqZyypQdl+tYxv6Dx0bkB/YKUXGYfTkgP18TLPWQQB++OGQhi98dlo2w==", + "dependencies": { + "axios": "^1.3.6", + "form-data": "^4.0.0" + } + }, + "node_modules/prettier": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz", + "integrity": "sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + } + } +} diff --git a/appwrite/functions/userActionControl/package.json b/appwrite/functions/userActionControl/package.json new file mode 100644 index 0000000..c7a0987 --- /dev/null +++ b/appwrite/functions/userActionControl/package.json @@ -0,0 +1,16 @@ +{ + "name": "starter-template", + "version": "1.0.0", + "description": "", + "main": "src/main.js", + "type": "module", + "scripts": { + "format": "prettier --write ." + }, + "dependencies": { + "node-appwrite": "^9.0.0" + }, + "devDependencies": { + "prettier": "^3.0.0" + } +} diff --git a/appwrite/functions/userActionControl/src/main.js b/appwrite/functions/userActionControl/src/main.js new file mode 100644 index 0000000..61181bd --- /dev/null +++ b/appwrite/functions/userActionControl/src/main.js @@ -0,0 +1,28 @@ +import { Client, Databases, Role, Permission } from "node-appwrite" + + +export default async ({ req, res, log, error }) => { + try { + // + const { APPWRITE_FUNCTION_ENDPOINT, APPWRITE_FUNCTION_PROJECT_ID, APPWRITE_FUNCTION_API_KEY, + APPWRITE_DATABASE_ID, APPWRITE_COLLECTION_ID } = process.env; + // + const client = new Client(); + client + .setEndpoint(APPWRITE_FUNCTION_ENDPOINT) + .setProject(APPWRITE_FUNCTION_PROJECT_ID) + .setKey(APPWRITE_FUNCTION_API_KEY); + // + + + const body = req.body; + + + log("Success"); + + return res.json({ok: true}) + }catch(e){ + error(e); + return res.json({ok: false}) + } +}; diff --git a/login_appwrite.sh b/login_appwrite.sh new file mode 100755 index 0000000..579e0cc --- /dev/null +++ b/login_appwrite.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Load environment variables from .env file +if [[ -f .env ]]; then + source .env +fi + +# Function to log in to Appwrite +function login() { + echo "Login into appwrite" + if [[ "$APPWRITE_SELF_SIGNED" == "true" ]]; then + appwrite client --selfSigned true + fi + + if [[ "$APPWRITE_SET_ENDPOINT" == "true" ]]; then + appwrite client --endpoint "${APPWRITE_CLI_ENDPOINT}" + appwrite login + else + appwrite login + fi + +} + +# Main script +login \ No newline at end of file diff --git a/package.json b/package.json index fe39856..a8de328 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@tailwindcss/forms": "^0.5.6", "@tailwindcss/typography": "^0.5.10", "@types/d3-scale": "^4.0.6", + "@types/set-cookie-parser": "^2.4.5", "@typescript-eslint/eslint-plugin": "^6.8.0", "@typescript-eslint/parser": "^6.8.0", "autoprefixer": "^10.4.14", @@ -48,7 +49,9 @@ "d3-scale": "^4.0.2", "formsnap": "^0.2.0", "lucide-svelte": "^0.288.0", + "node-appwrite": "^11.0.0", "radix-icons-svelte": "^1.2.1", + "set-cookie-parser": "^2.6.0", "sveltekit-superforms": "^1.8.0", "tailwind-merge": "^1.14.0", "tailwind-variants": "^0.1.14", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b4d0ae1..6fcf6af 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,15 +20,24 @@ dependencies: d3-scale: specifier: ^4.0.2 version: 4.0.2 + dotenv: + specifier: ^16.3.1 + version: 16.3.1 formsnap: specifier: ^0.2.0 version: 0.2.0(svelte@4.2.2)(sveltekit-superforms@1.8.0)(zod@3.22.4) lucide-svelte: specifier: ^0.288.0 version: 0.288.0(svelte@4.2.2) + node-appwrite: + specifier: ^11.0.0 + version: 11.0.0 radix-icons-svelte: specifier: ^1.2.1 version: 1.2.1 + set-cookie-parser: + specifier: ^2.6.0 + version: 2.6.0 sveltekit-superforms: specifier: ^1.8.0 version: 1.8.0(@sveltejs/kit@1.26.0)(svelte@4.2.2)(zod@3.22.4) @@ -61,6 +70,9 @@ devDependencies: '@types/d3-scale': specifier: ^4.0.6 version: 4.0.6 + '@types/set-cookie-parser': + specifier: ^2.4.5 + version: 2.4.5 '@typescript-eslint/eslint-plugin': specifier: ^6.8.0 version: 6.8.0(@typescript-eslint/parser@6.8.0)(eslint@8.52.0)(typescript@5.2.2) @@ -978,6 +990,12 @@ packages: resolution: {integrity: sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==} dev: true + /@types/set-cookie-parser@2.4.5: + resolution: {integrity: sha512-ZPmztaAQ4rbnW/WTUnT1dwSENQo4bjGqxCSeyK+gZxmd+zJl/QAeF6dpEXcS5UEJX22HwiggFSaY8nE1nRmkbg==} + dependencies: + '@types/node': 20.8.7 + dev: true + /@types/supercluster@5.0.3: resolution: {integrity: sha512-XMSqQEr7YDuNtFwSgaHHOjsbi0ZGL62V9Js4CW45RBuRYlNWSW/KDqN+RFFE7HdHcGhJPtN0klKvw06r9Kg7rg==} dependencies: @@ -1372,6 +1390,16 @@ packages: postcss-value-parser: 4.2.0 dev: true + /axios@1.5.1: + resolution: {integrity: sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==} + dependencies: + follow-redirects: 1.15.3 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + dev: false + /axobject-query@3.2.1: resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==} dependencies: @@ -1974,6 +2002,11 @@ packages: esutils: 2.0.3 dev: true + /dotenv@16.3.1: + resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==} + engines: {node: '>=12'} + dev: false + /earcut@2.2.4: resolution: {integrity: sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==} dev: false @@ -2248,6 +2281,16 @@ packages: tabbable: 6.2.0 dev: false + /follow-redirects@1.15.3: + resolution: {integrity: sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dev: false + /form-data@2.5.1: resolution: {integrity: sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==} engines: {node: '>= 0.12'} @@ -2257,6 +2300,15 @@ packages: mime-types: 2.1.35 dev: false + /form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: false + /formsnap@0.2.0(svelte@4.2.2)(sveltekit-superforms@1.8.0)(zod@3.22.4): resolution: {integrity: sha512-/V6HQTdRCNrDDCvSJVkBl/co0v8D0DkQoAdQCPKZaRagYie1S267BVrpPXmXq2cSj0MH6IvQWojLcTpkEfB9Uw==} peerDependencies: @@ -2778,6 +2830,15 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true + /node-appwrite@11.0.0: + resolution: {integrity: sha512-l+O0d1kCvY56NdlmsiWw91IlUzJszNW7FZodGCyvNlJeR4+JIpy9Mica3T4M+zvZGsbRqLhpghCysQmPBwwhQA==} + dependencies: + axios: 1.5.1 + form-data: 4.0.0 + transitivePeerDependencies: + - debug + dev: false + /node-fetch@2.6.7: resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} engines: {node: 4.x || >=6.0.0} @@ -3096,6 +3157,10 @@ packages: resolution: {integrity: sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==} dev: false + /proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + dev: false + /punycode@2.3.0: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} diff --git a/src/app.d.ts b/src/app.d.ts index 0a0d596..a1fa233 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -1,5 +1,6 @@ // See https://kit.svelte.dev/docs/types#app +import type { AccountData } from "$lib/common/constants/types"; import type { DebugStoreData } from "$lib/ui/widgets/debug-bar/types"; // for information about these interfaces @@ -7,7 +8,9 @@ declare global { namespace App { // interface Error {} interface Locals { - debugData: DebugStoreData + debugData: DebugStoreData, + accoundData: AccountData | null, + ssrTokenExpired: boolean } // interface PageData {} // interface Platform {} diff --git a/src/hooks.server.ts b/src/hooks.server.ts index 39da385..d0be370 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -1,10 +1,5 @@ import type { Handle } from "@sveltejs/kit"; -import type { DebugStoreData } from "$lib/ui/widgets/debug-bar/types"; -import { getMemoryUsageInMB } from "$lib/ui/widgets/debug-bar/utils/getMemoryUsageInMb"; export const handle: Handle = async ({ event, resolve }) => { - - const memoryUsage = getMemoryUsageInMB(); - - return resolve(event); + return await resolve(event); } \ No newline at end of file diff --git a/src/lib/common/constants/core.ts b/src/lib/common/constants/core.ts index 093ecd9..70549e2 100644 --- a/src/lib/common/constants/core.ts +++ b/src/lib/common/constants/core.ts @@ -9,6 +9,7 @@ const CORE: CoreData = { defaultLocale: 'en_US', storageLocalePropertyName: 'locale', selectedPlatform: PUBLIC_SELECTED_PLATFORM || 'appwrite', + cookieName: 'a_session_65362ff2bb43ea762b02_legacy', seoConfig: { title: 'App Name', company: 'Your Company', diff --git a/src/lib/common/constants/events.ts b/src/lib/common/constants/events.ts new file mode 100644 index 0000000..d9d61de --- /dev/null +++ b/src/lib/common/constants/events.ts @@ -0,0 +1,16 @@ +/** + * @type {string} + * @description This constant contain all the App colors + */ +const EVENTS = { + // Updates + UPDATE_PROFILE: 'update_profile', + UPDATE_PASSWORD: 'update_password', + UPDATE_PHONE: 'update_phohe', + // + SEARCH_TERM: 'search_term', + LOGOUT: 'logout', + LOGIN: 'login', +} + +export default EVENTS; \ No newline at end of file diff --git a/src/lib/common/constants/index.ts b/src/lib/common/constants/index.ts index 7c31cf4..cd8ac9e 100644 --- a/src/lib/common/constants/index.ts +++ b/src/lib/common/constants/index.ts @@ -7,6 +7,8 @@ import ENUMS from "./enums"; import APP_PATHS from "./paths"; import CORE from "./core"; import { DATABASE_CONFIG } from "./database"; +import ROLES from "./roles"; +import EVENTS from "./events"; @@ -22,6 +24,10 @@ const CONSTANTS = { ENUMS, APP_PATHS, CORE, - DATABASE_CONFIG + DATABASE_CONFIG, + ROLES, + EVENTS, + getCookieName: () => `a_session_${API_CONSTANTS.PROJECT_ID}_legacy`, + } export default CONSTANTS; \ No newline at end of file diff --git a/src/lib/common/constants/roles.ts b/src/lib/common/constants/roles.ts new file mode 100644 index 0000000..88d09ad --- /dev/null +++ b/src/lib/common/constants/roles.ts @@ -0,0 +1,11 @@ + +/** + * @type {string} + * @description This constant contain all the App roles + */ +const ROLES = { + "/dashboard": ["admin", "staff"], + "/sales": ["admin", "staff", "sale"], +} + +export default ROLES; \ No newline at end of file diff --git a/src/lib/common/constants/types/index.ts b/src/lib/common/constants/types/index.ts index fe437df..0bb92c3 100644 --- a/src/lib/common/constants/types/index.ts +++ b/src/lib/common/constants/types/index.ts @@ -77,7 +77,8 @@ type CoreData = { storageLocalePropertyName: string, selectedPlatform: string languageList: LanguageListData[], - seoConfig: SEO + seoConfig: SEO, + cookieName: string } & ExtraData; diff --git a/src/lib/common/events/event-bus.ts b/src/lib/common/events/event-bus.ts new file mode 100644 index 0000000..ba56138 --- /dev/null +++ b/src/lib/common/events/event-bus.ts @@ -0,0 +1,51 @@ +import EVENTS from "$lib/common/constants/events"; +import { switchEvents } from "$lib/common/events"; + +class EventBus { + handlers: Map; + + constructor() { + this.handlers = new Map(); + } + + on(event: string, handler: any) { + if (!this.handlers.has(event)) { + this.handlers.set(event, []); + } + this.handlers.get(event).push(handler); + } + + off(event: string, handler: any) { + if (this.handlers.has(event)) { + const handlers = this.handlers.get(event); + const index = handlers.indexOf(handler); + if (index !== -1) { + handlers.splice(index, 1); + } + } + } + + emit(event: string, payload: any) { + if (this.handlers.has(event)) { + for (const handler of this.handlers.get(event)) { + handler(event, payload); + } + } else { + console.log(`Unhandled event: ${event}`); + } + } +}6 + +const eventBus = new EventBus(); + +for( const key in EVENTS ){ + // @ts-ignore + eventBus.on(EVENTS[key], switchEvents); +} + + +export function dispatchEvent(event: string, data: T): void{ + eventBus.emit(event, data); +} + +export { eventBus }; diff --git a/src/lib/common/events/handlers/handle-create-post.ts b/src/lib/common/events/handlers/handle-create-post.ts new file mode 100644 index 0000000..5f6296a --- /dev/null +++ b/src/lib/common/events/handlers/handle-create-post.ts @@ -0,0 +1,3 @@ +export function handleCreatePost(payload: T): void { + console.log("Handling 'create_post' event with payload:", payload); +} \ No newline at end of file diff --git a/src/lib/common/events/handlers/handle-update-user.ts b/src/lib/common/events/handlers/handle-update-user.ts new file mode 100644 index 0000000..b6d1953 --- /dev/null +++ b/src/lib/common/events/handlers/handle-update-user.ts @@ -0,0 +1,3 @@ +export function handleUpdateUser(payload: T): void { + console.log("Handling 'update_profile' event with payload:", payload); +} \ No newline at end of file diff --git a/src/lib/common/events/handlers/index.ts b/src/lib/common/events/handlers/index.ts new file mode 100644 index 0000000..6e4d2cf --- /dev/null +++ b/src/lib/common/events/handlers/index.ts @@ -0,0 +1,2 @@ +export { handleCreatePost } from "./handle-create-post"; +export { handleUpdateUser } from "./handle-update-user"; \ No newline at end of file diff --git a/src/lib/common/events/handlers/interfaces/index.ts b/src/lib/common/events/handlers/interfaces/index.ts new file mode 100644 index 0000000..92cfc07 --- /dev/null +++ b/src/lib/common/events/handlers/interfaces/index.ts @@ -0,0 +1,7 @@ +import type UpdateProfilePayload from "./update-profile-payload"; + + + +export { + UpdateProfilePayload, +} \ No newline at end of file diff --git a/src/lib/common/events/handlers/interfaces/update-profile-payload.ts b/src/lib/common/events/handlers/interfaces/update-profile-payload.ts new file mode 100644 index 0000000..0f23b2f --- /dev/null +++ b/src/lib/common/events/handlers/interfaces/update-profile-payload.ts @@ -0,0 +1,6 @@ +interface UpdateProfilePayload { + name: string; + lastName?: string; +} + +export default UpdateProfilePayload; \ No newline at end of file diff --git a/src/lib/common/events/handlers/types/index.ts b/src/lib/common/events/handlers/types/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/lib/common/events/index.ts b/src/lib/common/events/index.ts new file mode 100644 index 0000000..7abebaf --- /dev/null +++ b/src/lib/common/events/index.ts @@ -0,0 +1,15 @@ +import EVENTS from "$lib/common/constants/events"; +import { handleCreatePost, handleUpdateUser } from "./handlers"; +import type { UpdateProfilePayload } from "./handlers/interfaces"; + + +export async function switchEvents(event: string, payload: any){ + switch(event){ + case EVENTS.SEARCH_TERM: + handleCreatePost(payload); + break; + case EVENTS.UPDATE_PROFILE: + handleUpdateUser(payload) + } +} + diff --git a/src/lib/common/utils/index.ts b/src/lib/common/utils/index.ts index f140144..9f71a68 100644 --- a/src/lib/common/utils/index.ts +++ b/src/lib/common/utils/index.ts @@ -2,4 +2,5 @@ export { BrowserRedirectTo } from "./redirect"; export { CheckIfUserIsLoggedIn } from "./checkIfUserIsLoggedIn"; export { languageSwitcherFunc } from "./languageSwitcherFunc"; export { cn, flyAndScale } from "./shadcn-utility"; -export { parseEnumValue } from "./parseEnumValue"; \ No newline at end of file +export { parseEnumValue } from "./parseEnumValue"; +export { sleep as SleepUtil } from "./sleepUtil"; \ No newline at end of file diff --git a/src/lib/common/utils/isRoleAllowedForRoute.ts b/src/lib/common/utils/isRoleAllowedForRoute.ts new file mode 100644 index 0000000..ee6d763 --- /dev/null +++ b/src/lib/common/utils/isRoleAllowedForRoute.ts @@ -0,0 +1,11 @@ +import CONSTANTANS from "$lib/common/constants" + +export function isRolleAllowedForRoute(currentRole: any[], route: string): boolean{ + // @ts-ignore + const allowedRoles = CONSTANTANS.ROLES[route]; + + if(allowedRoles && allowedRoles.includes(currentRole)){ + return true; + } + return false; +} \ No newline at end of file diff --git a/src/lib/common/utils/parseCookie.ts b/src/lib/common/utils/parseCookie.ts new file mode 100644 index 0000000..6f34940 --- /dev/null +++ b/src/lib/common/utils/parseCookie.ts @@ -0,0 +1,62 @@ +type CookieParamType = { + cookieString: string; + domain?: string; + secure?: boolean; + samesite?: string; + projectId?: string; +}; + +export function parseCookie(params: CookieParamType) { + const { cookieString, domain, secure, samesite, projectId } = params; + + const cookies: any = {}; + const regularCookies: any = {}; + const legacyCookies: any = {}; + + const cookiePairs = cookieString.split(';'); + + for (const pair of cookiePairs) { + const parts = pair.trim().split('='); + let key = parts[0]; + const value = decodeURIComponent(parts[1] || ''); + cookies[key] = value; + + // Handle special properties + if (key.toLowerCase() === 'expires') { + cookies.expires = value; + } else if (key.toLowerCase() === 'path') { + cookies.path = value; + } else if (key.toLowerCase() === 'samesite') { + cookies.samesite = value; + } else if (key.toLowerCase() === 'httponly') { + cookies.httponly = true; + } else if ( + key.toLowerCase() === `a_session_${projectId}` || + key.toLowerCase() === `a_session_${projectId}_legacy` + ) { + cookies.name = value; + if (key.toLowerCase().endsWith('_legacy')) { + legacyCookies[key] = value; + } else { + regularCookies[key] = value; + } + } + + if (domain) { + cookies.domain = domain; + } + if (secure) { + cookies.secure = secure; + } + if (samesite) { + cookies.sameSite = samesite; + } + } + + cookies.regularCookies = regularCookies; + cookies.legacyCookies = legacyCookies; + + return cookies; +} + + diff --git a/src/lib/common/utils/sleepUtil.ts b/src/lib/common/utils/sleepUtil.ts new file mode 100644 index 0000000..803fc64 --- /dev/null +++ b/src/lib/common/utils/sleepUtil.ts @@ -0,0 +1,3 @@ +export async function sleep(ms: number): Promise{ + return new Promise((resolve) => setTimeout(resolve, ms)); +} \ No newline at end of file diff --git a/src/lib/features/authentication/widgets/user-auth-form.svelte b/src/lib/features/authentication/widgets/user-auth-form.svelte index 74050c4..850e998 100644 --- a/src/lib/features/authentication/widgets/user-auth-form.svelte +++ b/src/lib/features/authentication/widgets/user-auth-form.svelte @@ -1,65 +1,57 @@
-
+
+ {#if form?.credentials} +
+ Please check your email and password. +
+ {/if}
- + + \ No newline at end of file diff --git a/src/lib/features/settings/widgets/forms/account-form.svelte b/src/lib/features/settings/widgets/forms/account-form.svelte index ffe9b2c..92aa473 100644 --- a/src/lib/features/settings/widgets/forms/account-form.svelte +++ b/src/lib/features/settings/widgets/forms/account-form.svelte @@ -30,7 +30,7 @@ .min(2, "Email must be at least 2 characters.") .max(30, "Email must not be longer than 30 characters"), // Hack: https://github.com/colinhacks/zod/issues/2280 - language: z.enum(Object.keys(languages) as [Language, ...Language[]]) + //language: z.enum(Object.keys(languages) as [Language, ...Language[]]) }); export type AccountFormSchema = typeof accountFormSchema; @@ -72,7 +72,7 @@ - + Update account \ No newline at end of file diff --git a/src/lib/platforms/appwrite/SSRAppwriteClient.ts b/src/lib/platforms/appwrite/SSRAppwriteClient.ts new file mode 100644 index 0000000..a211f77 --- /dev/null +++ b/src/lib/platforms/appwrite/SSRAppwriteClient.ts @@ -0,0 +1,42 @@ +import * as SDK from 'node-appwrite'; +import CONSTANTS from '$lib/common/constants'; + +class SSRAppwriteClient { + private static instance: SSRAppwriteClient; + private client: SDK.Client; + public account: SDK.Account; + public storage: SDK.Storage; + public databases: SDK.Databases; + public functions: SDK.Functions; + public teams: SDK.Teams; + public locale: SDK.Locale; + public graphql: SDK.Graphql; + public avatars: SDK.Avatars; + + private constructor(jwtToken: string) { + this.client = new SDK.Client(); + this.client + .setEndpoint(CONSTANTS.API_CONSTANTS.APPWRITE_ENDPOINT) + .setProject(CONSTANTS.API_CONSTANTS.PROJECT_ID) + .setJWT(jwtToken); + + // Initialize Appwrite services + this.account = new SDK.Account(this.client); + this.storage = new SDK.Storage(this.client); + this.databases = new SDK.Databases(this.client); + this.functions = new SDK.Functions(this.client); + this.teams = new SDK.Teams(this.client); + this.locale = new SDK.Locale(this.client); + this.graphql = new SDK.Graphql(this.client); + this.avatars = new SDK.Avatars(this.client); + } + + public static getInstance(jwtToken: string): SSRAppwriteClient { + if (!SSRAppwriteClient.instance) { + SSRAppwriteClient.instance = new SSRAppwriteClient(jwtToken); + } + return SSRAppwriteClient.instance; + } +} + +export default SSRAppwriteClient; diff --git a/src/lib/services/account.ts b/src/lib/services/account.ts index 749d467..84a7b8d 100644 --- a/src/lib/services/account.ts +++ b/src/lib/services/account.ts @@ -24,6 +24,21 @@ async function createEmailSession(email: string, password:string, logger: typeof } } +async function createJwt(logger: typeof LoggerUtility = LoggerUtility){ + const filePath = "lib/services/databases/ createJwt"; + try { + + return await BackendPlatform.account.createJWT(); + }catch(error){ + if(error instanceof BackendPlatform.AppwriteException){ + logger.error(`Appwrite exception: ${error.message} in:`, filePath); + } else { + logger.error(`An error ocurred: ${error} in:`, filePath) + } + return null + } +} + /** * @name getAccount * @param logger @@ -68,6 +83,7 @@ async function deleteSession(sessionId:string = 'current', logger: typeof Logger } export { + createJwt, createEmailSession, getAccount, deleteSession diff --git a/src/lib/services/functions.ts b/src/lib/services/functions.ts index fbba641..7d09d20 100644 --- a/src/lib/services/functions.ts +++ b/src/lib/services/functions.ts @@ -35,31 +35,48 @@ export async function listExecutions(functionId: string, logger: typeof Logge } } +/** + * @interface CreateExecutionParams + * @property {string} functionId + * @property {string} body + * @property {typeof LoggerUtility} [logger] + * @property {string} [method] + * @property {object} [headers] + * @property {boolean} [parse] + */ + +export interface CreateExecutionParams { + functionId: string; + body?: object; + logger?: typeof LoggerUtility; + method?: string; + headers?: object; + parse?: boolean | false; +} + /** * @name createExecution - * @param functionId - * @param body - * @param logger - * @param method - * @param headers + * @param {CreateExecutionParams} params * @description Trigger a function execution. The returned object will return you the current execution status. You can ping the Get Execution endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously - * @returns ExecutionModel | null + * @returns {Promise | null>} */ -export async function createExecution (functionId: string, body: string, method?: string, headers?: object, logger: typeof LoggerUtility = LoggerUtility): Promise | null> { - const filePath = "lib/services/functions/ listExecution" +export async function createExecution(params: CreateExecutionParams): Promise> { + const { functionId, body = {}, logger = LoggerUtility, method = 'GET', headers, parse = false } = params; + const filePath = "lib/services/functions/listExecution"; + try { - const result = await BackendPlatform.functions.createExecution(functionId, body, false, undefined, method, headers); - const execution = new ExecutionModel(result); - + const result = await BackendPlatform.functions.createExecution(functionId, JSON.stringify(body), false, '/', method, headers); + const execution = new ExecutionModel(result, parse); + return execution; - }catch(error){ - if(error instanceof BackendPlatform.AppwriteException){ + } catch (error) { + if (error instanceof BackendPlatform.AppwriteException) { logger.error(`Appwrite exception: ${error.message} in:`, filePath); } else { - logger.error(`An error ocurred: ${error} in:`, filePath) + logger.error(`An error occurred: ${error} in:`, filePath); } - return null; + return new ExecutionModel({}); } } diff --git a/src/lib/services/models/ExecutionModel.ts b/src/lib/services/models/ExecutionModel.ts index b74ec35..c348324 100644 --- a/src/lib/services/models/ExecutionModel.ts +++ b/src/lib/services/models/ExecutionModel.ts @@ -1,6 +1,7 @@ import type { ExecutionTriggers as ExecutionTriggersType, ExecutionStatus as ExecutionStatusType, ExtraData } from "$lib/common/constants/types"; import { ExecutionStatus, ExecutionTriggers } from "$lib/common/constants/types"; import { parseEnumValue } from "$lib/common/utils"; +import { boolean } from "zod"; /** * Class representing an execution model. @@ -30,7 +31,7 @@ class ExecutionModel { /** * The function identifier associated with the execution, if available. */ - funtionId?: string; + functionId?: string; /** * The trigger type of the execution. @@ -91,14 +92,14 @@ class ExecutionModel { * Create a new ExecutionModel instance. * @param data - Data for initializing the execution model. */ - constructor(data: any) { + constructor(data: any, parse: boolean = false) { this.$id = data.$id || ''; this.$createdAt = data.$createdAt || ''; this.$updatedAt = data.$updatedAt || ''; this.$permissions = data.$permissions || ''; - this.funtionId = data.function || ''; - this.trigger = this.parseTrigger(data.trigger); - this.status = this.parseStatus(data.status); + this.functionId = data.functionId || ''; + this.trigger = data.trigger || ''; + this.status = data.status || ''; this.requestMethod = data.requestMethod || ''; this.requestPath = data.requestPath || ''; this.requestHeaders = this.parseHeaders(data.requestHeaders); @@ -107,7 +108,7 @@ class ExecutionModel { this.logs = data.logs || ''; this.errors = data.errors || ''; this.duration = data.duration || 0; - this.responseBody = data.responseBody || ''; + this.responseBody = parse? ExecutionModel.#parseBody(data.responseBody) : data.responseBody || ''; } /** @@ -146,6 +147,33 @@ class ExecutionModel { parseEnumValue(value: string, enumType: any) { return parseEnumValue(value, enumType); } + + /** + * + * @param data + * @returns + */ + static #parseBody(data: any){ + return JSON.parse(data); + } + + /** + * + * @param data + * @returns + */ + serialize(data: any){ + JSON.stringify(data) + } + + /** + * + * @param data + * @returns + */ + unserialize(data: any): T{ + return JSON.parse(data); + } } /** @@ -154,8 +182,8 @@ class ExecutionModel { * @param data - Data for initializing the execution model. * @returns A new ExecutionModel instance. */ -function createExecutionModel(data: T) { - return new ExecutionModel(data); +function createExecutionModel(data: T, parse: boolean = false) { + return new ExecutionModel(data, parse); } export { ExecutionModel, createExecutionModel }; \ No newline at end of file diff --git a/src/lib/stores/account.ts b/src/lib/stores/account.ts index 9158ce1..e9feaf0 100644 --- a/src/lib/stores/account.ts +++ b/src/lib/stores/account.ts @@ -15,10 +15,17 @@ export const AccountStore: Writable = writable(null); * @description Initialize AccountStore * @returns Promise void */ -export const InitAccountStore = async (): Promise => { +export const InitAccountStore = async (store?: AccountData): Promise => { try { - // @ts-ignore - AccountStore.set(await BackendPlatform.account.get()); + + if(!store){ + // @ts-ignore + AccountStore.set(await BackendPlatform.account.get()); + }else{ + // @ts-ignore + AccountStore.set(store); + } + }catch(e){ AccountStore.set(null); } diff --git a/src/routes/(auth)/login/+page.server.ts b/src/routes/(auth)/login/+page.server.ts new file mode 100644 index 0000000..9273eae --- /dev/null +++ b/src/routes/(auth)/login/+page.server.ts @@ -0,0 +1,68 @@ +import { fail, redirect } from "@sveltejs/kit"; +import type { Actions, Action, PageServerLoad } from "../../(backoffice)/dashboard/$types"; +import CONSTANTS from "$lib/common/constants"; +import { parseCookie } from "$lib/common/utils/parseCookie"; +import { SleepUtil } from "$lib/common/utils"; + + +export const load: PageServerLoad = async ({ }) => { + return { + + } +} + +const login: Action = async ({ cookies, request, fetch, locals }) => { + const data = await request.formData(); + + const email = data.get('email'); + const password = data.get('password'); + + if(typeof email !== 'string' || typeof password !== 'string'){ + return fail(400, { invalid: true }) + } + + const response = await fetch(`${CONSTANTS.API_CONSTANTS.APPWRITE_ENDPOINT}/account/sessions/email`, { + method: 'POST', + headers: { + "x-appwrite-project": CONSTANTS.API_CONSTANTS.PROJECT_ID, + "Content-Type": "application/json" + }, + body: JSON.stringify({ + email: email, + password: password + }) + }); + + const json = await response.json(); + + + if(json.code >= 400){ + return fail(json.code, { credentials: true }) + } + + const cookiePa = parseCookie({ + cookieString: response.headers.get('set-cookie') || '', + domain: 'localhost:5173', + projectId: CONSTANTS.API_CONSTANTS.PROJECT_ID, + secure: false, + samesite: 'strict' + }); + + + const cookieValue = cookiePa[`${CONSTANTS.getCookieName()}`]; + cookies.set(`${CONSTANTS.getCookieName()}`, `${cookieValue}`, { + httpOnly: true, + path: '/', + secure: true, + sameSite: "none", + expires: new Date(cookiePa.expires), + domain: 'localhost' + }); + + + + throw redirect(303, CONSTANTS.APP_PATHS.routes.backoffice); +} + + +export const actions: Actions = { login } \ No newline at end of file diff --git a/src/routes/(auth)/login/+page.svelte b/src/routes/(auth)/login/+page.svelte index f0ea622..c912f27 100644 --- a/src/routes/(auth)/login/+page.svelte +++ b/src/routes/(auth)/login/+page.svelte @@ -1,6 +1,25 @@
@@ -11,7 +30,7 @@ {$LanguageStore.loginSubHeading}

- +

{$LanguageStore.formAgreedText}{" "} diff --git a/src/routes/(auth)/logout/+page.server.ts b/src/routes/(auth)/logout/+page.server.ts new file mode 100644 index 0000000..a17e799 --- /dev/null +++ b/src/routes/(auth)/logout/+page.server.ts @@ -0,0 +1,23 @@ +import { redirect } from "@sveltejs/kit"; +import type { PageServerLoad, Actions } from "./$types"; +import CONSTANTS from "$lib/common/constants"; +import { AccountService } from "$lib/services"; + +export const load: PageServerLoad = async ({}) => { + throw redirect(302, '/'); +} + +export const actions: Actions = { + async default({ cookies }){ + const cookiesToDelete = [`${CONSTANTS.getCookieName()}`, 'a_session_t', 'x']; + await AccountService.deleteSession(); + cookiesToDelete.map((co) => { + cookies.set(`${co}`, '', { + path: '/', + expires: new Date(0) + }); + }) + + throw redirect(302, '/login') + }, +} \ No newline at end of file diff --git a/src/routes/(backoffice)/+layout.svelte b/src/routes/(backoffice)/+layout.svelte index d70ce0a..64c953c 100644 --- a/src/routes/(backoffice)/+layout.svelte +++ b/src/routes/(backoffice)/+layout.svelte @@ -1,8 +1,7 @@ Dashboard @@ -35,11 +29,11 @@

- +
- +
diff --git a/src/routes/(backoffice)/+layout.ts b/src/routes/(backoffice)/+layout.ts index afb701a..40e205d 100644 --- a/src/routes/(backoffice)/+layout.ts +++ b/src/routes/(backoffice)/+layout.ts @@ -1,5 +1,15 @@ import { InitAccountStore } from "$lib/stores"; +import type { LayoutServerLoad } from "../$types"; -export const load = async() => { - await InitAccountStore(); +export const load: LayoutServerLoad = async ({ locals }) => { + + if(locals?.accoundData){ + await InitAccountStore(locals.accoundData); + }else{ + await InitAccountStore(); + } + + return { + accountData: locals?.accoundData + } } \ No newline at end of file diff --git a/src/routes/(backoffice)/dashboard/+page.server.ts b/src/routes/(backoffice)/dashboard/+page.server.ts index 9a424fa..dce6d20 100644 --- a/src/routes/(backoffice)/dashboard/+page.server.ts +++ b/src/routes/(backoffice)/dashboard/+page.server.ts @@ -1,14 +1,14 @@ import type { PageServerLoad } from "./$types"; import type { LeadData } from "$lib/common/constants/types"; -import { DatabaseService, StorageService } from "$lib/services"; +import { DatabaseService, StorageService, FunctionService } from "$lib/services"; import CONSTANTS from "$lib/common/constants"; export const load: PageServerLoad = async () => { + const payload = {}; + //const functions = await FunctionService.createExecution('userActionControl', JSON.stringify(payload)); + return { - leads: await DatabaseService.listDocuments( - CONSTANTS.DATABASE_CONFIG.databases.test.id, - CONSTANTS.DATABASE_CONFIG.databases.test.collections.leads), - files: await StorageService.listFiles(CONSTANTS.DATABASE_CONFIG.buckets.dev) + } } \ No newline at end of file diff --git a/src/routes/(backoffice)/dashboard/+page.svelte b/src/routes/(backoffice)/dashboard/+page.svelte index 97d4d24..5610390 100644 --- a/src/routes/(backoffice)/dashboard/+page.svelte +++ b/src/routes/(backoffice)/dashboard/+page.svelte @@ -1,8 +1,40 @@ + + \ No newline at end of file diff --git a/src/routes/(backoffice)/settings/account/+page.server.ts b/src/routes/(backoffice)/settings/account/+page.server.ts index ea88944..cb77970 100644 --- a/src/routes/(backoffice)/settings/account/+page.server.ts +++ b/src/routes/(backoffice)/settings/account/+page.server.ts @@ -2,8 +2,11 @@ import { superValidate } from "sveltekit-superforms/server"; import type { PageServerLoad } from "./$types"; import { accountFormSchema } from "$lib/features/settings/widgets/forms/account-form.svelte"; import { fail, type Actions } from "@sveltejs/kit"; +import CONSTANTS from "$lib/common/constants"; +import SSRAppwriteClient from "$lib/platforms/appwrite/SSRAppwriteClient"; export const load: PageServerLoad = async () => { + return { form: superValidate(accountFormSchema) }; @@ -16,6 +19,14 @@ export const actions: Actions = { return fail(400, { form }); + }else{ + const jwtToken = event.cookies.get(CONSTANTS.CORE.cookieName); + if(jwtToken){ + const ssrClient = SSRAppwriteClient.getInstance(jwtToken); + const response = await ssrClient.account.updateName(form.data.name); + console.log("response", response); + } + } return { form diff --git a/src/routes/+layout.server.ts b/src/routes/+layout.server.ts new file mode 100644 index 0000000..e7e348e --- /dev/null +++ b/src/routes/+layout.server.ts @@ -0,0 +1,7 @@ +import type { LayoutServerLoad } from "./$types"; + +export const load: LayoutServerLoad = async ({ locals }) => { + return { + + } +} \ No newline at end of file diff --git a/src/routes/+layout.ts b/src/routes/+layout.ts index 1d39581..0c6d372 100644 --- a/src/routes/+layout.ts +++ b/src/routes/+layout.ts @@ -1,27 +1,22 @@ import { InitAccountStore, AccountStore } from "$lib/stores"; import { CheckIfUserIsLoggedIn } from "$lib/common/utils"; import { UpdateDebugStore } from "$lib/ui/widgets/debug-bar/store/DebugStore.js"; -import { DebugStore } from "$lib/ui/widgets/debug-bar/store/DebugStore.js"; import { get } from "svelte/store"; -export async function load({parent}){ - let start = performance.now(); +export async function load({ }){ await InitAccountStore(); const accountData = get(AccountStore); if(accountData){ } CheckIfUserIsLoggedIn(accountData); - let end = performance.now(); - - let responseTime = end -start; const debugStoreData = { route: { currentRoute: '', }, vitals: { - executionTime: responseTime, + executionTime: 0, memoryUsage: 120 }, request: {