diff --git a/package.json b/package.json index e3cabc6..fa2a983 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "prettier-plugin-svelte": "^2.7.0", "svelte": "^3.44.0", "svelte-check": "^2.7.1", + "svelte-loading-spinners": "^0.1.7", "svelte-preprocess": "^4.10.7", "tailwindcss": "^3.1.4", "tslib": "^2.3.1", @@ -45,6 +46,7 @@ "date-fns": "^2.28.0", "date-fns-tz": "^1.3.5", "dto-mapping": "^1.1.0", + "froala-editor": "^4.0.12", "http-status-codes": "^2.2.0", "js-cookie": "^3.0.1", "ky": "^0.31.0", @@ -55,6 +57,8 @@ "polka": "^0.5.2", "sass": "^1.53.0", "secure-random": "^1.1.2", - "svelte-material-icons": "^2.0.2" + "svelte-material-icons": "^2.0.2", + "svg-loaders": "^0.2.0", + "wysiwyg-editor-node-sdk": "^4.0.12" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0c73a2a..127bd24 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,6 +19,7 @@ specifiers: eslint: ^8.16.0 eslint-config-prettier: ^8.3.0 eslint-plugin-svelte3: ^4.0.0 + froala-editor: ^4.0.12 http-status-codes: ^2.2.0 js-cookie: ^3.0.1 ky: ^0.31.0 @@ -34,11 +35,14 @@ specifiers: secure-random: ^1.1.2 svelte: ^3.44.0 svelte-check: ^2.7.1 + svelte-loading-spinners: ^0.1.7 svelte-material-icons: ^2.0.2 svelte-preprocess: ^4.10.7 + svg-loaders: ^0.2.0 tailwindcss: ^3.1.4 tslib: ^2.3.1 typescript: ^4.7.2 + wysiwyg-editor-node-sdk: ^4.0.12 dependencies: '@sveltejs/adapter-node': 1.0.0-next.78 @@ -47,6 +51,7 @@ dependencies: date-fns: 2.28.0 date-fns-tz: 1.3.5_date-fns@2.28.0 dto-mapping: 1.1.0 + froala-editor: 4.0.12 http-status-codes: 2.2.0 js-cookie: 3.0.1 ky: 0.31.0 @@ -58,6 +63,8 @@ dependencies: sass: 1.53.0 secure-random: 1.1.2 svelte-material-icons: 2.0.2_svelte@3.48.0 + svg-loaders: 0.2.0 + wysiwyg-editor-node-sdk: 4.0.12 devDependencies: '@playwright/test': 1.23.0 @@ -77,6 +84,7 @@ devDependencies: prettier-plugin-svelte: 2.7.0_nakrehnrzdf7fdea5k3a4dfy4m svelte: 3.48.0 svelte-check: 2.8.0_s4vji4hbm6754nioyrbgjz6o3e + svelte-loading-spinners: 0.1.7 svelte-preprocess: 4.10.7_yzgb7wkzq6wz6qgj3h2t2u7ppa tailwindcss: 3.1.4 tslib: 2.4.0 @@ -614,6 +622,14 @@ packages: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} dev: true + /array-parallel/0.1.3: + resolution: {integrity: sha512-TDPTwSWW5E4oiFiKmz6RGJ/a80Y91GuLgUYuLd49+XBS75tYo8PNgaT2K/OxuQYqkoI852MDGBorg9OcUSTQ8w==} + dev: false + + /array-series/0.1.5: + resolution: {integrity: sha512-L0XlBwfx9QetHOsbLDrE/vh2t018w9462HM3iaFfxRiK83aJjAt/Ja3NMkOW7FICwWTlQBa3ZbL5FKhuQWkDrg==} + dev: false + /array-union/2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} @@ -675,6 +691,14 @@ packages: resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} dev: true + /busboy/0.2.14: + resolution: {integrity: sha512-InWFDomvlkEj+xWLBfU3AvnbVYqeTWmQopiW0tWWEy5yehYm2YkGEc59sUmw/4ty5Zj/b0WHGs1LgecuBSBGrg==} + engines: {node: '>=0.8.0'} + dependencies: + dicer: 0.2.5 + readable-stream: 1.1.14 + dev: false + /callsites/3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -697,6 +721,10 @@ packages: supports-color: 7.2.0 dev: true + /charenc/0.0.2: + resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} + dev: false + /chokidar/3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} @@ -747,7 +775,13 @@ packages: /core-util-is/1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - dev: true + + /cross-spawn/4.0.2: + resolution: {integrity: sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA==} + dependencies: + lru-cache: 4.1.5 + which: 1.3.1 + dev: false /cross-spawn/7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} @@ -758,6 +792,14 @@ packages: which: 2.0.2 dev: true + /crypt/0.0.2: + resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} + dev: false + + /crypto-js/3.3.0: + resolution: {integrity: sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==} + dev: false + /cssesc/3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} @@ -791,7 +833,6 @@ packages: optional: true dependencies: ms: 2.1.3 - dev: true /debug/4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} @@ -850,6 +891,14 @@ packages: minimist: 1.2.6 dev: true + /dicer/0.2.5: + resolution: {integrity: sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=} + engines: {node: '>=0.8.0'} + dependencies: + readable-stream: 1.1.14 + streamsearch: 0.1.2 + dev: false + /didyoumean/1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} dev: true @@ -1351,6 +1400,10 @@ packages: resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==} dev: true + /froala-editor/4.0.12: + resolution: {integrity: sha512-y4uh6DOKYddXZNx2lGhzng8KFHqb2/yD/u9SlT9zXQDwoo4N2AtINs8F4CwDmKFDiwMMaWEpEmWWgsFYQ8fo8Q==} + dev: false + /fs-minipass/1.2.7: resolution: {integrity: sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==} dependencies: @@ -1463,6 +1516,18 @@ packages: /globrex/0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + /gm/1.23.1: + resolution: {integrity: sha512-wYGVAa8/sh9ggF5qWoOs6eArcAgwEPkDNvf637jHRHkMUznvs7m/Q2vrc0KLN6B8px3nnRJqJcXK4mTK6lLFmg==} + engines: {node: '>= 0.10.0'} + dependencies: + array-parallel: 0.1.3 + array-series: 0.1.5 + cross-spawn: 4.0.2 + debug: 3.2.7 + transitivePeerDependencies: + - supports-color + dev: false + /graceful-fs/4.2.10: resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} dev: true @@ -1583,13 +1648,16 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + /isarray/0.0.1: + resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} + dev: false + /isarray/1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} dev: true /isexe/2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true /js-cookie/3.0.1: resolution: {integrity: sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==} @@ -1657,6 +1725,13 @@ packages: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true + /lru-cache/4.1.5: + resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} + dependencies: + pseudomap: 1.0.2 + yallist: 2.1.2 + dev: false + /lru-cache/6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} @@ -1693,6 +1768,10 @@ packages: resolution: {integrity: sha512-pGkZ5LJOLH/R3jlqL2HXGVi36cucTn/RxSkPtqsinxB2xoDE0fZStwAUZlMKcW0z4qqDamBwVvzM1IVQe6OQDw==} dev: false + /merge/2.1.1: + resolution: {integrity: sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==} + dev: false + /merge2/1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -1799,7 +1878,6 @@ packages: /ms/2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: true /multi-part-lite/1.0.0: resolution: {integrity: sha512-KxIRbBZZ45hoKX1ROD/19wJr0ql1bef1rE8Y1PCwD3PuNXV42pp7Wo8lEHYuAajoT4vfAFcd3rPjlkyEEyt1nw==} @@ -2164,6 +2242,10 @@ packages: engines: {node: '>= 0.6.0'} dev: false + /pseudomap/1.0.2: + resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} + dev: false + /punycode/2.1.1: resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} engines: {node: '>=6'} @@ -2194,6 +2276,15 @@ packages: pify: 2.3.0 dev: true + /readable-stream/1.1.14: + resolution: {integrity: sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==} + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 0.0.1 + string_decoder: 0.10.31 + dev: false + /readable-stream/2.3.7: resolution: {integrity: sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==} dependencies: @@ -2354,6 +2445,13 @@ packages: resolution: {integrity: sha512-cHMAtSXilfyBePduZEBVPTCftTQWz6ehWJD5YNUg4mqvRosrrjKbo4WS8JkB0/RxonMoohHm7cOGH60mDkRQ9w==} dev: true + /sha1/1.1.1: + resolution: {integrity: sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==} + dependencies: + charenc: 0.0.2 + crypt: 0.0.2 + dev: false + /shebang-command/2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -2392,6 +2490,11 @@ packages: resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} dev: true + /streamsearch/0.1.2: + resolution: {integrity: sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=} + engines: {node: '>=0.8.0'} + dev: false + /string-width/1.0.2: resolution: {integrity: sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==} engines: {node: '>=0.10.0'} @@ -2409,6 +2512,10 @@ packages: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 + /string_decoder/0.10.31: + resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==} + dev: false + /string_decoder/1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} dependencies: @@ -2499,6 +2606,10 @@ packages: svelte: 3.48.0 dev: true + /svelte-loading-spinners/0.1.7: + resolution: {integrity: sha512-EKCId1DjVL2RSUVJJsvtNcqQHox03XIgh4xh/4p7r6ST7d8mut6INY9/LqK4A17PFU64+3quZmqiSfOlf480CA==} + dev: true + /svelte-material-icons/2.0.2_svelte@3.48.0: resolution: {integrity: sha512-+kzpt2pOzHXgDteQFzYksZ64PaF4rdx8UtORR0v8LlBN/ZRzvHRsqEkhlux3c6r8GzPQeRdTjAP7pWQQfNisnA==} peerDependencies: @@ -2564,6 +2675,10 @@ packages: resolution: {integrity: sha512-fN2YRm/bGumvjUpu6yI3BpvZnpIm9I6A7HR4oUNYd7ggYyIwSA/BX7DJ+UXXffLp6XNcUijyLvttbPVCYa/3xQ==} engines: {node: '>= 8'} + /svg-loaders/0.2.0: + resolution: {integrity: sha512-yE4UtCqr8L45QKhZX6p4B07iZfFrDPXmDLfxqJN+uOeJ1gAxpTXA4qOIVvjv1JsguDFanrph1k9fF1jciB1NeQ==} + dev: false + /tailwindcss/3.1.4: resolution: {integrity: sha512-NrxbFV4tYsga/hpWbRyUfIaBrNMXDxx5BsHgBS4v5tlyjf+sDsgBg5m9OxjrXIqAS/uR9kicxLKP+bEHI7BSeQ==} engines: {node: '>=12.13.0'} @@ -2749,6 +2864,13 @@ packages: tr46: 0.0.3 webidl-conversions: 3.0.1 + /which/1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: false + /which/2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -2778,6 +2900,18 @@ packages: /wrappy/1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + /wysiwyg-editor-node-sdk/4.0.12: + resolution: {integrity: sha512-4tiI52IdHzPuXQ+Kq1w4u7PG1yeNZwu5QKQ86/VdNmOeD8x0qiLcpM1IO92Jo6NrsLwNfXY3kYc14YKdPuoJ6g==} + dependencies: + busboy: 0.2.14 + crypto-js: 3.3.0 + gm: 1.23.1 + merge: 2.1.1 + sha1: 1.1.1 + transitivePeerDependencies: + - supports-color + dev: false + /x3-linkedlist/1.2.0: resolution: {integrity: sha512-mH/YwxpYSKNa8bDNF1yOuZCMuV+K80LtDN8vcLDUAwNazCxptDNsYt+zA/EJeYiGbdtKposhKLZjErGVOR8mag==} engines: {node: '>=10'} @@ -2796,6 +2930,10 @@ packages: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} + /yallist/2.1.2: + resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} + dev: false + /yallist/3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} dev: true diff --git a/src/hooks.ts b/src/hooks.ts index 92e8a52..e4ed675 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -2,8 +2,9 @@ import type {RequestEvent, ResolveOptions} from '@sveltejs/kit'; import type {MaybePromise} from '@sveltejs/kit/types/private'; import _ from 'lodash-es'; import njwt from 'njwt'; -import {CookieParser} from './lib/cookie-parser'; -import {key} from './lib/auth/user/server'; +import {CookieParser} from '$lib/cookie-parser'; +import {key} from '$lib/auth/user/server'; +import type {EUserRanks} from '$lib/types/user-ranks'; /** @type {import('@sveltejs/kit').Handle} */ export async function handle({event, resolve}: HandleParameter) { @@ -38,14 +39,25 @@ async function getUser(cookie: string | null) { } } - const body = jwt.body.toJSON(); + return jwt.body.toJSON(); + // console.log(body) +} + +/** @type {import('@sveltejs/kit').GetSession} */ +export function getSession(event: RequestEvent) { + return event.locals.user; } declare global { // eslint-disable-next-line @typescript-eslint/no-namespace namespace App { interface Locals { - user: any + user: any; + } + + interface Session { + uid: string; + rank: EUserRanks; } } } diff --git a/src/lib/auth/user/client.ts b/src/lib/auth/user/client.ts index b949e23..4e1d73e 100644 --- a/src/lib/auth/user/client.ts +++ b/src/lib/auth/user/client.ts @@ -41,6 +41,7 @@ export class User { const res = await r.json(); return res.token; } + } export interface ILoginResponse { diff --git a/src/lib/auth/user/server.ts b/src/lib/auth/user/server.ts index f2a900a..98e73a9 100644 --- a/src/lib/auth/user/server.ts +++ b/src/lib/auth/user/server.ts @@ -22,11 +22,11 @@ export class User { if (!await this.exists) { return reject('user not exists'); } - + console.log(2) db.query(aql` for user in users filter user.id == ${this.id} - return user`) + RETURN user`) .then(async (cursor) => { if (!cursor.hasNext) { return reject('no user found'); @@ -44,12 +44,29 @@ export class User { return this.stored; } + get uid(): Promise { + return new Promise((resolve, reject) => { + this.loadUserData() + .then((user) => resolve(user._key)) + .catch(reject); + }); + } + + get rank(): Promise { + return new Promise((resolve, reject) => { + this.loadUserData() + .then((user) => resolve(user.rank)) + .catch(reject); + }); + } + get exists(): Promise { return new Promise(async (resolve, reject) => { + console.log(1) db.query(aql` for user in users filter user.id == ${this.id} - return user`) + RETURN user`) .then(async (r) => { resolve(r.hasNext); }) @@ -57,6 +74,18 @@ export class User { }); } + static async getByUniqueId(uid: string): Promise { + try { + const cursor = await db.query(aql` + for user in users + filter user._key == ${uid} + return user`); + return await cursor.next(); + } catch { + return null; + } + } + async register(password: string) { if (await this.exists) { throw Error('user exists already'); @@ -77,12 +106,12 @@ export class User { const user = await this.loadUserData(); return await argon2.verify(user.password, password); } catch (e) { - console.log(e) + console.log(e); return false; } } - token(type: 'user' | 'refesh', payload: Rec = {}) { + token(type: 'user' | 'refesh', payload: Rec = {}) { return njwt.create({ iss: 'https://now.gd/', sub: `user/${this.id}`, @@ -93,6 +122,7 @@ export class User { } export interface IUserInfo extends IArangoDocumentIdentifier { + id: string; password: string; // hashed rank: EUserRanks; } \ No newline at end of file diff --git a/src/lib/community/article/client.ts b/src/lib/community/article/client.ts new file mode 100644 index 0000000..0c1ce8c --- /dev/null +++ b/src/lib/community/article/client.ts @@ -0,0 +1,18 @@ +import type {Board} from '$lib/community/board/client'; +import ky from 'ky-universal'; +import type {IArangoDocumentIdentifier} from '$lib/database'; +import { goto } from '$app/navigation'; + +export class Article { + constructor(private readonly board: Board) { + + } + + async write(title: string, content: string, tags: string[]) { + const res = await ky.post(`/community/${this.board.id}/api/write`, { + json: {title, content, tags}, + }); + const {_key} = await res.json(); + await goto(`/community/${this.board.id}/${_key}`); + } +} \ No newline at end of file diff --git a/src/lib/community/article.ts b/src/lib/community/article/server.ts similarity index 68% rename from src/lib/community/article.ts rename to src/lib/community/article/server.ts index 0089ce5..fcbfc7a 100644 --- a/src/lib/community/article.ts +++ b/src/lib/community/article/server.ts @@ -26,5 +26,16 @@ export class ArticleManager { }); } + /** + * 태그를 추가합니다. (누적도 동일) + * @param tag 추가할 태그 이름입니다. + */ + async addTag(tag: string) { + if (/\s/.exec(tag) !== null) { + throw new Error('whitespace not allowed in tag'); + } + + // todo: 태그 추가 + } } \ No newline at end of file diff --git a/src/lib/community/board.ts b/src/lib/community/board.ts deleted file mode 100644 index fbd64f3..0000000 --- a/src/lib/community/board.ts +++ /dev/null @@ -1,32 +0,0 @@ -import db from '../database/instance'; -import {aql} from 'arangojs/aql'; -import type {EUserRanks} from '../types/user-ranks'; - -export class BoardManager { - constructor(private readonly id: string) { - } - - create() { - db.query(aql` - insert ${{}}`); - } - - get exists(): Promise { - return new Promise(async (resolve, reject) => { - db.query(aql` - for board from boards - filter board._key == ${this.id} - return bid`) - .then((result) => { - resolve(result.hasNext) - }) - .catch(reject); - }); - } -} - -export interface INewBoardInfo { - name: string; - min: EUserRanks; - blocked: boolean; -} \ No newline at end of file diff --git a/src/lib/community/board/client.ts b/src/lib/community/board/client.ts new file mode 100644 index 0000000..872e992 --- /dev/null +++ b/src/lib/community/board/client.ts @@ -0,0 +1,27 @@ +import ky from 'ky-universal'; +import type {IArangoDocumentIdentifier} from '$lib/database'; +import type {IBoardConfig} from '$lib/types/board'; + +export class Board { + constructor(readonly id: string) { + } + + static async new(config: IBoardConfig): Promise { + const response = await ky.post('/community/admin/add?type=board', { + json: config, + }); + const {_key} = await response.json(); + return _key; + } + + /** + * + * @param after 여기에 주어진 게시글 번호 이후부터 불러옵니다. + * @param order 정렬 순서입니다. + * @return - 게시글 목록을 반환합니다. {_key, name, author(mapped), viewer, tags,}[] + */ + async listArticles(after = '', order: 'asc' | 'desc' = 'desc') { + const res = await ky.get(`/community/${this.id}/read?after=${after}&order=${order}`); + + } +} \ No newline at end of file diff --git a/src/lib/community/board/server.ts b/src/lib/community/board/server.ts new file mode 100644 index 0000000..34cd4c5 --- /dev/null +++ b/src/lib/community/board/server.ts @@ -0,0 +1,35 @@ +import db from '$lib/database/instance'; +import {aql} from 'arangojs/aql'; +import type {EUserRanks} from '$lib/types/user-ranks'; + +export class Board { + constructor(private readonly id: string) { + } + + async create(title: string, pub: boolean,) { + const cursor = await db.query(aql` + insert ${{title, pub}} into boards return NEW`); + + return await cursor.next() + } + + get exists(): Promise { + return new Promise(async (resolve, reject) => { + db.query(aql` + for board in boards + filter board._key == ${this.id} + return board`) + .then(async (result) => { + // console.log(result.hasNext, await result.next()) + resolve(result.hasNext) + }) + .catch(reject); + }); + } +} + +export interface INewBoardInfo { + name: string; + min: EUserRanks; + blocked: boolean; +} \ No newline at end of file diff --git a/src/lib/components/ArticleList.svelte b/src/lib/components/ArticleList.svelte index 90f6c0b..71f056a 100644 --- a/src/lib/components/ArticleList.svelte +++ b/src/lib/components/ArticleList.svelte @@ -1,7 +1,15 @@ - +
+
    + {#each list as article} +
  • + {article.title} +
  • + {/each} +
+
\ No newline at end of file diff --git a/src/lib/components/Login.svelte b/src/lib/components/Login.svelte index 2b8b0ba..a715e73 100644 --- a/src/lib/components/Login.svelte +++ b/src/lib/components/Login.svelte @@ -2,20 +2,34 @@ import {createEventDispatcher} from 'svelte'; import {ELoginError} from '$lib/errors/login'; import {goto} from '$app/navigation'; + import {Pulse} from 'svelte-loading-spinners' const dispatch = createEventDispatcher(); - let password: HTMLInputElement; - let id = '', pw = ''; + let passwordInput: HTMLInputElement; + let loginButton: HTMLButtonElement; + let id = '', password = ''; + let loading = false; let error: ELoginError = ELoginError.None; + function done() { + loading = false; + loginButton.disabled = false; + } + function login() { - if (pw.length <= 5) { + if (loading) { + return; + } + + if (password.length <= 5) { error = ELoginError.PW_TOO_SHORT; return; } - dispatch('login', {id, pw}) + loginButton.disabled = true; + + dispatch('login', {id, password, whenDone: done}); // console.log('fired') } @@ -26,7 +40,7 @@ error = ELoginError.ID_TOO_SHORT; return; } - return password.focus(); + return passwordInput.focus(); } if (type === 1) { @@ -39,21 +53,84 @@ -
+ checkEnter(e, 0)} bind:value={id} class="w-full shadow-md rounded-md px-4 py-2 focus:outline-0"> checkEnter(e, 1)} - bind:this={password} bind:value={pw} + bind:this={passwordInput} bind:value={password} class="w-full shadow-md rounded-md px-4 py-2 focus:outline-0"> -
-
-
\ No newline at end of file + +
+
+ +
+
+ +
+
+ +
+
+ + + \ No newline at end of file diff --git a/src/lib/components/Nav.svelte b/src/lib/components/Nav.svelte index ce04544..ef7dcb2 100644 --- a/src/lib/components/Nav.svelte +++ b/src/lib/components/Nav.svelte @@ -1,27 +1,156 @@ - -