diff --git a/next.config.js b/next.config.js index b7a1f35..ae05198 100644 --- a/next.config.js +++ b/next.config.js @@ -2,6 +2,7 @@ const nextConfig = { experimental: { serverComponentsExternalPackages: ['sequelize', 'sequelize-typescript'], + serverActions: true, } } diff --git a/package-lock.json b/package-lock.json index dbb4996..c039c25 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,18 +11,21 @@ "@types/bcrypt": "^5.0.0", "@types/cookie": "^0.5.1", "@types/node": "20.1.7", - "@types/react": "18.2.6", + "@types/react": "18.2.30", "@types/react-bootstrap": "^0.32.32", - "@types/react-dom": "18.2.4", + "@types/react-dom": "18.2.14", "autoprefixer": "10.4.14", "bcrypt": "^5.1.0", "bootstrap": "^5.3.0", "cookie": "^0.5.0", "eslint": "8.40.0", "eslint-config-next": "13.4.2", + "fetch-cookie": "^3.0.1", + "flowbite": "^2.3.0", + "flowbite-react": "^0.7.5", "mysql": "^2.18.1", "mysql2": "^3.3.3", - "next": "13.4.2", + "next": "14.1.4", "pg-hstore": "^2.3.4", "postcss": "8.4.23", "react": "18.2.0", @@ -31,6 +34,7 @@ "sequelize": "^6.32.0", "sqlite": "^4.2.1", "tailwindcss": "3.3.2", + "ts-node": "^10.9.2", "typescript": "5.0.4" }, "devDependencies": { @@ -67,6 +71,26 @@ "node": ">=6.9.0" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -119,6 +143,54 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz", + "integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==", + "dependencies": { + "@floating-ui/utils": "^0.2.1" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.3.tgz", + "integrity": "sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==", + "dependencies": { + "@floating-ui/core": "^1.0.0", + "@floating-ui/utils": "^0.2.0" + } + }, + "node_modules/@floating-ui/react": { + "version": "0.26.9", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.9.tgz", + "integrity": "sha512-p86wynZJVEkEq2BBjY/8p2g3biQ6TlgT4o/3KgFKyTWoJLU1GZ8wpctwRqtkEl2tseYA+kw7dBAIDFcednfI5w==", + "dependencies": { + "@floating-ui/react-dom": "^2.0.8", + "@floating-ui/utils": "^0.2.1", + "tabbable": "^6.0.1" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz", + "integrity": "sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==", + "dependencies": { + "@floating-ui/dom": "^1.6.1" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + }, "node_modules/@gar/promisify": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", @@ -276,9 +348,9 @@ } }, "node_modules/@next/env": { - "version": "13.4.2", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.2.tgz", - "integrity": "sha512-Wqvo7lDeS0KGwtwg9TT9wKQ8raelmUxt+TQKWvG/xKfcmDXNOtCuaszcfCF8JzlBG1q0VhpI6CKaRMbVPMDWgw==" + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.1.4.tgz", + "integrity": "sha512-e7X7bbn3Z6DWnDi75UWn+REgAbLEqxI8Tq2pkFOFAMpWAWApz/YCUhtWMWn410h8Q2fYiYL7Yg5OlxMOCfFjJQ==" }, "node_modules/@next/eslint-plugin-next": { "version": "13.4.2", @@ -289,9 +361,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "13.4.2", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.2.tgz", - "integrity": "sha512-6BBlqGu3ewgJflv9iLCwO1v1hqlecaIH2AotpKfVUEzUxuuDNJQZ2a4KLb4MBl8T9/vca1YuWhSqtbF6ZuUJJw==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.1.4.tgz", + "integrity": "sha512-ubmUkbmW65nIAOmoxT1IROZdmmJMmdYvXIe8211send9ZYJu+SqxSnJM4TrPj9wmL6g9Atvj0S/2cFmMSS99jg==", "cpu": [ "arm64" ], @@ -304,9 +376,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "13.4.2", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.2.tgz", - "integrity": "sha512-iZuYr7ZvGLPjPmfhhMl0ISm+z8EiyLBC1bLyFwGBxkWmPXqdJ60mzuTaDSr5WezDwv0fz32HB7JHmRC6JVHSZg==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.4.tgz", + "integrity": "sha512-b0Xo1ELj3u7IkZWAKcJPJEhBop117U78l70nfoQGo4xUSvv0PJSTaV4U9xQBLvZlnjsYkc8RwQN1HoH/oQmLlQ==", "cpu": [ "x64" ], @@ -319,9 +391,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.4.2", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.2.tgz", - "integrity": "sha512-2xVabFtIge6BJTcJrW8YuUnYTuQjh4jEuRuS2mscyNVOj6zUZkom3CQg+egKOoS+zh2rrro66ffSKIS+ztFJTg==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.4.tgz", + "integrity": "sha512-457G0hcLrdYA/u1O2XkRMsDKId5VKe3uKPvrKVOyuARa6nXrdhJOOYU9hkKKyQTMru1B8qEP78IAhf/1XnVqKA==", "cpu": [ "arm64" ], @@ -334,9 +406,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "13.4.2", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.2.tgz", - "integrity": "sha512-wKRCQ27xCUJx5d6IivfjYGq8oVngqIhlhSAJntgXLt7Uo9sRT/3EppMHqUZRfyuNBTbykEre1s5166z+pvRB5A==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.4.tgz", + "integrity": "sha512-l/kMG+z6MB+fKA9KdtyprkTQ1ihlJcBh66cf0HvqGP+rXBbOXX0dpJatjZbHeunvEHoBBS69GYQG5ry78JMy3g==", "cpu": [ "arm64" ], @@ -349,9 +421,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "13.4.2", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.2.tgz", - "integrity": "sha512-NpCa+UVhhuNeaFVUP1Bftm0uqtvLWq2JTm7+Ta48+2Uqj2mNXrDIvyn1DY/ZEfmW/1yvGBRaUAv9zkMkMRixQA==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.4.tgz", + "integrity": "sha512-BapIFZ3ZRnvQ1uWbmqEGJuPT9cgLwvKtxhK/L2t4QYO7l+/DxXuIGjvp1x8rvfa/x1FFSsipERZK70pewbtJtw==", "cpu": [ "x64" ], @@ -364,9 +436,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "13.4.2", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.2.tgz", - "integrity": "sha512-ZWVC72x0lW4aj44e3khvBrj2oSYj1bD0jESmyah3zG/3DplEy/FOtYkMzbMjHTdDSheso7zH8GIlW6CDQnKhmQ==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.4.tgz", + "integrity": "sha512-mqVxTwk4XuBl49qn2A5UmzFImoL1iLm0KQQwtdRJRKl21ylQwwGCxJtIYo2rbfkZHoSKlh/YgztY0qH3wG1xIg==", "cpu": [ "x64" ], @@ -379,9 +451,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.4.2", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.2.tgz", - "integrity": "sha512-pLT+OWYpzJig5K4VKhLttlIfBcVZfr2+Xbjra0Tjs83NQSkFS+y7xx+YhCwvpEmXYLIvaggj2ONPyjbiigOvHQ==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.4.tgz", + "integrity": "sha512-xzxF4ErcumXjO2Pvg/wVGrtr9QQJLk3IyQX1ddAC/fi6/5jZCZ9xpuL9Tzc4KPWMFq8GGWFVDMshZOdHGdkvag==", "cpu": [ "arm64" ], @@ -394,9 +466,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.4.2", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.2.tgz", - "integrity": "sha512-dhpiksQCyGca4WY0fJyzK3FxMDFoqMb0Cn+uDB+9GYjpU2K5//UGPQlCwiK4JHxuhg8oLMag5Nf3/IPSJNG8jw==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.4.tgz", + "integrity": "sha512-WZiz8OdbkpRw6/IU/lredZWKKZopUMhcI2F+XiMAcPja0uZYdMTZQRoQ0WZcvinn9xZAidimE7tN9W5v9Yyfyw==", "cpu": [ "ia32" ], @@ -409,9 +481,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "13.4.2", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.2.tgz", - "integrity": "sha512-O7bort1Vld00cu8g0jHZq3cbSTUNMohOEvYqsqE10+yfohhdPHzvzO+ziJRz4Dyyr/fYKREwS7gR4JC0soSOMw==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.4.tgz", + "integrity": "sha512-4Rto21sPfw555sZ/XNLqfxDUNeLhNYGO2dlPqsnuCg8N8a2a9u1ltqBOPQ4vj1Gf7eJC0W2hHG2eYUHuiXgY2w==", "cpu": [ "x64" ], @@ -558,9 +630,9 @@ "integrity": "sha512-RbhOOTCNoCrbfkRyoXODZp75MlpiHMgbE5MEBZAnnnLyQNgrigEj4p0lzsMDyc1zVsJDLrivB58tgg3emX0eEA==" }, "node_modules/@swc/helpers": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", - "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", + "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", "dependencies": { "tslib": "^2.4.0" } @@ -575,6 +647,26 @@ "node": ">= 6" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" + }, "node_modules/@types/bcrypt": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.2.tgz", @@ -617,9 +709,9 @@ "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" }, "node_modules/@types/react": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.6.tgz", - "integrity": "sha512-wRZClXn//zxCFW+ye/D2qY65UsYP1Fpex2YXorHc8awoNamkMZSvBxwxdYVInsHOZZd2Ppq8isnSzJL5Mpf8OA==", + "version": "18.2.30", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.30.tgz", + "integrity": "sha512-OfqdJnDsSo4UNw0bqAjFCuBpLYQM7wvZidz0hVxHRjrEkzRlvZL1pJVyOSY55HMiKvRNEo9DUBRuEl7FNlJ/Vg==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -635,9 +727,9 @@ } }, "node_modules/@types/react-dom": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.4.tgz", - "integrity": "sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==", + "version": "18.2.14", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.14.tgz", + "integrity": "sha512-V835xgdSVmyQmI1KLV2BEIUgqEuinxp9O4G6g3FqO/SqLac049E53aysv0oEFD2kHfejeKU+ZqL2bcFWj9gLAQ==", "dependencies": { "@types/react": "*" } @@ -785,6 +877,14 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -1593,6 +1693,11 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1627,6 +1732,17 @@ "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==" }, + "node_modules/debounce": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-2.0.0.tgz", + "integrity": "sha512-xRetU6gL1VJbs85Mc4FoEGSjQxzpdxRyFhe3lmWFyy2EzydIcD4xzUvRJMD+NPDfMwKNhxa3PvsIOU32luIWeA==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1738,6 +1854,14 @@ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -2448,6 +2572,15 @@ "reusify": "^1.0.4" } }, + "node_modules/fetch-cookie": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-3.0.1.tgz", + "integrity": "sha512-ZGXe8Y5Z/1FWqQ9q/CrJhkUD73DyBU9VF0hBQmEO/wPHe4A9PKTjplFDLeFX8aOsYypZUcX5Ji/eByn3VCVO3Q==", + "dependencies": { + "set-cookie-parser": "^2.4.8", + "tough-cookie": "^4.0.0" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -2509,6 +2642,33 @@ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==" }, + "node_modules/flowbite": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/flowbite/-/flowbite-2.3.0.tgz", + "integrity": "sha512-pm3JRo8OIJHGfFYWgaGpPv8E+UdWy0Z3gEAGufw+G/1dusaU/P1zoBLiQpf2/+bYAi+GBQtPVG86KYlV0W+AFQ==", + "dependencies": { + "@popperjs/core": "^2.9.3", + "mini-svg-data-uri": "^1.4.3" + } + }, + "node_modules/flowbite-react": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/flowbite-react/-/flowbite-react-0.7.5.tgz", + "integrity": "sha512-Zt2joKS29xLfsmOpMjpSVkHo3qwYrneGui78prJ97LbelFmK4WvAEIhjp5DWLgCkw94hvv5qFxQpZmksh6re5g==", + "dependencies": { + "@floating-ui/react": "^0.26.2", + "classnames": "^2.5.1", + "debounce": "^2.0.0", + "flowbite": "^2.0.0", + "react-icons": "^4.11.0", + "tailwind-merge": "^2.0.0" + }, + "peerDependencies": { + "react": "^18", + "react-dom": "^18", + "tailwindcss": "^3" + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -3639,6 +3799,11 @@ "semver": "bin/semver.js" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, "node_modules/make-fetch-happen": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", @@ -3712,6 +3877,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/mini-svg-data-uri": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", + "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", + "bin": { + "mini-svg-data-uri": "cli.js" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3973,39 +4146,37 @@ } }, "node_modules/next": { - "version": "13.4.2", - "resolved": "https://registry.npmjs.org/next/-/next-13.4.2.tgz", - "integrity": "sha512-aNFqLs3a3nTGvLWlO9SUhCuMUHVPSFQC0+tDNGAsDXqx+WJDFSbvc233gOJ5H19SBc7nw36A9LwQepOJ2u/8Kg==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/next/-/next-14.1.4.tgz", + "integrity": "sha512-1WTaXeSrUwlz/XcnhGTY7+8eiaFvdet5z9u3V2jb+Ek1vFo0VhHKSAIJvDWfQpttWjnyw14kBeq28TPq7bTeEQ==", "dependencies": { - "@next/env": "13.4.2", - "@swc/helpers": "0.5.1", + "@next/env": "14.1.4", + "@swc/helpers": "0.5.2", "busboy": "1.6.0", - "caniuse-lite": "^1.0.30001406", - "postcss": "8.4.14", - "styled-jsx": "5.1.1", - "zod": "3.21.4" + "caniuse-lite": "^1.0.30001579", + "graceful-fs": "^4.2.11", + "postcss": "8.4.31", + "styled-jsx": "5.1.1" }, "bin": { "next": "dist/bin/next" }, "engines": { - "node": ">=16.8.0" + "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "13.4.2", - "@next/swc-darwin-x64": "13.4.2", - "@next/swc-linux-arm64-gnu": "13.4.2", - "@next/swc-linux-arm64-musl": "13.4.2", - "@next/swc-linux-x64-gnu": "13.4.2", - "@next/swc-linux-x64-musl": "13.4.2", - "@next/swc-win32-arm64-msvc": "13.4.2", - "@next/swc-win32-ia32-msvc": "13.4.2", - "@next/swc-win32-x64-msvc": "13.4.2" + "@next/swc-darwin-arm64": "14.1.4", + "@next/swc-darwin-x64": "14.1.4", + "@next/swc-linux-arm64-gnu": "14.1.4", + "@next/swc-linux-arm64-musl": "14.1.4", + "@next/swc-linux-x64-gnu": "14.1.4", + "@next/swc-linux-x64-musl": "14.1.4", + "@next/swc-win32-arm64-msvc": "14.1.4", + "@next/swc-win32-ia32-msvc": "14.1.4", + "@next/swc-win32-x64-msvc": "14.1.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", - "fibers": ">= 3.1.0", - "node-sass": "^6.0.0 || ^7.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "sass": "^1.3.0" @@ -4014,21 +4185,15 @@ "@opentelemetry/api": { "optional": true }, - "fibers": { - "optional": true - }, - "node-sass": { - "optional": true - }, "sass": { "optional": true } } }, "node_modules/next/node_modules/postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "funding": [ { "type": "opencollective", @@ -4037,10 +4202,14 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -4764,6 +4933,11 @@ "react": ">=0.14.0" } }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -4782,6 +4956,11 @@ "node": ">=6" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -4877,6 +5056,14 @@ "react": "^18.2.0" } }, + "node_modules/react-icons": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.12.0.tgz", + "integrity": "sha512-IBaDuHiShdZqmfc/TwHu6+d6k2ltNCf3AszxNmjJc1KUfXdEeRJOKyNvLmAHaarhzGmTSVygNdyu8/opXv2gaw==", + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -4977,6 +5164,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -5229,6 +5421,11 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, + "node_modules/set-cookie-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", + "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -5740,6 +5937,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" + }, + "node_modules/tailwind-merge": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.2.2.tgz", + "integrity": "sha512-tWANXsnmJzgw6mQ07nE3aCDkCK4QdT3ThPMCzawoYA2Pws7vSTCvz3Vrjg61jVUGfFZPJzxEP+NimbcW+EdaDw==", + "dependencies": { + "@babel/runtime": "^7.24.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, "node_modules/tailwindcss": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz", @@ -5897,6 +6111,20 @@ "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", "integrity": "sha512-OsLcGGbYF3rMjPUf8oKktyvCiUxSbqMMS39m33MAjLTC1DVIH6x3WSt63/M77ihI09+Sdfk1AXvfhCEeUmC7mg==" }, + "node_modules/tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -5907,6 +6135,53 @@ "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -6110,6 +6385,14 @@ "imurmurhash": "^0.1.4" } }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/update-browserslist-db": { "version": "1.0.13", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", @@ -6147,6 +6430,15 @@ "punycode": "^2.1.0" } }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -6160,6 +6452,11 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" + }, "node_modules/validator": { "version": "13.11.0", "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", @@ -6406,6 +6703,14 @@ "node": ">= 14" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -6416,14 +6721,6 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } - }, - "node_modules/zod": { - "version": "3.21.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", - "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } } } } diff --git a/package.json b/package.json index 756788c..61b02ae 100644 --- a/package.json +++ b/package.json @@ -12,18 +12,21 @@ "@types/bcrypt": "^5.0.0", "@types/cookie": "^0.5.1", "@types/node": "20.1.7", - "@types/react": "18.2.6", + "@types/react": "18.2.30", "@types/react-bootstrap": "^0.32.32", - "@types/react-dom": "18.2.4", + "@types/react-dom": "18.2.14", "autoprefixer": "10.4.14", "bcrypt": "^5.1.0", "bootstrap": "^5.3.0", "cookie": "^0.5.0", "eslint": "8.40.0", "eslint-config-next": "13.4.2", + "fetch-cookie": "^3.0.1", + "flowbite": "^2.3.0", + "flowbite-react": "^0.7.5", "mysql": "^2.18.1", "mysql2": "^3.3.3", - "next": "13.4.2", + "next": "14.1.4", "pg-hstore": "^2.3.4", "postcss": "8.4.23", "react": "18.2.0", @@ -32,6 +35,7 @@ "sequelize": "^6.32.0", "sqlite": "^4.2.1", "tailwindcss": "3.3.2", + "ts-node": "^10.9.2", "typescript": "5.0.4" }, "devDependencies": { diff --git a/src/api/user.ts b/src/api/user.ts index 674134b..82d43ac 100644 --- a/src/api/user.ts +++ b/src/api/user.ts @@ -1,8 +1,9 @@ -import { MUser } from "@/model/sequelize/User"; -import { MAuth } from "@/model/sequelize/Auth"; +// import { MUser } from "@/model/sequelize/User"; +// import { MAuth } from "@/model/sequelize/Auth"; import { validatePassword } from "@/util/Auth"; import { APIError } from "@/api/error"; +import { User, Auth } from "@/model/sequelize/NewModels"; export function parseBasicAuth(authb64:string):UserAuth { @@ -22,7 +23,7 @@ export type UserAuth = { export async function getAssociatedUser(auth:UserAuth) { const username = auth.username; - let foundUser = await MUser.findOne({ where: {username: auth.username} }); + let foundUser = await User.findOne({ attributes: {include: ['password']}, where: {username: auth.username} }); if (!foundUser) throw new APIError({status: 401, responseText:"Unauthorized: Invalid Username"}); diff --git a/src/app/admin/login/page.tsx b/src/app/admin/login/page.tsx new file mode 100644 index 0000000..f85133e --- /dev/null +++ b/src/app/admin/login/page.tsx @@ -0,0 +1,40 @@ +'use client' + +import { authenticate } from '@/app/lib/actions' +import { useFormState, useFormStatus } from "react-dom"; +import { cookies } from 'next/headers'; + + +export default function Page(state:any) { + const [loginResult, dispatch] = useFormState(authenticate, undefined) + console.log(dispatch); + + console.log(state); + // if(loginResult?.cookie && loginResult.cookie){ + // cookies().set('auth',loginResult.cookie['auth']) + // } + + return ( +
+
+ + +
{loginResult?.errorMessage &&

{loginResult?.errorMessage}

}
+ + +
+

