From c9e7717130ea10fd709246eeddb04da550a1e485 Mon Sep 17 00:00:00 2001 From: Andreas Schaafsma Date: Sat, 6 Jul 2024 23:23:01 +0200 Subject: [PATCH] yes --- .vscode/settings.json | 37 ++- insomnia.json | 1 - src/app/admin/layout.tsx | 37 ++- src/app/api-doc/page.tsx | 11 + src/app/api/attachment/route.ts | 13 +- src/app/api/auth/route.ts | 17 +- src/app/api/setupDB/route.ts | 302 ++++++++++-------- src/app/api/user/route.ts | 2 +- src/app/article/[...slug]/page.tsx | 2 +- src/app/layout.tsx | 4 +- src/app/lib/actions/actions.ts | 26 +- src/app/page.tsx | 4 +- src/components/client/SwaggerComponent.tsx | 14 + src/components/client/admin/CAuthHandler.tsx | 15 + .../admin/{loginForm.tsx => CLoginForm.tsx} | 11 +- src/components/client/admin/PostEditor.tsx | 3 - src/components/client/admin/PostTable.tsx | 13 +- .../client/admin/clientAuthHandler.tsx | 16 - .../client/input/EntityEditorTextArea.tsx | 1 - src/components/server/admin/authHandler.tsx | 65 ++-- src/components/shared/bootstrap.tsx | 10 - src/components/shared/news/tagbar.module.css | 2 +- src/lib/swagger.ts | 1 + src/models/DBState.ts | 3 +- src/models/Project.ts | 2 +- src/models/index.ts | 2 +- src/providers/authprovider.tsx | 14 + .../{providers.tsx => contextproviders.tsx} | 17 +- src/providers/index.ts | 2 + src/util/aifa.ts | 3 - src/util/api/getAPIEnv.ts | 5 +- src/util/api/index.ts | 1 + src/util/api/runapiaction.ts | 19 ++ src/util/{DeepPartial.ts => deeppartial.ts} | 0 src/util/index.ts | 3 +- src/util/url/urlConstructor.ts | 8 +- src/views/admin/post/CPostView.tsx | 18 +- src/views/admin/post/PostView.tsx | 15 +- src/views/admin/project/ProjectView.tsx | 2 +- 39 files changed, 395 insertions(+), 326 deletions(-) delete mode 100644 insomnia.json create mode 100644 src/app/api-doc/page.tsx create mode 100644 src/components/client/SwaggerComponent.tsx create mode 100644 src/components/client/admin/CAuthHandler.tsx rename src/components/client/admin/{loginForm.tsx => CLoginForm.tsx} (82%) delete mode 100644 src/components/client/admin/clientAuthHandler.tsx delete mode 100644 src/components/shared/bootstrap.tsx create mode 100644 src/providers/authprovider.tsx rename src/providers/{providers.tsx => contextproviders.tsx} (58%) create mode 100644 src/providers/index.ts delete mode 100644 src/util/aifa.ts create mode 100644 src/util/api/runapiaction.ts rename src/util/{DeepPartial.ts => deeppartial.ts} (100%) diff --git a/.vscode/settings.json b/.vscode/settings.json index d25648a..5ea5cca 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,25 +2,24 @@ "window.title": "${dirty}${activeEditorMedium}${separator}${rootName}${separator}${profileName}${separator}${appName}", "workbench.editor.labelFormat": "medium", "files.exclude": { - "**/.git": true, - "**/.svn": true, - "**/.hg": true, - "**/CVS": true, - "**/.DS_Store": true, - "**/Thumbs.db": true, - "**/.next": true, - "**/.sqlite_queries": true, - "**/node_modules": true, - "**/.env.example": true, - "**/.vscode": true, - "**/.env**": true, - "**/.gitignore": true, - "**/.eslintrc.json": true, - "**/next-env.d.ts": true, - "**/package-lock.json": true, - "**/package.json": true, - "**/bucket": true, - + "**/.git": false, + "**/.svn": false, + "**/.hg": false, + "**/CVS": false, + "**/.DS_Store": false, + "**/Thumbs.db": false, + "**/.next": false, + "**/.sqlite_queries": false, + "**/node_modules": false, + "**/.env.example": false, + "**/.vscode": false, + "**/.env**": false, + "**/.gitignore": false, + "**/.eslintrc.json": false, + "**/next-env.d.ts": false, + "**/package-lock.json": false, + "**/package.json": false, + "**/bucket": false }, "exportall.config.folderListener": [ "/src/util/api", diff --git a/insomnia.json b/insomnia.json deleted file mode 100644 index 83599b9..0000000 --- a/insomnia.json +++ /dev/null @@ -1 +0,0 @@ -{"_type":"export","__export_format":4,"__export_date":"2023-06-12T09:30:08.182Z","__export_source":"insomnia.desktop.app:v2023.2.2","resources":[{"_id":"req_e1f51a43553b49f1ab0dd8144f8838ab","parentId":"fld_b93603394ce3455cb1a0c169de187d03","modified":1686540762016,"created":1686464136593,"url":"{{ _.scheme }}://{{ _.host }}:{{ _.port }}/{{ _.base_path }}/{{ _.route }}","name":"New Request","description":"","method":"GET","body":{},"parameters":[{"id":"pair_7898d6e719ac4a1b91f0f052181a53a7","name":"username","value":"andreas3","description":""},{"id":"pair_b42362652f6c45e4b2023477a4a0fa28","name":"password","value":"changeme","description":""}],"headers":[{"id":"pair_fda94cda80a84d18af14dd872a7b16b8","name":"","value":"","description":""}],"authentication":{"type":"basic","useISO88591":false,"disabled":false,"username":"andreas2","password":"changeme"},"metaSortKey":-1686464136593,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global","_type":"request"},{"_id":"fld_b93603394ce3455cb1a0c169de187d03","parentId":"wrk_a189b5072b8c4203924446cbf96ec47d","modified":1686464158382,"created":1686464133576,"name":"auth","description":"","environment":{"route":"auth"},"environmentPropertyOrder":{"&":["route"]},"metaSortKey":-1686464133576,"_type":"request_group"},{"_id":"wrk_a189b5072b8c4203924446cbf96ec47d","parentId":null,"modified":1686453338349,"created":1686453338349,"name":"Portfolio","description":"","scope":"design","_type":"workspace"},{"_id":"req_2f70b86802a549cbbf24dff4fb318c73","parentId":"fld_a3c04530d80a4ec091b42f431e450237","modified":1686536923156,"created":1686535644896,"url":"{{ _.scheme }}://{{ _.host }}:{{ _.port }}/{{ _.base_path }}/{{ _.route }}","name":"New Request","description":"","method":"POST","body":{"mimeType":"application/json","text":"{\n\t\"username\": \"andreas3\",\n\t\"password\": \"changeme\"\n}"},"parameters":[],"headers":[{"id":"pair_fda94cda80a84d18af14dd872a7b16b8","name":"","value":"","description":""},{"name":"Content-Type","value":"application/json"}],"authentication":{},"metaSortKey":-1686464136593,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global","_type":"request"},{"_id":"fld_a3c04530d80a4ec091b42f431e450237","parentId":"wrk_a189b5072b8c4203924446cbf96ec47d","modified":1686535655573,"created":1686535644894,"name":"User","description":"","environment":{"route":"user"},"environmentPropertyOrder":{"&":["route"]},"metaSortKey":-1686383815714.5,"_type":"request_group"},{"_id":"req_4135b76ecd6e4b38ae875015a1f38c1a","parentId":"fld_b079892e41ea4b9dbf7d00e85df36b4e","modified":1686304187685,"created":1686303504644,"url":"{{ _.scheme }}://{{ _.host }}:{{ _.port }}/{{ _.base_path }}/{{ _.route }}","name":"Get All Posts","description":"","method":"GET","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1686303497803,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global","_type":"request"},{"_id":"fld_b079892e41ea4b9dbf7d00e85df36b4e","parentId":"wrk_a189b5072b8c4203924446cbf96ec47d","modified":1686304180712,"created":1686303497852,"name":"Post","description":"","environment":{"route":"post"},"environmentPropertyOrder":{"&":["route"]},"metaSortKey":-1686303497853,"_type":"request_group"},{"_id":"req_b70167944901490b94817df299f21de6","parentId":"fld_b079892e41ea4b9dbf7d00e85df36b4e","modified":1686453700500,"created":1686453675016,"url":"{{ _.scheme }}://{{ _.host }}:{{ _.port }}/{{ _.base_path }}/{{ _.route }}/1","name":"Get Specific Post","description":"","method":"GET","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1686303497753,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global","_type":"request"},{"_id":"req_6622010a2bca41beb03b8ba126a6c4b6","parentId":"fld_c82ab5d372fb414e9cf326a69225c7e4","modified":1686458449960,"created":1686455585158,"url":"{{ _.scheme }}://{{ _.host }}:{{ _.port }}/{{ _.base_path }}/{{ _.route }}","name":"Get All Posts","description":"","method":"GET","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1686303497803,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global","_type":"request"},{"_id":"fld_c82ab5d372fb414e9cf326a69225c7e4","parentId":"wrk_a189b5072b8c4203924446cbf96ec47d","modified":1686455601799,"created":1686455585147,"name":"Brown","description":"","environment":{"route":"brown"},"environmentPropertyOrder":{"&":["route"]},"metaSortKey":-1686303497803,"_type":"request_group"},{"_id":"req_eddd37fc4002491892d8acca3dc5d85e","parentId":"fld_c82ab5d372fb414e9cf326a69225c7e4","modified":1686459281655,"created":1686455607594,"url":"{{ _.scheme }}://{{ _.host }}:{{ _.port }}/{{ _.base_path }}/{{ _.route }}","name":"New Request","description":"","method":"POST","body":{"mimeType":"application/json","text":"{\n\t\"title\": \"peepee\",\n\t\"content\": \"poopoo\"\n}"},"parameters":[],"headers":[{"name":"Content-Type","value":"application/json"}],"authentication":{},"metaSortKey":-1686303497778,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global","_type":"request"},{"_id":"req_1703723ed00c40798a9f8fcd154cffd4","parentId":"fld_c82ab5d372fb414e9cf326a69225c7e4","modified":1686455585160,"created":1686455585160,"url":"{{ _.scheme }}://{{ _.host }}:{{ _.port }}/{{ _.base_path }}/{{ _.route }}/1","name":"Get Specific Post","description":"","method":"GET","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1686303497753,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global","_type":"request"},{"_id":"env_70d3512c1c8840df95de5b7dac78ac9f","parentId":"wrk_a189b5072b8c4203924446cbf96ec47d","modified":1686304013422,"created":1686303473288,"name":"Base Environment","data":{"scheme":"http","host":"localhost","port":3000,"base_path":"api"},"dataPropertyOrder":{"&":["scheme","host","port","base_path"]},"color":null,"isPrivate":false,"metaSortKey":1686303473288,"_type":"environment"},{"_id":"jar_7842a9b1b5aa4d75900c945b6008f4f7","parentId":"wrk_a189b5072b8c4203924446cbf96ec47d","modified":1686303473290,"created":1686303473290,"name":"Default Jar","cookies":[],"_type":"cookie_jar"},{"_id":"spc_a025b787e6754e45a91e8ab3ec1feb42","parentId":"wrk_a189b5072b8c4203924446cbf96ec47d","modified":1686453625860,"created":1686453378493,"fileName":"Portfolio","contents":"openapi: 3.0.0\ninfo:\n description: \"Ask your mom. \\r\\n\\r\\n\n Portfolio [https://aschaafsma.nl](aschaafsma.nl) or on [irc.freenode.net,\n #swagger](https://aschaafsma.nl/irc/). For this sample, you can use the api key\n `special-key` to test the authorization filters.\"\n version: 1.0.2\n title: Portfolio\n termsOfService: http://aschaafsa.nl\n contact:\n email: apiteam@aschaafsma.nl\n license:\n name: GPL 3.0\n url: https://lickmy.nuts\ntags:\n - name: post\n description: A post on the blog\n externalDocs:\n description: Find out more\n url: http://askyour.mom\n - name: tag\n description: Access to Petstore orders\n - name: user\n description: Operations about user\n externalDocs:\n description: Find out more about our store\n url: http://your.mom\npaths:\n /pet:\n post:\n tags:\n - pet\n summary: Add a new pet to the store\n description: \"\"\n operationId: addPet\n requestBody:\n $ref: \"#/components/requestBodies/Pet\"\n responses:\n \"405\":\n description: \"Invalid input\"\n put:\n tags:\n - pet\n summary: Update an existing pet\n description: \"\"\n operationId: updatePet\n requestBody:\n $ref: \"#/components/requestBodies/Pet\"\n responses:\n \"400\":\n description: Invalid ID supplied\n \"404\":\n description: Pet not found\n \"405\":\n description: Validation exception\n /pet/findByStatus:\n get:\n tags:\n - pet\n summary: Finds Pets by status\n description: Multiple status values can be provided with comma separated strings\n operationId: findPetsByStatus\n parameters:\n - name: status\n in: query\n description: Status values that need to be considered for filter\n required: true\n explode: true\n schema:\n type: array\n items:\n type: string\n enum:\n - available\n - pending\n - sold\n default: available\n responses:\n \"200\":\n description: successful operation\n content:\n application/xml:\n schema:\n type: array\n items:\n $ref: \"#/components/schemas/Pet\"\n application/json:\n schema:\n type: array\n items:\n $ref: \"#/components/schemas/Pet\"\n \"400\":\n description: Invalid status value\n /pet/findByTags:\n get:\n tags:\n - pet\n summary: Finds Pets by tags\n description: Multiple tags can be provided with comma separated strings. Use tag1,\n tag2, tag3 for testing.\n operationId: findPetsByTags\n parameters:\n - name: tags\n in: query\n description: Tags to filter by\n required: true\n explode: true\n schema:\n type: array\n items:\n type: string\n responses:\n \"200\":\n description: successful operation\n content:\n application/xml:\n schema:\n type: array\n items:\n $ref: \"#/components/schemas/Pet\"\n application/json:\n schema:\n type: array\n items:\n $ref: \"#/components/schemas/Pet\"\n \"400\":\n description: Invalid tag value\n deprecated: true\n \"/pet/{petId}\":\n get:\n tags:\n - pet\n summary: Find pet by ID\n description: Returns a single pet\n operationId: getPetById\n parameters:\n - name: petId\n in: path\n description: ID of pet to return\n required: true\n schema:\n type: integer\n format: int64\n responses:\n \"200\":\n description: successful operation\n content:\n application/xml:\n schema:\n $ref: \"#/components/schemas/Pet\"\n application/json:\n schema:\n $ref: \"#/components/schemas/Pet\"\n \"400\":\n description: Invalid ID supplied\n \"404\":\n description: Pet not found\n post:\n tags:\n - pet\n summary: Updates a pet in the store with form data\n description: \"\"\n operationId: updatePetWithForm\n parameters:\n - name: petId\n in: path\n description: ID of pet that needs to be updated\n required: true\n schema:\n type: integer\n format: int64\n requestBody:\n content:\n application/x-www-form-urlencoded:\n schema:\n type: object\n properties:\n name:\n description: Updated name of the pet\n type: string\n status:\n description: Updated status of the pet\n type: string\n responses:\n \"405\":\n description: Invalid input\n delete:\n tags:\n - pet\n summary: Deletes a pet\n description: \"\"\n operationId: deletePet\n parameters:\n - name: api_key\n in: header\n required: false\n schema:\n type: string\n - name: petId\n in: path\n description: Pet id to delete\n required: true\n schema:\n type: integer\n format: int64\n responses:\n \"400\":\n description: Invalid ID supplied\n \"404\":\n description: Pet not found\n /store/inventory:\n get:\n tags:\n - store\n summary: Returns pet inventories by status\n description: Returns a map of status codes to quantities\n operationId: getInventory\n responses:\n \"200\":\n description: successful operation\n content:\n application/json:\n schema:\n type: object\n additionalProperties:\n type: integer\n format: int32\n /store/order:\n post:\n tags:\n - store\n summary: Place an order for a pet\n description: \"\"\n operationId: placeOrder\n requestBody:\n content:\n application/json:\n schema:\n $ref: \"#/components/schemas/Order\"\n description: order placed for purchasing the pet\n required: true\n responses:\n \"200\":\n description: successful operation\n content:\n application/xml:\n schema:\n $ref: \"#/components/schemas/Order\"\n application/json:\n schema:\n $ref: \"#/components/schemas/Order\"\n \"400\":\n description: Invalid Order\n \"/store/order/{orderId}\":\n get:\n tags:\n - store\n summary: Find purchase order by ID\n description: For valid response try integer IDs with value >= 1 and <= 10. Other\n values will generated exceptions\n operationId: getOrderById\n parameters:\n - name: orderId\n in: path\n description: ID of pet that needs to be fetched\n required: true\n schema:\n type: integer\n format: int64\n minimum: 1\n maximum: 10\n responses:\n \"200\":\n description: successful operation\n content:\n application/xml:\n schema:\n $ref: \"#/components/schemas/Order\"\n application/json:\n schema:\n $ref: \"#/components/schemas/Order\"\n \"400\":\n description: Invalid ID supplied\n \"404\":\n description: Order not found\n delete:\n tags:\n - store\n summary: Delete purchase order by ID\n description: For valid response try integer IDs with positive integer value. Negative\n or non-integer values will generate API errors\n operationId: deleteOrder\n parameters:\n - name: orderId\n in: path\n description: ID of the order that needs to be deleted\n required: true\n schema:\n type: integer\n format: int64\n minimum: 1\n responses:\n \"400\":\n description: Invalid ID supplied\n \"404\":\n description: Order not found\n /user:\n post:\n tags:\n - user\n summary: Create user\n description: This can only be done by the logged in user.\n operationId: createUser\n requestBody:\n content:\n application/json:\n schema:\n $ref: \"#/components/schemas/User\"\n description: Created user object\n required: true\n responses:\n default:\n description: successful operation\n /user/createWithArray:\n post:\n tags:\n - user\n summary: Creates list of users with given input array\n description: \"\"\n operationId: createUsersWithArrayInput\n requestBody:\n $ref: \"#/components/requestBodies/UserArray\"\n responses:\n default:\n description: successful operation\n /user/createWithList:\n post:\n tags:\n - user\n summary: Creates list of users with given input array\n description: \"\"\n operationId: createUsersWithListInput\n requestBody:\n $ref: \"#/components/requestBodies/UserArray\"\n responses:\n default:\n description: successful operation\n /user/login:\n get:\n tags:\n - user\n summary: Logs user into the system\n description: \"\"\n operationId: loginUser\n parameters:\n - name: username\n in: query\n description: The user name for login\n required: true\n schema:\n type: string\n - name: password\n in: query\n description: The password for login in clear text\n required: true\n schema:\n type: string\n responses:\n \"200\":\n description: successful operation\n headers:\n X-Rate-Limit:\n description: calls per hour allowed by the user\n schema:\n type: integer\n format: int32\n X-Expires-After:\n description: date in UTC when token expires\n schema:\n type: string\n format: date-time\n content:\n application/xml:\n schema:\n type: string\n application/json:\n schema:\n type: string\n \"400\":\n description: Invalid username/password supplied\n /user/logout:\n get:\n tags:\n - user\n summary: Logs out current logged in user session\n description: \"\"\n operationId: logoutUser\n responses:\n default:\n description: successful operation\n \"/user/{username}\":\n get:\n tags:\n - user\n summary: Get user by user name\n description: \"\"\n operationId: getUserByName\n parameters:\n - name: username\n in: path\n description: \"The name that needs to be fetched. Use user1 for testing. \"\n required: true\n schema:\n type: string\n responses:\n \"200\":\n description: successful operation\n content:\n application/xml:\n schema:\n $ref: \"#/components/schemas/User\"\n application/json:\n schema:\n $ref: \"#/components/schemas/User\"\n \"400\":\n description: Invalid username supplied\n \"404\":\n description: User not found\n put:\n tags:\n - user\n summary: Updated user\n description: This can only be done by the logged in user.\n operationId: updateUser\n parameters:\n - name: username\n in: path\n description: name that need to be updated\n required: true\n schema:\n type: string\n requestBody:\n content:\n application/json:\n schema:\n $ref: \"#/components/schemas/User\"\n description: Updated user object\n required: true\n responses:\n \"400\":\n description: Invalid user supplied\n \"404\":\n description: User not found\n delete:\n tags:\n - user\n summary: Delete user\n description: This can only be done by the logged in user.\n operationId: deleteUser\n parameters:\n - name: username\n in: path\n description: The name that needs to be deleted\n required: true\n schema:\n type: string\n responses:\n \"400\":\n description: Invalid username supplied\n \"404\":\n description: User not found\nexternalDocs:\n description: Find out more about your mom\n url: http://your.mom\nservers:\n - url: https://petstore.swagger.io/v2\ncomponents:\n requestBodies:\n UserArray:\n content:\n application/json:\n schema:\n type: array\n items:\n $ref: \"#/components/schemas/User\"\n description: List of user object\n required: true\n Pet:\n content:\n application/json:\n schema:\n $ref: \"#/components/schemas/Pet\"\n application/xml:\n schema:\n $ref: \"#/components/schemas/Pet\"\n description: Pet object that needs to be added to the store\n required: true\n schemas:\n Order:\n type: object\n properties:\n id:\n type: integer\n format: int64\n petId:\n type: integer\n format: int64\n quantity:\n type: integer\n format: int32\n shipDate:\n type: string\n format: date-time\n status:\n type: string\n description: Order Status\n enum:\n - placed\n - approved\n - delivered\n complete:\n type: boolean\n default: false\n xml:\n name: Order\n User:\n type: object\n properties:\n id:\n type: integer\n format: int64\n username:\n type: string\n firstName:\n type: string\n lastName:\n type: string\n email:\n type: string\n password:\n type: string\n phone:\n type: string\n userStatus:\n type: integer\n format: int32\n description: User Status\n xml:\n name: User\n Category:\n type: object\n properties:\n id:\n type: integer\n format: int64\n name:\n type: string\n xml:\n name: Category\n Tag:\n type: object\n properties:\n id:\n type: integer\n format: int64\n name:\n type: string\n xml:\n name: Tag\n Pet:\n type: object\n required:\n - name\n - photoUrls\n properties:\n id:\n type: integer\n format: int64\n category:\n $ref: \"#/components/schemas/Category\"\n name:\n type: string\n example: doggie\n photoUrls:\n type: array\n xml:\n name: photoUrl\n wrapped: true\n items:\n type: string\n tags:\n type: array\n xml:\n name: tag\n wrapped: true\n items:\n $ref: \"#/components/schemas/Tag\"\n status:\n type: string\n description: pet status in the store\n enum:\n - available\n - pending\n - sold\n xml:\n name: Pet\n ApiResponse:\n type: object\n properties:\n code:\n type: integer\n format: int32\n type:\n type: string\n message:\n type: string","contentType":"yaml","_type":"api_spec"},{"_id":"env_c42d5b08a21141908834b43e42ee6e46","parentId":"env_70d3512c1c8840df95de5b7dac78ac9f","modified":1686541816225,"created":1686303739938,"name":"Dev","data":{"scheme":"http","host":"localhost","port":3000,"base_path":"api"},"dataPropertyOrder":{"&":["scheme","host","port","base_path"]},"color":null,"isPrivate":false,"metaSortKey":1686303739938,"_type":"environment"}]} \ No newline at end of file diff --git a/src/app/admin/layout.tsx b/src/app/admin/layout.tsx index 01fb0c8..928cb35 100644 --- a/src/app/admin/layout.tsx +++ b/src/app/admin/layout.tsx @@ -1,25 +1,30 @@ // import '../globals.css' -import { Inter } from 'next/font/google' -import StyledJsxRegistry from '../registry'; -import Providers from '@/providers/providers'; -import 'bootstrap/dist/css/bootstrap.css'; -import { Toaster } from 'react-hot-toast'; +import { Inter } from "next/font/google"; +import StyledJsxRegistry from "../registry"; +import ContextProviders from "@/providers/contextproviders"; +import "bootstrap/dist/css/bootstrap.css"; +import { Toaster } from "react-hot-toast"; -const inter = Inter({ subsets: ['latin'], fallback: ['system-ui', 'arial'] }) +const inter = Inter({ subsets: ["latin"], fallback: ["system-ui", "arial"] }); export const metadata = { - title: 'Create Next App', - description: 'Generated by create next app', -} + title: "Create Next App", + description: "Generated by create next app", +}; export default function RootLayout({ - children, + children, }: { - children: React.ReactNode + children: React.ReactNode; }) { - return ( - - {children} - - ) + return ( + + + + + {children} + + + + ); } diff --git a/src/app/api-doc/page.tsx b/src/app/api-doc/page.tsx new file mode 100644 index 0000000..f429059 --- /dev/null +++ b/src/app/api-doc/page.tsx @@ -0,0 +1,11 @@ +import { getApiDocs } from "@/lib/swagger"; +import ReactSwagger from "@/components/client/SwaggerComponent"; + +export default async function IndexPage() { + const spec = await getApiDocs(); + return ( +
+ +
+ ); +} \ No newline at end of file diff --git a/src/app/api/attachment/route.ts b/src/app/api/attachment/route.ts index cc71211..ed590d7 100644 --- a/src/app/api/attachment/route.ts +++ b/src/app/api/attachment/route.ts @@ -1,6 +1,5 @@ "use server"; -import { APIError, attemptAPIAction } from "@/util"; import { sequelize, Bucket, @@ -20,6 +19,7 @@ import { } from "@/app/lib/actions/entityManagement/attachment/attachmentActions"; import { Attributes } from "@sequelize/core"; import { RequestCookie } from "next/dist/compiled/@edge-runtime/cookies"; +import { APIError, attemptAPIAction } from "@/util/api"; export async function tryCreateAttachment(request: Request) { // Make sure the DB is ready @@ -127,6 +127,17 @@ export async function tryCreateAttachment(request: Request) { ); } + + +/** + * @swagger + * /api/attachment: + * get: + * description: Returns all attachments + * responses: + * 200: + * description: idk + */ export async function tryFetchAttachments(request: Request) { await Post.sync(); diff --git a/src/app/api/auth/route.ts b/src/app/api/auth/route.ts index 1da075f..fe4d193 100644 --- a/src/app/api/auth/route.ts +++ b/src/app/api/auth/route.ts @@ -1,8 +1,8 @@ "use server"; import { cookies } from "next/headers"; -import { APIError, UserAuth, parseBasicAuth, getAssociatedUser } from "@/util"; import { Auth, User } from "@/models"; +import { APIError, getAssociatedUser, parseBasicAuth } from "@/util/api"; async function tryAuth(request: Request) { // await User.sync(); @@ -63,11 +63,12 @@ async function tryAuth(request: Request) { 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; - } - } + } 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/setupDB/route.ts b/src/app/api/setupDB/route.ts index 83ac650..4b51a4b 100644 --- a/src/app/api/setupDB/route.ts +++ b/src/app/api/setupDB/route.ts @@ -1,159 +1,189 @@ -'use server' +"use server"; import { cookies } from "next/headers"; -import { APIError} from "@/util/api/error" -import { UserAuth, parseBasicAuth, getAssociatedUser } from "@/util/api/user" -import { Attachment, Auth, Bucket, DBState, Post, PostTag, Project, Tag, User, UserPerms,dbSync,sequelize} from "@/models"; +import { APIError } from "@/util/api/error"; +import { + Attachment, + Auth, + Bucket, + DBState, + Post, + PostTag, + Project, + Tag, + User, + UserPerms, + dbSync, + sequelize, +} from "@/models"; import Sequelize, { CreationAttributes, DataTypes } from "@sequelize/core"; -import { SqliteColumnsDescription, SqliteDialect, SqliteQueryInterface } from "@sequelize/sqlite3"; +import { + SqliteColumnsDescription, + SqliteDialect, + SqliteQueryInterface, +} from "@sequelize/sqlite3"; import { hashpassword } from "@/util/auth"; import { copyFile, readFileSync } from "fs"; import path from "path"; -import { Attributes } from '@sequelize/core'; -import { DeepPartial } from "@/util/DeepPartial"; import { UUID } from "crypto"; +import { runApiAction } from "@/util/api"; -async function seedUsers(qif: SqliteQueryInterface){ - const fp = path.resolve('./db/seed/users.json'); - const json: {users: CreationAttributes[]} = JSON.parse(Buffer.from(readFileSync(fp).valueOf()).toString()); +async function seedUsers(qif: SqliteQueryInterface) { + const fp = path.resolve("./db/seed/users.json"); + const json: { users: CreationAttributes[] } = JSON.parse( + Buffer.from(readFileSync(fp).valueOf()).toString() + ); - const users = json.users.map(async user=>{ - user.password = await hashpassword(user.password); - return user; - }) - - const dbUsers = await User.bulkCreate(await Promise.all(users), {include: User.associations.perms}) + const users = json.users.map(async (user) => { + user.password = await hashpassword(user.password); + return user; + }); + + const dbUsers = await User.bulkCreate(await Promise.all(users), { + include: User.associations.perms, + }); } -async function seedPosts(qif: SqliteQueryInterface){ - const fp = path.resolve('./db/seed/posts.json'); - const json: {users: CreationAttributes[]} = JSON.parse(Buffer.from(readFileSync(fp).valueOf()).toString()); - const projects =[ - { - "name": "Blog", - "readableIdentifier": "blog", - "posts": [ - { - "title": "Test Post", - "content": "# Hello \nthis is some **test** markdown and we make some edits\n![](/attachment/788dfc19-55ba-482c-8124-277702296dfb/FB_IMG_1716665756868.jpg)", - "description": "A new post to test the blog system", - "project_id": 1, - "user_id": 1, - "buckets": [ - { - "id": "788dfc19-55ba-482c-8124-277702296dfb", - "attachments": [ - { - "filename": "FB_IMG_1716665756868.jpg" - } - ] - } - ] - } - ] - }] - projects.map(project=>{ - Project.create({name: project.name, readableIdentifier: project.readableIdentifier}); - project.posts.map(async post=>{ - const pst = await Post.create({title:post.title, content:post.content, description:post.description, project_id: post.project_id, user_id: post.user_id}); - post.buckets.map(async bucket=>{ - pst.createBucket({id:bucket.id as UUID}); - bucket.attachments.map(attachment=>{ - Attachment.create({bucket_id:bucket.id as UUID, filename: attachment.filename}).then((a)=>{ - copyFile( - path.resolve('.','db','seed','post',a.filename), - path.resolve('.','bucket',bucket.id,a.filename), - ()=>{ +async function seedPosts(qif: SqliteQueryInterface) { + const fp = path.resolve("./db/seed/posts.json"); + const json: { users: CreationAttributes[] } = JSON.parse( + Buffer.from(readFileSync(fp).valueOf()).toString() + ); + const projects = [ + { + name: "Blog", + readableIdentifier: "blog", + posts: [ + { + title: "Test Post", + content: + "# Hello \nthis is some **test** markdown and we make some edits\n![](/attachment/788dfc19-55ba-482c-8124-277702296dfb/FB_IMG_1716665756868.jpg)", + description: "A new post to test the blog system", + project_id: 1, + user_id: 1, + buckets: [ + { + id: "788dfc19-55ba-482c-8124-277702296dfb", + attachments: [ + { + filename: "FB_IMG_1716665756868.jpg", + }, + ], + }, + ], + }, + ], + }, + ]; + projects.map((project) => { + Project.create({ + name: project.name, + readableIdentifier: project.readableIdentifier, + }); + project.posts.map(async (post) => { + const pst = await Post.create({ + title: post.title, + content: post.content, + description: post.description, + project_id: post.project_id, + user_id: post.user_id, + }); + post.buckets.map(async (bucket) => { + pst.createBucket({ id: bucket.id as UUID }); + bucket.attachments.map((attachment) => { + Attachment.create({ + bucket_id: bucket.id as UUID, + filename: attachment.filename, + }).then((a) => { + copyFile( + path.resolve(".", "db", "seed", "post", a.filename), + path.resolve(".", "bucket", bucket.id, a.filename), + () => {} + ); + }); + }); + }); + }); + }); - } - ) - }) - }) - }) - }) - }) - - - - - const project = await Project.findOne({where: { - readableIdentifier: 'blog' - }}).then(e=> e ? e : Project.create({name:'General Blog',readableIdentifier:'blog'})); + const project = await Project.findOne({ + where: { + readableIdentifier: "blog", + }, + }).then((e) => + e + ? e + : Project.create({ + name: "General Blog", + readableIdentifier: "blog", + }) + ); } +async function seedDatabase(qif: SqliteQueryInterface) { + await seedUsers(qif); + await seedPosts(qif); - - - -async function seedDatabase(qif:SqliteQueryInterface){ - await seedUsers(qif); - await seedPosts(qif) - - // await Post.create({ - // title: 'Test Post', - // content: ` - // # Hello - // this is some **test** markdown - // `, - // project_id: project.id, - // user_id: user.id - // }) - // await Post.create({ - // title: 'Test Post 2', - // content: ` - // # Hello - // this is amother post with some **test** markdown - // `, - // project_id: project.id, - // user_id: user.id - // }) + // await Post.create({ + // title: 'Test Post', + // content: ` + // # Hello + // this is some **test** markdown + // `, + // project_id: project.id, + // user_id: user.id + // }) + // await Post.create({ + // title: 'Test Post 2', + // content: ` + // # Hello + // this is amother post with some **test** markdown + // `, + // project_id: project.id, + // user_id: user.id + // }) } -async function trySetup(request:Request){ - await dbSync; +export async function GET(request: Request) { + runApiAction(async (request) => { + await dbSync; - const queryInterface = sequelize.queryInterface - + const queryInterface = sequelize.queryInterface; - const version = (await DBState.findAll()).sort((a,b)=> ((a.version > b.version) ? 1 : -1)).map(a=>a.version)[0]; + const version = (await DBState.findAll()) + .sort((a, b) => (a.version > b.version ? 1 : -1)) + .map((a) => a.version)[0]; - + switch (version) { + case 1: + break; + default: + seedDatabase(queryInterface); + const postsRows: SqliteColumnsDescription = await queryInterface + .describeTable(Post.table.tableName) + .then((t) => t); + if (!postsRows["project_id"]) + queryInterface.addColumn("Posts", "project_id", { + type: DataTypes.INTEGER, + acceptsNull: () => false, + defaultValue: 1, + }); + break; + } - switch(version){ - case 1: - break; - default: - seedDatabase(queryInterface); - const postsRows:SqliteColumnsDescription = await queryInterface.describeTable(Post.table.tableName).then(t=>t); - if (!postsRows['project_id']) queryInterface.addColumn('Posts','project_id',{type: DataTypes.INTEGER, acceptsNull:()=>false,defaultValue:1}) - break; - } - - return new Response( - JSON.stringify( - { - test: await queryInterface.describeTable('Posts').then(t=>t) - }), - { - status: 200, - headers:{ - "Content-Type": "text/JSON" - } - } - ); -} - -export async function GET(request:Request){ - try{ - return await trySetup(request); - } - catch(e){ - if (e instanceof APIError){ - return new Response(e.info.responseText,{status:e.info.status}); - } - else{ - throw e; - } - } + return new Response( + JSON.stringify({ + test: await queryInterface + .describeTable("Posts") + .then((t) => t), + }), + { + status: 200, + headers: { + "Content-Type": "text/JSON", + }, + } + ); + }, request); } diff --git a/src/app/api/user/route.ts b/src/app/api/user/route.ts index 1d4f72c..b86e266 100644 --- a/src/app/api/user/route.ts +++ b/src/app/api/user/route.ts @@ -90,7 +90,7 @@ async function attemptGetUsers(request:Request){ ); } -export async function GET(request:Request){ +export async function GET(request:Request): Promise{ try{ return await attemptGetUsers(request); } diff --git a/src/app/article/[...slug]/page.tsx b/src/app/article/[...slug]/page.tsx index 860a7d9..00c9113 100644 --- a/src/app/article/[...slug]/page.tsx +++ b/src/app/article/[...slug]/page.tsx @@ -12,7 +12,7 @@ import "@/app/index.css" import { Post } from "@/models"; import { Attributes } from "@sequelize/core"; -import { DeepPartial } from "@/util/DeepPartial"; +import { DeepPartial } from "@/util/deeppartial"; async function getData(slug:string):Promise> { diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 98a4a16..8cda69c 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,7 +1,7 @@ import './globals.css' import { Inter } from 'next/font/google' import StyledJsxRegistry from './registry'; -import Providers from '@/providers/providers'; +import ContextProviders from '@/providers/contextproviders'; const inter = Inter({ subsets: ['latin'], fallback: ['system-ui', 'arial'] }) @@ -17,7 +17,7 @@ export default function RootLayout({ }) { return ( - {children} + {children} ) } diff --git a/src/app/lib/actions/actions.ts b/src/app/lib/actions/actions.ts index e788bac..2cdd8d9 100644 --- a/src/app/lib/actions/actions.ts +++ b/src/app/lib/actions/actions.ts @@ -6,7 +6,7 @@ import { parseSetCookie } from "@/util/cookies"; import makeFetchCookie from "fetch-cookie"; import fetchCookie from "fetch-cookie"; import { User, Auth } from "@/models"; -import { AuthProps } from "@/providers/providers"; +import { AuthContextProviderProps } from "@/providers"; type LoginReturn = { cookie?: unknown; @@ -42,7 +42,7 @@ async function attemptAPILogin( )}` ).toString("base64")}` ); - let res = await fetchWithCookie(constructAPIUrl("auth"), { + let res = await fetchWithCookie(await constructAPIUrl("auth"), { method: "POST", credentials: "include", headers: headers, @@ -71,6 +71,7 @@ export async function serverAttemptAuthenticateUser( return signInStatus; } catch (error: any) { if (error) { + console.log(error); switch (error.type) { case "CredentialsSignin": return { errorMessage: "invalidCredentials" }; @@ -85,12 +86,15 @@ export async function serverAttemptAuthenticateUser( export async function serverValidateSessionCookie( koek: string ): Promise { - const validateSession = await fetch(constructAPIUrl("auth/validate"), { - method: "POST", - headers: { - Cookie: `auth=${koek};`, - }, - }); + const validateSession = await fetch( + await constructAPIUrl("auth/validate"), + { + method: "POST", + headers: { + Cookie: `auth=${koek};`, + }, + } + ); if (validateSession.status == 200) return true; else return false; } @@ -107,7 +111,7 @@ export async function userIsAdmin(): Promise { if (!parsedAuth.id || !parsedAuth.token || !parsedAuth.user_id) return false; - const p: AuthProps = { + const p: AuthContextProviderProps = { auth: { id: parsedAuth.id, token: parsedAuth.token, @@ -121,7 +125,7 @@ export async function userIsAdmin(): Promise { return true; } -export async function getCookieAuth(): Promise { +export async function getCookieAuth(): Promise { const cookieAuthValue = await cookies().get("auth")?.value; const cookieAuthSanitized = cookieAuthValue ? JSON.parse(JSON.stringify(cookieAuthValue)) @@ -138,7 +142,7 @@ export async function getCookieAuth(): Promise { include: { model: User }, }); if (!foundAuth) return {}; - const authObject: AuthProps = { + const authObject: AuthContextProviderProps = { auth: { id: kd.id, token: kd.token, diff --git a/src/app/page.tsx b/src/app/page.tsx index 521bfbf..dc2a1df 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -7,7 +7,7 @@ import ReactDOM from "react"; import "/public/global.css" import "./index.css" import { Post } from "@/models"; -import { constructAPIUrl } from "@/util"; +import { constructAPIUrl } from "@/util/url"; import Link from "next/link"; import { Attributes } from "@sequelize/core"; @@ -17,7 +17,7 @@ type DeepPartial = T extends object ? { export default async function Test() { - const response = await fetch(constructAPIUrl('post')); + const response = await fetch(await constructAPIUrl('post')); const articles:Array> = await response.json(); diff --git a/src/components/client/SwaggerComponent.tsx b/src/components/client/SwaggerComponent.tsx new file mode 100644 index 0000000..7d4bd6a --- /dev/null +++ b/src/components/client/SwaggerComponent.tsx @@ -0,0 +1,14 @@ +'use client'; + +import SwaggerUI from 'swagger-ui-react'; +import 'swagger-ui-react/swagger-ui.css'; + +type Props = { + spec: Record, +}; + +function ReactSwagger({ spec }: Props) { + return ; +} + +export default ReactSwagger; \ No newline at end of file diff --git a/src/components/client/admin/CAuthHandler.tsx b/src/components/client/admin/CAuthHandler.tsx new file mode 100644 index 0000000..699b2a2 --- /dev/null +++ b/src/components/client/admin/CAuthHandler.tsx @@ -0,0 +1,15 @@ +'use client' +import { AuthContext, AuthContextProviderProps } from "@/providers"; +import { ReactNode } from "react" + +type CAuthProviderProps = { + children?:ReactNode; + authProps:AuthContextProviderProps +} + +export default function CAuthProvider(props:CAuthProviderProps){ + + return ( + {props.children} + ) +} \ No newline at end of file diff --git a/src/components/client/admin/loginForm.tsx b/src/components/client/admin/CLoginForm.tsx similarity index 82% rename from src/components/client/admin/loginForm.tsx rename to src/components/client/admin/CLoginForm.tsx index 919dda7..a0a61be 100644 --- a/src/components/client/admin/loginForm.tsx +++ b/src/components/client/admin/CLoginForm.tsx @@ -1,19 +1,10 @@ 'use client' import { serverAttemptAuthenticateUser } from "@/app/lib/actions/actions"; -import { AuthContext } from "@/providers/providers"; -import { constructAPIUrl } from "@/util/url"; -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(){ +export default function CLoginForm(){ const [loginResult, dispatch] = useFormState(serverAttemptAuthenticateUser, undefined); return ( diff --git a/src/components/client/admin/PostEditor.tsx b/src/components/client/admin/PostEditor.tsx index 6591e51..36938ee 100644 --- a/src/components/client/admin/PostEditor.tsx +++ b/src/components/client/admin/PostEditor.tsx @@ -6,9 +6,6 @@ import { EntityEditorTextArea } from '../input/EntityEditorTextArea'; import { ChangeEventHandler, MouseEventHandler, - MutableRefObject, - useLayoutEffect, - useRef, useState, } from "react"; import { diff --git a/src/components/client/admin/PostTable.tsx b/src/components/client/admin/PostTable.tsx index 05e18e5..009c0f7 100644 --- a/src/components/client/admin/PostTable.tsx +++ b/src/components/client/admin/PostTable.tsx @@ -19,7 +19,7 @@ import { } from "@/app/lib/actions/entityManagement/post/postActions"; import { PostViewProps } from "@/views/admin/post"; -import { aifa, StateHook } from "@/util/"; +import { StateHook } from "@/util/"; export type PostTableStateProps = { posts: StateHook; @@ -110,13 +110,10 @@ export default function PostTable({ : `${post.content.substring(0, 255)}...`} - {aifa( - projects.find((e) => { - console.log(e.id); - return e.id == post.project.id; - })?.readableIdentifier, - "uncategorized" - )} + {projects.find((e) => { + console.log(e.id); + return e.id == post.project.id; + })?.readableIdentifier || "uncategorized"} {post.createdAt?.toString()} {post.updatedAt?.toString()} diff --git a/src/components/client/admin/clientAuthHandler.tsx b/src/components/client/admin/clientAuthHandler.tsx deleted file mode 100644 index 1dff506..0000000 --- a/src/components/client/admin/clientAuthHandler.tsx +++ /dev/null @@ -1,16 +0,0 @@ -'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/client/input/EntityEditorTextArea.tsx b/src/components/client/input/EntityEditorTextArea.tsx index b4b2941..c3b3783 100644 --- a/src/components/client/input/EntityEditorTextArea.tsx +++ b/src/components/client/input/EntityEditorTextArea.tsx @@ -5,7 +5,6 @@ import { MutableRefObject, useLayoutEffect, ChangeEventHandler, - useState, } from "react"; import { StateHook } from "@/util"; diff --git a/src/components/server/admin/authHandler.tsx b/src/components/server/admin/authHandler.tsx index fc34cde..d1e3c14 100644 --- a/src/components/server/admin/authHandler.tsx +++ b/src/components/server/admin/authHandler.tsx @@ -1,43 +1,46 @@ -'use server' +"use server"; import { cookies } from "next/headers"; -import LoginForm from "@/components/client/admin/loginForm"; -import ClientAuthHandler from "@/components/client/admin/clientAuthHandler"; +import CLoginForm from "@/components/client/admin/CLoginForm"; +import ClientAuthHandler from "@/components/client/admin/CAuthHandler"; import { serverValidateSessionCookie } from "@/app/lib/actions/actions"; import { ReactNode } from "react"; -import { AuthContext, AuthProps } from "@/providers/providers"; - +import { AuthContextProviderProps } from "@/providers"; interface Props { - children?: ReactNode; - params?: any; - requiredRole?: number; + 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 = { - }; - if(koek){ - const kd = JSON.parse(koek); - if(kd.id && kd.token && kd.user_id){ - p = { - auth: { - id:kd.id, - token:kd.token, - user_id:kd.user_id - } - } - } - } + const protoKoek = await cookies().get("auth")?.value; + const koek = decodeURIComponent(protoKoek ? protoKoek : ""); + // console.log("koekje:" + koek) + let p: AuthContextProviderProps = {}; + if (koek) { + const kd = JSON.parse(koek); + if (kd.id && kd.token && kd.user_id) { + p = { + auth: { + id: kd.id, + token: kd.token, + user_id: kd.user_id, + }, + }; + } + } - return ( -
- {!(koek && await serverValidateSessionCookie(koek)) ? { } : {props.children}} -
- ); + return ( +
+ {!(koek && (await serverValidateSessionCookie(koek))) ? ( + {} + ) : ( + + {props.children} + + )} +
+ ); } diff --git a/src/components/shared/bootstrap.tsx b/src/components/shared/bootstrap.tsx deleted file mode 100644 index 4f53cf9..0000000 --- a/src/components/shared/bootstrap.tsx +++ /dev/null @@ -1,10 +0,0 @@ -'use client' -import 'bootstrap/dist/css/bootstrap.css'; -import { useEffect } from 'react'; - -export default function Bootstrap(Component, children, pageProps){ - useEffect(() => { - typeof document !== undefined ? require('bootstrap/dist/js/bootstrap') : null - }, []); - return <>
; -} \ No newline at end of file diff --git a/src/components/shared/news/tagbar.module.css b/src/components/shared/news/tagbar.module.css index d50dac2..991e0b3 100644 --- a/src/components/shared/news/tagbar.module.css +++ b/src/components/shared/news/tagbar.module.css @@ -7,7 +7,7 @@ margin-left:0px; padding: 1px 5px 1px 5px; border-radius: 20%; - *display: inline; + display: inline; } .tagbar{ margin: 0px 0px 0px 0px; diff --git a/src/lib/swagger.ts b/src/lib/swagger.ts index 1b991b9..5146a81 100644 --- a/src/lib/swagger.ts +++ b/src/lib/swagger.ts @@ -1,3 +1,4 @@ +// @ts-ignore import { createSwaggerSpec } from "next-swagger-doc"; export const getApiDocs = async () => { diff --git a/src/models/DBState.ts b/src/models/DBState.ts index 0ada976..5495d97 100644 --- a/src/models/DBState.ts +++ b/src/models/DBState.ts @@ -10,10 +10,11 @@ import { HasOne, UpdatedAt, CreatedAt, + Table, } from '@sequelize/core/decorators-legacy'; import { SqliteDialect } from '@sequelize/sqlite3'; - +@Table({tableName: "DBStates"}) export class DBState extends Model, InferCreationAttributes>{ @Attribute(DataTypes.INTEGER) diff --git a/src/models/Project.ts b/src/models/Project.ts index ac03e57..2986586 100644 --- a/src/models/Project.ts +++ b/src/models/Project.ts @@ -20,7 +20,7 @@ export class Project extends Model< > { @Attribute(DataTypes.INTEGER) @PrimaryKey - @Unique + // @Unique @AutoIncrement declare id: CreationOptional; @Attribute(DataTypes.STRING) diff --git a/src/models/index.ts b/src/models/index.ts index 536255e..0292f6b 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -25,7 +25,7 @@ export * from './UserPerms'; export const sequelize = new Sequelize({ dialect: SqliteDialect, - storage: 'db.sqlite', + storage: './db/db.sqlite', models: [Auth, Attachment, Bucket, DBState, Post, PostBucket, PostTag, Project, Tag, User, UserPerms], }); diff --git a/src/providers/authprovider.tsx b/src/providers/authprovider.tsx new file mode 100644 index 0000000..456baca --- /dev/null +++ b/src/providers/authprovider.tsx @@ -0,0 +1,14 @@ +import { Auth, User } from "@/models"; +import { Attributes } from "@sequelize/core"; +import { Context, createContext } from "react"; + + +export type AuthContextProviderProps = { + auth?: Attributes + user?: Attributes +} + +let p: AuthContextProviderProps = {} + +export const AuthContext: Context = createContext(p); + diff --git a/src/providers/providers.tsx b/src/providers/contextproviders.tsx similarity index 58% rename from src/providers/providers.tsx rename to src/providers/contextproviders.tsx index b835d95..4e76164 100644 --- a/src/providers/providers.tsx +++ b/src/providers/contextproviders.tsx @@ -3,23 +3,14 @@ import { Auth, User } from "@/models"; import { ReactNode, createContext } from "react"; import { Attributes, InferAttributes } from "@sequelize/core"; +import { AuthContext } from "./authprovider"; - -export type AuthProps = { - auth?: Attributes - user?: Attributes -} - -let p: AuthProps = {} - -export const AuthContext = createContext(p); - -interface Props { +interface ProvidersProps { children?: ReactNode; params?: any; -} +} -export default function Providers(props:Props){ +export default function ContextProviders(props:ProvidersProps){ return ( {props.children} ) diff --git a/src/providers/index.ts b/src/providers/index.ts new file mode 100644 index 0000000..f1e2c1b --- /dev/null +++ b/src/providers/index.ts @@ -0,0 +1,2 @@ +export * from './authprovider'; +export * from './contextproviders'; diff --git a/src/util/aifa.ts b/src/util/aifa.ts deleted file mode 100644 index 0104e5c..0000000 --- a/src/util/aifa.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { ReactNode } from "react"; - -export const aifa = (a: ReactNode, b: ReactNode) => (a ? a : b); \ No newline at end of file diff --git a/src/util/api/getAPIEnv.ts b/src/util/api/getAPIEnv.ts index d38702c..af1a412 100644 --- a/src/util/api/getAPIEnv.ts +++ b/src/util/api/getAPIEnv.ts @@ -1,10 +1,9 @@ 'server only'; -// import Auth from "./Auth"; -export function getAPIEnv() { +export async function getAPIEnv() { return { 'schema': process.env.API_SCHEMA, 'host': process.env.API_HOST, 'port': process.env.API_PORT, - 'basepath': process.env.API_BASEPATH + 'basepath': process.env.API_BASEPATH, }; } diff --git a/src/util/api/index.ts b/src/util/api/index.ts index 26fde1e..08e4369 100644 --- a/src/util/api/index.ts +++ b/src/util/api/index.ts @@ -1,3 +1,4 @@ export * from './error'; export * from './getAPIEnv'; +export * from './runapiaction'; export * from './user'; diff --git a/src/util/api/runapiaction.ts b/src/util/api/runapiaction.ts new file mode 100644 index 0000000..4c85e4e --- /dev/null +++ b/src/util/api/runapiaction.ts @@ -0,0 +1,19 @@ +import { NextApiResponse } from "next"; +import { APIError } from "./error"; + +export type APIRequest = (request:Request)=>Promise; + +export async function runApiAction(c:APIRequest,request:Request){ + try{ + return await c(request); + } + catch(e){ + if (e instanceof APIError){ + return new Response(e.info.responseText,{status:e.info.status}); + console.log("responded"); + } + else{ + throw e; + } + } +} \ No newline at end of file diff --git a/src/util/DeepPartial.ts b/src/util/deeppartial.ts similarity index 100% rename from src/util/DeepPartial.ts rename to src/util/deeppartial.ts diff --git a/src/util/index.ts b/src/util/index.ts index 3eaa49b..5be0227 100644 --- a/src/util/index.ts +++ b/src/util/index.ts @@ -1,6 +1,5 @@ -export * from './DeepPartial'; -export * from './aifa'; export * from './auth'; export * from './cookies'; +export * from './deeppartial'; export * from './state'; export * from './strings'; diff --git a/src/util/url/urlConstructor.ts b/src/util/url/urlConstructor.ts index 8527298..618c8a4 100644 --- a/src/util/url/urlConstructor.ts +++ b/src/util/url/urlConstructor.ts @@ -2,11 +2,11 @@ import { getAPIEnv } from "../api/getAPIEnv"; -export function constructAPIUrl(endpoint:string){ - const { schema, host, port, basepath } = getAPIEnv(); +export async function constructAPIUrl(endpoint:string){ + const { schema, host, port, basepath } = await getAPIEnv(); return `${schema}://${host}:${port}/${basepath}/${endpoint}` } -export function constructUrl(endpoint:string){ - const { schema, host, port, basepath } = getAPIEnv(); +export async function constructUrl(endpoint:string){ + const { schema, host, port, basepath } = await getAPIEnv(); return `${schema}://${host}:${port}/${endpoint}` }1 \ No newline at end of file diff --git a/src/views/admin/post/CPostView.tsx b/src/views/admin/post/CPostView.tsx index b7dc421..dc758c3 100644 --- a/src/views/admin/post/CPostView.tsx +++ b/src/views/admin/post/CPostView.tsx @@ -38,16 +38,14 @@ export function CPostView({ posts: parseStateHook(useState(posts)), editor: parseStateHook(useState(initEditorState)), }; - + // render out the post table return ( - <> - - + ); } diff --git a/src/views/admin/post/PostView.tsx b/src/views/admin/post/PostView.tsx index 457f4fa..9ee0ada 100644 --- a/src/views/admin/post/PostView.tsx +++ b/src/views/admin/post/PostView.tsx @@ -30,14 +30,6 @@ export async function PostView(props: Props) { "UpdatedAt", ]; - const actions: PostServerActions = { - deletePost: deletePost, - getPosts: getPostsWithBucketsAndProject, - getProjects: getProjects, - savePost: updatePost, - // uploadAttachment:tryCreateAttachment - }; - const posts: GetPostsAttributes[] | undefined = handleActionResult( await getPostsWithBucketsAndProject() ); @@ -52,7 +44,12 @@ export async function PostView(props: Props) { posts={posts ? posts : []} projects={projects} headings={headings} - actions={actions} + actions={{ + deletePost: deletePost, + getPosts: getPostsWithBucketsAndProject, + getProjects: getProjects, + savePost: updatePost + }} />
diff --git a/src/views/admin/project/ProjectView.tsx b/src/views/admin/project/ProjectView.tsx index d8e8e64..e1d2581 100644 --- a/src/views/admin/project/ProjectView.tsx +++ b/src/views/admin/project/ProjectView.tsx @@ -1,6 +1,6 @@ cache: "no-store"; -import { ReactNode, useEffect } from "react"; +import { ReactNode } from "react"; import EntityManagementTable from "../../../components/client/EntityManagementTable"; import PostTable from "@/components/client/admin/PostTable"; import {