{""+loginResult?.cookie}

+
+
+ ) +} + +function LoginButton() { + const { pending } = useFormStatus() + + return ( + + ) +} \ No newline at end of file diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 08f89a4..479e258 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -1,58 +1,13 @@ -'use client' -import Container from 'react-bootstrap/Container'; -import Nav from 'react-bootstrap/Nav'; -import Navbar from 'react-bootstrap/Navbar'; -import NavDropdown from 'react-bootstrap/NavDropdown'; -import Button from 'react-bootstrap/Button'; -import Form from 'react-bootstrap/Form'; +import AdminPanel from "@/components/admin/adminPanel"; +import AuthHandler from "@/components/admin/authHandler"; +import { cookies } from "next/headers"; -export default function Page(){ - return
- - - React-Bootstrap - - - - - - - -
- - Email address - - - We'll never share your email with anyone else. - - - - - Password - - - - - - -
-
-
+export default async function Page(){ + return ( +
+

this is only shown on the admin panel

+
{JSON.stringify(cookies().getAll())}
+
+ ); } \ No newline at end of file diff --git a/src/app/api/[...slug]/route.ts b/src/app/api/[...slug]/route.ts index 0eed7a0..6f7544c 100644 --- a/src/app/api/[...slug]/route.ts +++ b/src/app/api/[...slug]/route.ts @@ -14,7 +14,7 @@ export async function GET(request:Request, { params }: {params:{slug: string}}){ // @ts-ignore cookies().set('name', 'lee'); return Response.json({ - "a": "kanker", + "a": "lorem", "b": params }); } diff --git a/src/app/api/auth/route.ts b/src/app/api/auth/route.ts index fd92106..53c882d 100644 --- a/src/app/api/auth/route.ts +++ b/src/app/api/auth/route.ts @@ -41,7 +41,7 @@ async function tryAuth(request:Request){ return new Response("error",{status:500}); - const kanker = await authentication.getUser(); + const authUser = await authentication.getUser(); // @ts-ignore cookies().set('auth', JSON.stringify(authentication)); @@ -51,7 +51,7 @@ async function tryAuth(request:Request){ { credentials: userAuth, auth: authentication, - kanker: kanker, + user: authUser, foundAuth: foundAuth }), { diff --git a/src/app/api/auth/validate/route.ts b/src/app/api/auth/validate/route.ts new file mode 100644 index 0000000..a00f847 --- /dev/null +++ b/src/app/api/auth/validate/route.ts @@ -0,0 +1,64 @@ +'use server' + +import { Model } from "sequelize"; +import { cookies } from "next/headers"; + +import { Auth, Post, User } from "@/model/sequelize/NewModels"; + + +import { APIError} from "@/api/error" +import { UserAuth, parseBasicAuth, getAssociatedUser } from "@/api/user" + + +async function tryAuth(request:Request){ + + // await User.sync(); + await Auth.sync(); + + + const koek = cookies().get('auth'); + if(!koek){ + return new Response("unauthorized",{status:403}); + } + console.log(koek); + const auth = JSON.parse(koek.value); + + const authentication = await Auth.findOne( { include: 'user', where: {token:auth.token} }) + + + if(!authentication) + return new Response("unauthorized: invalid token",{status:403}); + + + const authUser = await authentication.getUser(); + + // @ts-ignore + cookies().set('auth', JSON.stringify(authentication)); + + return new Response( + JSON.stringify( + { + auth: authentication, + }), + { + status: 200, + headers:{ + "Content-Type": "text/JSON" + } + } + ); +} + +export async function POST(request:Request){ + try{ + return await tryAuth(request); + } + catch(e){ + if (e instanceof APIError){ + return new Response(e.info.responseText,{status:e.info.status}); + } + else{ + throw e; + } + } +} diff --git a/src/app/api/user/route.ts b/src/app/api/user/route.ts index f20a0e9..1e77698 100644 --- a/src/app/api/user/route.ts +++ b/src/app/api/user/route.ts @@ -1,6 +1,6 @@ 'use server' -import { User, Auth, Post } from "@/model/sequelize/NewModels" +import { User, Auth, Post, UserPerms } from "@/model/sequelize/NewModels" import { APIError } from "@/api/error"; import { UserAuth } from "@/api/user"; import { hashPassword } from "@/util/Auth"; @@ -24,7 +24,16 @@ async function tryRegister(request:Request){ const hash = await hashPassword(requestBody.password); const user = await User.create({ username: requestBody.username, - password: hash + password: hash, + perms:{ + isAdmin: false + } + + }, + { + include: [{ + association: 'perms' + }] }) return new Response( @@ -58,7 +67,19 @@ export async function POST(request:Request){ async function tryGetUsers(request:Request){ - const users = await User.findAll({include: "authtokens"}); + const defaultScope:any = User.scope('defaultScope'); + + const mergedInclude = defaultScope.include ? [defaultScope.include] : []; + mergedInclude.push({ association: 'authtokens' }); + + // const mergedInclude = [...defaultScope.include, { association: 'authtokens' }]; + + const users = await User.findAll( + { + attributes: defaultScope.attributes, + include: mergedInclude, + } + ); return new Response( diff --git a/src/app/article/[...slug]/page.tsx b/src/app/article/[...slug]/page.tsx index 26b64b7..af0b614 100644 --- a/src/app/article/[...slug]/page.tsx +++ b/src/app/article/[...slug]/page.tsx @@ -5,7 +5,7 @@ import Sidebar from "@/components/sidebar"; import Article from "@/components/news/article"; import ArticlePreview from "@/components/news/article-preview" import ReactDOM from "react"; -import "public/global.css" +import "/public/global.css" import "@/app/index.css" import { Post, User } from "@/model/sequelize/NewModels"; import { Attributes } from "sequelize"; @@ -17,7 +17,7 @@ type DeepPartial = T extends object ? { async function getData(slug:string):Promise> { // Get all posts from the API - const res = await fetch(`http://localhost:3000/api2/post/${slug}`); + const res = await fetch(`http://localhost:3000/api/post/${slug}`); // The return value is *not* serialized // You can return Date, Map, Set, etc. // Recommendation: handle errors @@ -39,12 +39,12 @@ export default async function Page({ params }: {params: {slug:string}}) {
- + {/*

Filters

  • filter 1
  • filter 2
  • filter 3
-
+
*/}
diff --git a/src/app/globals.css b/src/app/globals.css index fd81e88..8e62362 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -25,3 +25,130 @@ body { ) rgb(var(--background-start-rgb)); } + +@layer base { + :root { + --text-50: #f3eff5; + --text-100: #e7dfec; + --text-200: #cfbfd9; + --text-300: #b89fc6; + --text-400: #a080b3; + --text-500: #88609f; + --text-600: #6d4d80; + --text-700: #523960; + --text-800: #362640; + --text-900: #1b1320; + --text-950: #0e0a10; + + --background-50: #f4eef6; + --background-100: #e8ddee; + --background-200: #d2bbdd; + --background-300: #bb99cc; + --background-400: #a477bb; + --background-500: #8e55aa; + --background-600: #714488; + --background-700: #553366; + --background-800: #392244; + --background-900: #1c1122; + --background-950: #0e0911; + + --primary-50: #f3edf8; + --primary-100: #e6daf1; + --primary-200: #ceb5e3; + --primary-300: #b590d5; + --primary-400: #9c6bc7; + --primary-500: #8346b9; + --primary-600: #693894; + --primary-700: #4f2a6f; + --primary-800: #351c4a; + --primary-900: #1a0e25; + --primary-950: #0d0712; + + --secondary-50: #f3ebf9; + --secondary-100: #e7d7f4; + --secondary-200: #cfb0e8; + --secondary-300: #b788dd; + --secondary-400: #9f61d1; + --secondary-500: #8739c6; + --secondary-600: #6c2e9e; + --secondary-700: #512277; + --secondary-800: #36174f; + --secondary-900: #1b0b28; + --secondary-950: #0d0614; + + --accent-50: #f3eafb; + --accent-100: #e7d5f6; + --accent-200: #cfaaee; + --accent-300: #b880e5; + --accent-400: #a056dc; + --accent-500: #882bd4; + --accent-600: #6d23a9; + --accent-700: #521a7f; + --accent-800: #361155; + --accent-900: #1b092a; + --accent-950: #0e0415; + + } + .dark { + --text-50: #0e0910; + --text-100: #1b1320; + --text-200: #362541; + --text-300: #513861; + --text-400: #6c4a82; + --text-500: #885da2; + --text-600: #9f7db5; + --text-700: #b79ec7; + --text-800: #cfbeda; + --text-900: #e7dfec; + --text-950: #f3eff6; + + --background-50: #0d0911; + --background-100: #1b1122; + --background-200: #352244; + --background-300: #503366; + --background-400: #6a4488; + --background-500: #8555aa; + --background-600: #9d77bb; + --background-700: #b699cc; + --background-800: #cebbdd; + --background-900: #e7ddee; + --background-950: #f3eef6; + + --primary-50: #0d0712; + --primary-100: #1a0e25; + --primary-200: #351c4a; + --primary-300: #4f2a6f; + --primary-400: #693894; + --primary-500: #8346b9; + --primary-600: #9c6bc7; + --primary-700: #b590d5; + --primary-800: #ceb5e3; + --primary-900: #e6daf1; + --primary-950: #f3edf8; + + --secondary-50: #0d0614; + --secondary-100: #1b0b28; + --secondary-200: #36174f; + --secondary-300: #512277; + --secondary-400: #6c2e9e; + --secondary-500: #8739c6; + --secondary-600: #9f61d1; + --secondary-700: #b788dd; + --secondary-800: #cfb0e8; + --secondary-900: #e7d7f4; + --secondary-950: #f3ebf9; + + --accent-50: #0e0415; + --accent-100: #1b092a; + --accent-200: #361155; + --accent-300: #521a7f; + --accent-400: #6d23a9; + --accent-500: #882bd4; + --accent-600: #a056dc; + --accent-700: #b880e5; + --accent-800: #cfaaee; + --accent-900: #e7d5f6; + --accent-950: #f3eafb; + + } +} \ No newline at end of file diff --git a/src/app/layout.tsx b/src/app/layout.tsx index b7501b5..98a4a16 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,6 +1,7 @@ import './globals.css' import { Inter } from 'next/font/google' import StyledJsxRegistry from './registry'; +import Providers from '@/providers/providers'; const inter = Inter({ subsets: ['latin'], fallback: ['system-ui', 'arial'] }) @@ -16,7 +17,7 @@ export default function RootLayout({ }) { return ( - {children} + {children} ) } diff --git a/src/app/lib/actions.ts b/src/app/lib/actions.ts new file mode 100644 index 0000000..86faf5c --- /dev/null +++ b/src/app/lib/actions.ts @@ -0,0 +1,79 @@ +'use server' + +import { constructAPIUrl } from "@/util/Utils" +// import { signIn } from '@/auth' +import { cookies } from "next/headers" +import { parseSetCookie } from "@/util/parseSetCookie"; +import makeFetchCookie from 'fetch-cookie'; + +type LoginReturn = { + cookie?:unknown, + errorMessage?:string; +} + +async function signIn(method:string,b:FormData):Promise +{ + console.log("form data:"); + console.log(b); + + if(!b || !b.get('input_username') || !b.get('input_password')) return null; + let headers:Headers = new Headers(); + const fetchCookie = makeFetchCookie(fetch) + headers.set('Authorization', 'Basic ' + Buffer.from(b.get('input_username') + ":" + b.get('input_password')).toString('base64')); + let res = await fetchCookie(constructAPIUrl("auth"), { + method:'POST', + credentials: 'include', + headers:headers, + }); + + // if(res.headers.get('set-coo')) console.log(res.headers['set-cookie']) + let koek = res.headers.getSetCookie(); + // console.log("api koek:" + koek.map((k)=>decodeURIComponent(k))); + let cookieDict = parseSetCookie(koek); + console.log("testing cookiedict") + console.log(cookieDict); + await cookies().set('auth', cookieDict.auth); + return { + cookie:cookieDict.auth, + errorMessage:"" + }; + // console.log(koek); +} + +export async function authenticate(_currentState: unknown, formData: FormData):Promise +{ + console.log("action triggered") + try { + const signInStatus = await signIn('credentials', formData) + return signInStatus; + } catch (error:any) { + if (error) { + switch (error.type) { + case 'CredentialsSignin': + return { + errorMessage: 'invalidCredentials' + } + default: + return { + errorMessage: 'Something went wrong.' + } + } + } + throw error + } +} +export async function koekValid(koek:string):Promise +{ + + + const validateSession = await fetch(constructAPIUrl("auth/validate"),{ + method:"POST", + headers:{ + Cookie: `auth=${koek};` + } + }); + if(validateSession.status == 200) + return true + else + return false +} \ No newline at end of file diff --git a/src/app/page.tsx b/src/app/page.tsx index ad48756..e549138 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -4,10 +4,11 @@ import Navbar from "@/components/navbar"; import Sidebar from "@/components/sidebar"; import ArticlePreview from "@/components/news/article-preview" import ReactDOM from "react"; -import "public/global.css" +import "/public/global.css" import "./index.css" import { Post, PostAttributes } from "@/model/sequelize/NewModels"; import { constructAPIUrl } from "@/util/Utils"; +import Link from "next/link"; type DeepPartial = T extends object ? { [P in keyof T]?: DeepPartial; @@ -23,12 +24,12 @@ export default async function Test() {
- + {/*

Filters

  • filter 1
  • filter 2
  • filter 3
-
+
*/}
{articles.map((article, i) => { console.log("Entered"); diff --git a/src/components/admin/adminPanel.tsx b/src/components/admin/adminPanel.tsx new file mode 100644 index 0000000..1eb3959 --- /dev/null +++ b/src/components/admin/adminPanel.tsx @@ -0,0 +1,32 @@ +'use client' +import { ReactNode, useContext } from "react"; +import { AuthContext, AuthProps } from "@/providers/providers"; +import SomeServerSubComponent from "./serverContextUserTest"; + +interface Props { + children?: ReactNode; + auth?: AuthProps; +} + +export default function AdminPanel(props:Props){ + + return ( +
+

Super Secret Admin Panel!

+

this is where we use the context test:

+ +
+ {props.children} +
+
+ ) +} + +function SomeSubComponent(props:Props){ + let { test, auth } = useContext(AuthContext); + return ( + {test}{JSON.stringify(auth)} + ); +} + + diff --git a/src/components/admin/authHandler.tsx b/src/components/admin/authHandler.tsx new file mode 100644 index 0000000..97605f6 --- /dev/null +++ b/src/components/admin/authHandler.tsx @@ -0,0 +1,47 @@ +'use server' +import { cookies } from "next/headers"; +// import { useState } from "react"; +import LoginForm from "./loginForm"; +import { koekValid } from "@/app/lib/actions"; +import { constructAPIUrl } from "@/util/Utils"; +import AdminPanel from "./adminPanel"; +import { ReactNode } from "react"; +import { AuthContext, AuthProps } from "@/providers/providers"; +import ClientAuthHandler from "./clientAuthHandler"; + + +interface Props { + children?: ReactNode; + params?: any; + requiredRole?: number; +} // We interfacing lads + + + +export default async function AuthHandler(props: Props) { + const protoKoek = await cookies().get('auth')?.value; + const koek = decodeURIComponent(protoKoek?protoKoek:""); + console.log("koekje:" + koek) + let p:AuthProps = { + test:"not pog" + }; + if(koek){ + const kd = JSON.parse(koek); + if(kd.id && kd.token && kd.user_id){ + p = { + test:"success!", + auth: { + id:kd.id, + token:kd.token, + user_id:kd.user_id + } + } + } + } + + return ( +
+ {!(koek && await koekValid(koek)) ? { } :
{props.children}
signed in! :D
} +
+ ); +} diff --git a/src/components/admin/clientAuthHandler.tsx b/src/components/admin/clientAuthHandler.tsx new file mode 100644 index 0000000..1dff506 --- /dev/null +++ b/src/components/admin/clientAuthHandler.tsx @@ -0,0 +1,16 @@ +'use client' +import { AuthContext, AuthProps } from "@/providers/providers"; +import { ReactNode, createContext } from "react" + +type Props = { + children?:ReactNode; + authProps:AuthProps +} + + +export default function ClientAuthHandler(props:Props){ + + return ( + {props.children} + ) +} \ No newline at end of file diff --git a/src/components/admin/loginForm.tsx b/src/components/admin/loginForm.tsx new file mode 100644 index 0000000..00103fc --- /dev/null +++ b/src/components/admin/loginForm.tsx @@ -0,0 +1,46 @@ +'use client' + +import { authenticate } from "@/app/lib/actions"; +import { AuthContext } from "@/providers/providers"; +import { constructAPIUrl } from "@/util/Utils"; +import { cookies } from "next/headers"; +import { createContext, useState } from "react"; +import { useFormState, useFormStatus } from "react-dom"; + + +// async function authenticate(){ +// const url = await constructAPIUrl("auth"); +// const auth = await fetch(url); +// } + + +export default function LoginForm(){ + const [loginResult, dispatch] = useFormState(authenticate, undefined); + + // if(loginResult?.cookie && loginResult.cookie && loginResult.cookie['auth']){ + // cookies().set('auth', loginResult.cookie['auth']) + // } + + return ( +
+ + + + + +
{loginResult?.errorMessage &&

{loginResult?.errorMessage}

}
+
+

{""+loginResult?.cookie}

+
+
); +} + +function LoginButton() { + const { pending } = useFormStatus() + + return ( + + ) + } \ No newline at end of file diff --git a/src/components/admin/serverContextUserTest.tsx b/src/components/admin/serverContextUserTest.tsx new file mode 100644 index 0000000..4dd9b05 --- /dev/null +++ b/src/components/admin/serverContextUserTest.tsx @@ -0,0 +1,14 @@ +import { AuthContext, AuthProps } from "@/providers/providers"; +import { ReactNode, useContext } from "react"; + +interface Props { + children?: ReactNode; + auth?: AuthProps; +} + +export default function SomeServerSubComponent(props:Props){ + let { test, auth } = useContext(AuthContext); + return ( + {test}{JSON.stringify(auth)} + ); +} \ No newline at end of file diff --git a/src/components/auth/authComponents.tsx b/src/components/auth/authComponents.tsx new file mode 100644 index 0000000..9996a59 --- /dev/null +++ b/src/components/auth/authComponents.tsx @@ -0,0 +1,16 @@ +import { AuthContext } from "@/providers/providers"; +import { ReactNode, useContext } from "react" + +type Props = { + children:ReactNode; +} + + + +export default function AdminOnlyComponent(p:Props){ + const context = useContext(AuthContext) + return + (
+ +
); +} \ No newline at end of file diff --git a/src/components/news/article-preview.module.css b/src/components/news/article-preview.module.css index a7206a3..794cd05 100644 --- a/src/components/news/article-preview.module.css +++ b/src/components/news/article-preview.module.css @@ -3,6 +3,8 @@ flex-direction: row; box-sizing: content-box; min-height:128px; + padding-top: 0; + background-color: #1a4457; /* background-color: aqua; */ /* max-width:25vw; */ /* outline: auto; */ @@ -20,4 +22,5 @@ .summary{ /* flex-shrink: 1; */ padding:8px; + padding-top:0px; } \ No newline at end of file diff --git a/src/components/news/article-preview.tsx b/src/components/news/article-preview.tsx index f234ce0..3de3b6d 100644 --- a/src/components/news/article-preview.tsx +++ b/src/components/news/article-preview.tsx @@ -4,16 +4,35 @@ import styles from "./article-preview.module.css" import bg from "public/placeholder-square.png" import { ReactNode } from "react" import { Style } from "util"; +import Link from "next/link"; +import { redirect } from 'next/navigation'; +import { Router } from "next/router"; +import { useRouter } from 'next/navigation' +import { truncateString } from "@/util/Utils"; -export default function ArticlePreview(params: { id: string|undefined, title: string|undefined, content: string|undefined, date?:string|undefined } ){ - return
-
+type Props = { + id?:string + title?:string + content?:string + date?:string +} + + + +export default function ArticlePreview(props:Props){ + // if (!props.content) + return ( +
+
-
-
-

{params.title}

-

{params.content}

-
-
; +
+
+

{props.title}

+

{truncateString(props.content,255)}

+
+ +
+ + ); } \ No newline at end of file diff --git a/src/components/news/article.module.css b/src/components/news/article.module.css index cdec6f1..b32d256 100644 --- a/src/components/news/article.module.css +++ b/src/components/news/article.module.css @@ -9,7 +9,7 @@ } .imagecontainer{ - min-width:100%; + min-width:fit-content; min-height:256px; /* flex-grow: 10; */ background-image: url(/placeholder-square.png); diff --git a/src/components/news/article.tsx b/src/components/news/article.tsx index a92fd47..6dca98c 100644 --- a/src/components/news/article.tsx +++ b/src/components/news/article.tsx @@ -1,5 +1,5 @@ import Tagbar from "@/components/news/tagbar"; -import "public/global.css" +import "/public/global.css" import "@/app/index.css" import styles from "./article.module.css" @@ -7,13 +7,11 @@ import styles from "./article.module.css" export default function Article(params: { id: string|undefined, title: string|undefined, content: string|undefined, date?:string|undefined } ) { return (
-

{params.title}

- -
- -

{params.content}

-
{params.date}
-
+

{params.title}

+
+
+

{params.content}

+
{params.date}

); } \ No newline at end of file diff --git a/src/components/news/tagbar.module.css b/src/components/news/tagbar.module.css index 8fe422a..d50dac2 100644 --- a/src/components/news/tagbar.module.css +++ b/src/components/news/tagbar.module.css @@ -10,5 +10,5 @@ *display: inline; } .tagbar{ - margin: 0px 0px 4px 0px; + margin: 0px 0px 0px 0px; } \ No newline at end of file diff --git a/src/components/news/tagbar.tsx b/src/components/news/tagbar.tsx index 42154bd..26995e2 100644 --- a/src/components/news/tagbar.tsx +++ b/src/components/news/tagbar.tsx @@ -1,7 +1,7 @@ import styles from "./tagbar.module.css" const tagItems = ["tag1", "tag2", "tag3"]; -const tagList = tagItems.map(value =>
  • {value}
  • ); +const tagList = tagItems.map(value =>
  • {value}
  • ); export default function Tagbar() { diff --git a/src/controller/Post.ts b/src/controller/Post.ts deleted file mode 100644 index 8742850..0000000 --- a/src/controller/Post.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Connection, RowDataPacket, OkPacket, QueryError } from "mysql2"; -import { getConnection } from "@/db"; - - -export interface IPost extends RowDataPacket { - id: number; - post: string; -} - -export async function getPost(id:Number): Promise { - // let [rows]:Array = await conn.execute("SELECT * FROM `post`", []); - return new Promise((resolve, reject) => { - let res = getConnection().then((conn)=>{conn.query(`SELECT * FROM post WHERE id = ${id}`, (err:QueryError, res) => { - if (err) reject(err) - else resolve(res) - }); - }); - return res; - }); -} - -export async function getPosts(): Promise { - // let [rows]:Array = await conn.execute("SELECT * FROM `post`", []); - return new Promise((resolve, reject) => { - let res = getConnection().then((conn)=>{conn.query("SELECT * FROM post", (err:QueryError, res) => { - if (err) reject(err) - else resolve(res) - }); - }); - return res; - }); -} - -// export default { getPost, getPosts } \ No newline at end of file diff --git a/src/model/sequelize/NewModels.ts b/src/model/sequelize/NewModels.ts index e96d902..9e814d7 100644 --- a/src/model/sequelize/NewModels.ts +++ b/src/model/sequelize/NewModels.ts @@ -4,7 +4,9 @@ import { HasManySetAssociationsMixin, HasManyAddAssociationsMixin, HasManyHasAssociationsMixin, HasManyRemoveAssociationMixin, HasManyRemoveAssociationsMixin, Model, ModelDefined, Optional, Sequelize, InferAttributes, InferCreationAttributes, CreationOptional, NonAttribute, ForeignKey, BelongsTo, BelongsToGetAssociationMixin, UUIDV4, UUID, - VirtualDataType + VirtualDataType, + HasOneGetAssociationMixin, + HasOneCreateAssociationMixin } from 'sequelize'; @@ -13,11 +15,35 @@ const sequelize = new Sequelize({ storage: 'db.sqlite' }); +export class UserPerms extends Model, InferCreationAttributes> { + declare id: CreationOptional; + declare user:NonAttribute; + declare user_id:ForeignKey; + declare isAdmin:CreationOptional; +} +UserPerms.init({ + id: { + allowNull: false, + autoIncrement: true, + type: DataTypes.INTEGER, + primaryKey: true, + unique: true, + }, + isAdmin: { + allowNull: false, + defaultValue: false, + type: DataTypes.BOOLEAN + } +}, +{ + tableName: 'Perms', + sequelize // passing the `sequelize` instance is required +}); + export class Auth extends Model, InferCreationAttributes> { declare id: CreationOptional; declare token: CreationOptional; - declare user:NonAttribute; declare user_id:ForeignKey; declare getUser: BelongsToGetAssociationMixin; declare static associations: { @@ -96,6 +122,13 @@ export class User extends Model, InferCreationAttributes; declare getPosts:HasManyGetAssociationsMixin; + declare getPerms:HasOneGetAssociationMixin; + declare createPerms:HasOneCreateAssociationMixin; + declare perms?:NonAttribute + declare static associations: { + perms: Association; + }; + } User.init( @@ -114,20 +147,19 @@ User.init( password: { allowNull: false, type: DataTypes.STRING, - } - + }, }, { defaultScope: { - attributes:{ - exclude:['password'] - } + attributes: { + exclude: ['password'], + }, + include: [{ association: 'perms' }], }, tableName: 'Users', sequelize // passing the `sequelize` instance is required } ); -User.scope Auth.belongsTo(User, { foreignKey:'user_id', @@ -149,7 +181,19 @@ User.hasMany(Post, { foreignKey: 'user_id', as: 'posts' // this determines the name in `associations`! }); +UserPerms.belongsTo(User, { + foreignKey:'user_id', + targetKey:'id', + as: 'user' +}) +User.hasOne(UserPerms, { + sourceKey: 'id', + foreignKey: 'user_id', + as: 'perms' +}) + User.sync(); Auth.sync(); -Post.sync(); \ No newline at end of file +Post.sync(); +UserPerms.sync(); \ No newline at end of file diff --git a/src/providers/providers.tsx b/src/providers/providers.tsx new file mode 100644 index 0000000..0c32eb7 --- /dev/null +++ b/src/providers/providers.tsx @@ -0,0 +1,28 @@ +'use client' + +import { Auth, User } from "@/model/sequelize/NewModels"; +import { ReactNode, createContext } from "react"; +import { InferAttributes } from "sequelize/types/model"; + + +export type AuthProps = { + test: string; + auth?: InferAttributes + user?: InferAttributes +} +let p: AuthProps = { + test: "lorem", +} + +export const AuthContext = createContext(p); + +interface Props { + children?: ReactNode; + params?: any; +} + +export default function Providers(props:Props){ + return ( + {props.children} + ) +} \ No newline at end of file diff --git a/src/util/Utils.ts b/src/util/Utils.ts index 006dd99..c3b1faf 100644 --- a/src/util/Utils.ts +++ b/src/util/Utils.ts @@ -14,6 +14,17 @@ function constructAPIUrl(endpoint:string){ const { schema, host, port, basepath } = getAPIEnv(); return `${schema}://${host}:${port}/${basepath}/${endpoint}` } +function constructUrl(endpoint:string){ + const { schema, host, port, basepath } = getAPIEnv(); + return `${schema}://${host}:${port}/${endpoint}` +} +function truncateString(str:string = '', num:number = 255) { + if (str.length > num) { + return str.slice(0, num) + "..."; + } else { + return str; + } +} -export { Gens, Auth, constructAPIUrl } \ No newline at end of file +export { Gens, Auth, constructAPIUrl, constructUrl, truncateString } \ No newline at end of file diff --git a/src/util/parseSetCookie.ts b/src/util/parseSetCookie.ts new file mode 100644 index 0000000..36fdab6 --- /dev/null +++ b/src/util/parseSetCookie.ts @@ -0,0 +1,9 @@ +export function parseSetCookie(h: string[]) { + let aaa = h.map( + s => [...s.matchAll(/(.*?)=(.*?)($|;|,(?! ))/gm)] + ); + const dict = Object.assign({}, ...aaa[0].map((e) => { + return { [e[1]]: decodeURIComponent(e[2]) }; + })); + return dict; +} diff --git a/tailwind.config.js b/tailwind.config.js index d53b2ea..c55da51 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -12,7 +12,76 @@ module.exports = { 'gradient-conic': 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', }, + colors: { + 'text': { + 50: 'var(--text-50)', + 100: 'var(--text-100)', + 200: 'var(--text-200)', + 300: 'var(--text-300)', + 400: 'var(--text-400)', + 500: 'var(--text-500)', + 600: 'var(--text-600)', + 700: 'var(--text-700)', + 800: 'var(--text-800)', + 900: 'var(--text-900)', + 950: 'var(--text-950)', + }, + 'background': { + 50: 'var(--background-50)', + 100: 'var(--background-100)', + 200: 'var(--background-200)', + 300: 'var(--background-300)', + 400: 'var(--background-400)', + 500: 'var(--background-500)', + 600: 'var(--background-600)', + 700: 'var(--background-700)', + 800: 'var(--background-800)', + 900: 'var(--background-900)', + 950: 'var(--background-950)', + }, + 'primary': { + 50: 'var(--primary-50)', + 100: 'var(--primary-100)', + 200: 'var(--primary-200)', + 300: 'var(--primary-300)', + 400: 'var(--primary-400)', + 500: 'var(--primary-500)', + 600: 'var(--primary-600)', + 700: 'var(--primary-700)', + 800: 'var(--primary-800)', + 900: 'var(--primary-900)', + 950: 'var(--primary-950)', + }, + 'secondary': { + 50: 'var(--secondary-50)', + 100: 'var(--secondary-100)', + 200: 'var(--secondary-200)', + 300: 'var(--secondary-300)', + 400: 'var(--secondary-400)', + 500: 'var(--secondary-500)', + 600: 'var(--secondary-600)', + 700: 'var(--secondary-700)', + 800: 'var(--secondary-800)', + 900: 'var(--secondary-900)', + 950: 'var(--secondary-950)', + }, + 'accent': { + 50: 'var(--accent-50)', + 100: 'var(--accent-100)', + 200: 'var(--accent-200)', + 300: 'var(--accent-300)', + 400: 'var(--accent-400)', + 500: 'var(--accent-500)', + 600: 'var(--accent-600)', + 700: 'var(--accent-700)', + 800: 'var(--accent-800)', + 900: 'var(--accent-900)', + 950: 'var(--accent-950)', + }, + }, }, }, - plugins: [], + plugins: [ + require('flowbite/plugin') + ] }