From 3687f5ac0f6e16604b485767e26cb25c2f5c3965 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Wed, 29 Apr 2026 18:55:53 +0000 Subject: [PATCH] Autosave: 20260429-185553 --- 502.html | 187 - Dockerfile | 21 - Dockerfile.dev | 85 - LICENSE | 1 - README.md | 244 - backend/.env | 1 - backend/.eslintignore | 4 - backend/.eslintrc.cjs | 15 - backend/.prettierrc | 11 - backend/.sequelizerc | 7 - backend/Dockerfile | 23 - backend/README.md | 56 - backend/package.json | 56 - backend/src/ai/LocalAIApi.js | 484 -- backend/src/auth/auth.js | 68 - backend/src/config.js | 79 - backend/src/db/api/customers.js | 541 -- backend/src/db/api/file.js | 87 - backend/src/db/api/order_items.js | 639 --- backend/src/db/api/orders.js | 1031 ---- backend/src/db/api/payments.js | 693 --- backend/src/db/api/permissions.js | 336 -- backend/src/db/api/product_categories.js | 447 -- backend/src/db/api/products.js | 821 --- backend/src/db/api/roles.js | 406 -- backend/src/db/api/shipments.js | 703 --- backend/src/db/api/users.js | 938 ---- backend/src/db/db.config.js | 33 - backend/src/db/migrations/1777487463402.js | 2873 ----------- .../migrations/20260316000000-create-files.js | 124 - ...ate-users-custom-permissions-join-table.js | 77 - backend/src/db/models/customers.js | 151 - backend/src/db/models/file.js | 53 - backend/src/db/models/index.js | 38 - backend/src/db/models/order_items.js | 155 - backend/src/db/models/orders.js | 325 -- backend/src/db/models/payments.js | 226 - backend/src/db/models/permissions.js | 75 - backend/src/db/models/product_categories.js | 115 - backend/src/db/models/products.js | 210 - backend/src/db/models/roles.js | 108 - backend/src/db/models/shipments.js | 190 - backend/src/db/models/users.js | 241 - backend/src/db/reset.js | 16 - .../db/seeders/20200430130759-admin-user.js | 66 - .../db/seeders/20200430130760-user-roles.js | 954 ---- .../db/seeders/20231127130745-sample-data.js | 3800 -------------- backend/src/db/utils.js | 27 - backend/src/helpers.js | 23 - backend/src/index.js | 164 - backend/src/middlewares/check-permissions.js | 149 - backend/src/middlewares/upload.js | 11 - backend/src/routes/auth.js | 207 - backend/src/routes/contactForm.js | 0 backend/src/routes/customers.js | 448 -- backend/src/routes/file.js | 32 - backend/src/routes/openai.js | 328 -- backend/src/routes/order_items.js | 448 -- backend/src/routes/orders.js | 474 -- backend/src/routes/organizationLogin.js | 2 - backend/src/routes/payments.js | 444 -- backend/src/routes/permissions.js | 429 -- backend/src/routes/pexels.js | 104 - backend/src/routes/product_categories.js | 435 -- backend/src/routes/products.js | 460 -- backend/src/routes/roles.js | 429 -- backend/src/routes/search.js | 52 - backend/src/routes/shipments.js | 448 -- backend/src/routes/sql.js | 61 - backend/src/routes/users.js | 440 -- backend/src/services/auth.js | 312 -- backend/src/services/customers.js | 138 - .../emailAddressVerification.html | 52 - .../invitation/invitationTemplate.html | 55 - .../passwordReset/passwordResetEmail.html | 52 - backend/src/services/email/index.js | 44 - .../email/list/addressVerification.js | 38 - backend/src/services/email/list/invitation.js | 37 - .../src/services/email/list/passwordReset.js | 38 - backend/src/services/file.js | 213 - .../notifications/errors/forbidden.js | 17 - .../notifications/errors/validation.js | 18 - backend/src/services/notifications/helpers.js | 35 - backend/src/services/notifications/list.js | 104 - backend/src/services/openai.js | 80 - backend/src/services/order_items.js | 138 - backend/src/services/orders.js | 138 - backend/src/services/payments.js | 138 - backend/src/services/permissions.js | 138 - backend/src/services/product_categories.js | 138 - backend/src/services/products.js | 138 - backend/src/services/roles.js | 437 -- backend/src/services/search.js | 363 -- backend/src/services/shipments.js | 138 - backend/src/services/users.js | 171 - backend/watcher.js | 49 - backend/yarn.lock | 4470 ----------------- docker/.gitignore | 1 - docker/README.md | 46 - docker/docker-compose.yml | 58 - docker/start-backend.sh | 2 - docker/wait-for-it.sh | 182 - frontend/.eslintignore | 3 - frontend/.eslintrc.cjs | 25 - frontend/.gitignore | 33 - frontend/.prettierrc | 10 - frontend/Dockerfile | 19 - frontend/LICENSE-justboil | 21 - frontend/README.md | 92 - frontend/next-env.d.ts | 6 - frontend/next.config.mjs | 32 - frontend/package.json | 79 - frontend/postcss.config.js | 9 - frontend/prettier.config.js | 13 - frontend/public/data-sources/clients.json | 1 - frontend/public/data-sources/history.json | 1 - frontend/public/favicon.svg | 27 - frontend/public/locales/de/common.json | 55 - frontend/public/locales/en/common.json | 52 - frontend/public/locales/es/common.json | 55 - frontend/public/locales/fr/common.json | 55 - frontend/src/colors.ts | 138 - frontend/src/components/AsideMenu.tsx | 30 - frontend/src/components/AsideMenuItem.tsx | 102 - frontend/src/components/AsideMenuLayer.tsx | 63 - frontend/src/components/AsideMenuList.tsx | 35 - frontend/src/components/BaseButton.tsx | 96 - frontend/src/components/BaseButtons.tsx | 38 - frontend/src/components/BaseDivider.tsx | 14 - frontend/src/components/BaseIcon.tsx | 32 - frontend/src/components/BigCalendar.tsx | 175 - frontend/src/components/CardBox.tsx | 64 - .../src/components/CardBoxComponentBody.tsx | 12 - .../src/components/CardBoxComponentEmpty.tsx | 11 - .../src/components/CardBoxComponentFooter.tsx | 10 - .../src/components/CardBoxComponentTitle.tsx | 17 - frontend/src/components/CardBoxModal.tsx | 59 - .../src/components/ChartLineSample/config.ts | 54 - .../src/components/ChartLineSample/index.tsx | 37 - frontend/src/components/ClickOutside.tsx | 35 - .../components/Customers/CardCustomers.tsx | 207 - .../components/Customers/ListCustomers.tsx | 152 - .../components/Customers/TableCustomers.tsx | 463 -- .../Customers/configureCustomersCols.tsx | 206 - .../src/components/DataGridMultiSelect.tsx | 55 - frontend/src/components/DevModeBadge.tsx | 150 - .../src/components/DragDropFilePicker.tsx | 124 - frontend/src/components/ErrorBoundary.tsx | 218 - frontend/src/components/FooterBar.tsx | 35 - frontend/src/components/FormCheckRadio.tsx | 20 - .../src/components/FormCheckRadioGroup.tsx | 20 - frontend/src/components/FormField.tsx | 80 - frontend/src/components/FormFilePicker.tsx | 92 - frontend/src/components/FormImagePicker.tsx | 90 - frontend/src/components/IconRounded.tsx | 34 - frontend/src/components/ImageField.tsx | 51 - frontend/src/components/IntroGuide.tsx | 55 - .../components/KanbanBoard/KanbanBoard.tsx | 51 - .../src/components/KanbanBoard/KanbanCard.tsx | 64 - .../components/KanbanBoard/KanbanColumn.tsx | 209 - frontend/src/components/LanguageSwitcher.tsx | 96 - .../src/components/ListActionsPopover.tsx | 115 - frontend/src/components/LoadingSpinner.tsx | 18 - frontend/src/components/Logo/index.tsx | 15 - frontend/src/components/NavBar.tsx | 57 - frontend/src/components/NavBarItem.tsx | 132 - frontend/src/components/NavBarItemPlain.tsx | 30 - frontend/src/components/NavBarMenuList.tsx | 19 - frontend/src/components/NotificationBar.tsx | 57 - .../Order_items/CardOrder_items.tsx | 219 - .../Order_items/ListOrder_items.tsx | 160 - .../Order_items/TableOrder_items.tsx | 463 -- .../Order_items/configureOrder_itemsCols.tsx | 237 - frontend/src/components/Orders/CardOrders.tsx | 387 -- frontend/src/components/Orders/ListOrders.tsx | 272 - .../src/components/Orders/TableOrders.tsx | 517 -- .../components/Orders/configureOrdersCols.tsx | 459 -- frontend/src/components/OverlayLayer.tsx | 41 - frontend/src/components/Pagination.tsx | 85 - .../src/components/PasswordSetOrReset.tsx | 113 - .../src/components/Payments/CardPayments.tsx | 255 - .../src/components/Payments/ListPayments.tsx | 184 - .../src/components/Payments/TablePayments.tsx | 489 -- .../Payments/configurePaymentsCols.tsx | 281 -- .../Permissions/CardPermissions.tsx | 111 - .../Permissions/ListPermissions.tsx | 88 - .../Permissions/TablePermissions.tsx | 463 -- .../Permissions/configurePermissionsCols.tsx | 83 - .../CardProduct_categories.tsx | 159 - .../ListProduct_categories.tsx | 120 - .../TableProduct_categories.tsx | 476 -- .../configureProduct_categoriesCols.tsx | 151 - .../src/components/Products/CardProducts.tsx | 311 -- .../src/components/Products/ListProducts.tsx | 226 - .../src/components/Products/TableProducts.tsx | 463 -- .../Products/configureProductsCols.tsx | 339 -- frontend/src/components/RichTextField.tsx | 44 - frontend/src/components/Roles/CardRoles.tsx | 123 - frontend/src/components/Roles/ListRoles.tsx | 96 - frontend/src/components/Roles/TableRoles.tsx | 463 -- .../components/Roles/configureRolesCols.tsx | 103 - frontend/src/components/Search.tsx | 50 - frontend/src/components/SearchResults.tsx | 83 - frontend/src/components/SectionFullScreen.tsx | 27 - frontend/src/components/SectionMain.tsx | 10 - frontend/src/components/SectionTitle.tsx | 27 - .../components/SectionTitleLineWithButton.tsx | 29 - frontend/src/components/SelectField.tsx | 53 - frontend/src/components/SelectFieldMany.tsx | 67 - .../components/Shipments/CardShipments.tsx | 262 - .../components/Shipments/ListShipments.tsx | 191 - .../components/Shipments/TableShipments.tsx | 515 -- .../Shipments/configureShipmentsCols.tsx | 291 -- .../components/SmartWidget/SmartWidget.tsx | 99 - .../SmartWidget/components/AreaChart.tsx | 18 - .../components/AreaChart/ApexAreaChart.tsx | 135 - .../components/AreaChart/ChartJSAreaChart.tsx | 96 - .../SmartWidget/components/BarChart.tsx | 18 - .../components/BarChart/ApexBarChart.tsx | 131 - .../components/BarChart/ChartJSBarChart.tsx | 92 - .../SmartWidget/components/FunnelChart.tsx | 134 - .../SmartWidget/components/LineChart.tsx | 18 - .../components/LineChart/ApexLineChart.tsx | 135 - .../components/LineChart/ChartJSLineChart.tsx | 97 - .../SmartWidget/components/PieChart.tsx | 18 - .../components/PieChart/ApexPieChart.tsx | 106 - .../components/PieChart/ChartJSPieChart.tsx | 81 - .../SmartWidget/models/widget.model.ts | 35 - .../components/SmartWidget/widgetHelpers.tsx | 36 - frontend/src/components/SwitchField.tsx | 22 - .../src/components/TableSampleClients.tsx | 141 - .../src/components/Uploaders/FilesUploader.js | 150 - .../components/Uploaders/ImagesUploader.js | 237 - .../src/components/Uploaders/UploadService.js | 79 - frontend/src/components/UserAvatar.tsx | 46 - .../src/components/UserAvatarCurrentUser.tsx | 43 - frontend/src/components/UserCard.tsx | 49 - frontend/src/components/Users/CardUsers.tsx | 208 - frontend/src/components/Users/ListUsers.tsx | 155 - frontend/src/components/Users/TableUsers.tsx | 463 -- .../components/Users/configureUsersCols.tsx | 207 - .../components/WidgetCreator/RoleSelect.tsx | 53 - .../WidgetCreator/WidgetCreator.tsx | 140 - frontend/src/config.ts | 15 - frontend/src/css/_app.css | 32 - frontend/src/css/_calendar.css | 39 - frontend/src/css/_checkbox-radio-switch.css | 59 - frontend/src/css/_helper.css | 23 - frontend/src/css/_progress.css | 21 - frontend/src/css/_rich-text.css | 1 - frontend/src/css/_scrollbars.css | 41 - frontend/src/css/_select-dropdown.css | 31 - frontend/src/css/_table.css | 117 - frontend/src/css/_theme.css | 103 - frontend/src/css/main.css | 35 - frontend/src/css/tailwind/_base.css | 1 - frontend/src/css/tailwind/_components.css | 1 - frontend/src/css/tailwind/_utilities.css | 1 - frontend/src/helpers/dataFormatter.js | 195 - frontend/src/helpers/fileSaver.ts | 6 - frontend/src/helpers/humanize.ts | 11 - frontend/src/helpers/notifyStateHandler.ts | 31 - frontend/src/helpers/pexels.ts | 76 - frontend/src/helpers/userPermissions.ts | 18 - frontend/src/hooks/sampleData.ts | 22 - frontend/src/hooks/useDevCompilationStatus.ts | 44 - frontend/src/i18n.ts | 21 - frontend/src/interfaces/index.ts | 109 - frontend/src/layouts/Authenticated.tsx | 129 - frontend/src/layouts/Guest.tsx | 17 - frontend/src/menuAside.ts | 107 - frontend/src/menuNavBar.ts | 53 - frontend/src/pages/_app.tsx | 201 - frontend/src/pages/api/hello.js | 5 - frontend/src/pages/api/logError.ts | 83 - .../src/pages/customers/[customersId].tsx | 705 --- .../src/pages/customers/customers-edit.tsx | 702 --- .../src/pages/customers/customers-list.tsx | 162 - .../src/pages/customers/customers-new.tsx | 545 -- .../src/pages/customers/customers-table.tsx | 164 - .../src/pages/customers/customers-view.tsx | 641 --- frontend/src/pages/dashboard.tsx | 439 -- frontend/src/pages/error.tsx | 35 - frontend/src/pages/forgot.tsx | 82 - frontend/src/pages/forms.tsx | 142 - frontend/src/pages/index.tsx | 166 - frontend/src/pages/login.tsx | 276 - .../src/pages/order_items/[order_itemsId].tsx | 836 --- .../pages/order_items/order_items-edit.tsx | 833 --- .../pages/order_items/order_items-list.tsx | 170 - .../src/pages/order_items/order_items-new.tsx | 603 --- .../pages/order_items/order_items-table.tsx | 172 - .../pages/order_items/order_items-view.tsx | 463 -- frontend/src/pages/orders/[ordersId].tsx | 1776 ------- frontend/src/pages/orders/orders-edit.tsx | 1773 ------- frontend/src/pages/orders/orders-list.tsx | 172 - frontend/src/pages/orders/orders-new.tsx | 1329 ----- frontend/src/pages/orders/orders-table.tsx | 172 - frontend/src/pages/orders/orders-view.tsx | 1348 ----- frontend/src/pages/password-reset.tsx | 12 - frontend/src/pages/payments/[paymentsId].tsx | 1034 ---- frontend/src/pages/payments/payments-edit.tsx | 1031 ---- frontend/src/pages/payments/payments-list.tsx | 170 - frontend/src/pages/payments/payments-new.tsx | 788 --- .../src/pages/payments/payments-table.tsx | 168 - frontend/src/pages/payments/payments-view.tsx | 561 --- .../src/pages/permissions/[permissionsId].tsx | 187 - .../pages/permissions/permissions-edit.tsx | 184 - .../pages/permissions/permissions-list.tsx | 162 - .../src/pages/permissions/permissions-new.tsx | 143 - .../pages/permissions/permissions-table.tsx | 160 - .../pages/permissions/permissions-view.tsx | 127 - frontend/src/pages/privacy-policy.tsx | 292 -- .../[product_categoriesId].tsx | 472 -- .../product_categories-edit.tsx | 469 -- .../product_categories-list.tsx | 170 - .../product_categories-new.tsx | 340 -- .../product_categories-table.tsx | 168 - .../product_categories-view.tsx | 448 -- frontend/src/pages/products/[productsId].tsx | 1205 ----- frontend/src/pages/products/products-edit.tsx | 1202 ----- frontend/src/pages/products/products-list.tsx | 166 - frontend/src/pages/products/products-new.tsx | 920 ---- .../src/pages/products/products-table.tsx | 168 - frontend/src/pages/products/products-view.tsx | 768 --- frontend/src/pages/profile.tsx | 180 - frontend/src/pages/register.tsx | 92 - frontend/src/pages/roles/[rolesId].tsx | 276 - frontend/src/pages/roles/roles-edit.tsx | 273 - frontend/src/pages/roles/roles-list.tsx | 162 - frontend/src/pages/roles/roles-new.tsx | 195 - frontend/src/pages/roles/roles-table.tsx | 160 - frontend/src/pages/roles/roles-view.tsx | 304 -- frontend/src/pages/search.tsx | 91 - .../src/pages/shipments/[shipmentsId].tsx | 1032 ---- .../src/pages/shipments/shipments-edit.tsx | 1029 ---- .../src/pages/shipments/shipments-list.tsx | 168 - .../src/pages/shipments/shipments-new.tsx | 774 --- .../src/pages/shipments/shipments-table.tsx | 168 - .../src/pages/shipments/shipments-view.tsx | 571 --- frontend/src/pages/tables.tsx | 33 - frontend/src/pages/terms-of-use.tsx | 206 - frontend/src/pages/users/[usersId].tsx | 710 --- frontend/src/pages/users/users-edit.tsx | 707 --- frontend/src/pages/users/users-list.tsx | 166 - frontend/src/pages/users/users-new.tsx | 502 -- frontend/src/pages/users/users-table.tsx | 164 - frontend/src/pages/users/users-view.tsx | 691 --- frontend/src/pages/verify-email.tsx | 62 - frontend/src/stores/authSlice.ts | 124 - .../src/stores/customers/customersSlice.ts | 231 - frontend/src/stores/hooks.ts | 6 - frontend/src/stores/introSteps.ts | 139 - frontend/src/stores/mainSlice.ts | 36 - frontend/src/stores/openAiSlice.ts | 151 - .../stores/order_items/order_itemsSlice.ts | 231 - frontend/src/stores/orders/ordersSlice.ts | 231 - frontend/src/stores/payments/paymentsSlice.ts | 231 - .../stores/permissions/permissionsSlice.ts | 231 - .../product_categoriesSlice.ts | 231 - frontend/src/stores/products/productsSlice.ts | 231 - frontend/src/stores/roles/rolesSlice.ts | 280 -- .../src/stores/shipments/shipmentsSlice.ts | 231 - frontend/src/stores/store.ts | 41 - frontend/src/stores/styleSlice.ts | 103 - frontend/src/stores/users/usersSlice.ts | 231 - frontend/src/stores/usersSlice.ts | 117 - frontend/src/styles.ts | 107 - frontend/tailwind.config.js | 110 - frontend/tsconfig.json | 30 - frontend/yarn.lock | 3608 ------------- nginx.conf | 96 - package.json | 8 - webT | 1 + 374 files changed, 1 insertion(+), 91380 deletions(-) delete mode 100644 502.html delete mode 100644 Dockerfile delete mode 100644 Dockerfile.dev delete mode 100644 LICENSE delete mode 100644 README.md delete mode 100644 backend/.env delete mode 100644 backend/.eslintignore delete mode 100644 backend/.eslintrc.cjs delete mode 100644 backend/.prettierrc delete mode 100644 backend/.sequelizerc delete mode 100644 backend/Dockerfile delete mode 100644 backend/README.md delete mode 100644 backend/package.json delete mode 100644 backend/src/ai/LocalAIApi.js delete mode 100644 backend/src/auth/auth.js delete mode 100644 backend/src/config.js delete mode 100644 backend/src/db/api/customers.js delete mode 100644 backend/src/db/api/file.js delete mode 100644 backend/src/db/api/order_items.js delete mode 100644 backend/src/db/api/orders.js delete mode 100644 backend/src/db/api/payments.js delete mode 100644 backend/src/db/api/permissions.js delete mode 100644 backend/src/db/api/product_categories.js delete mode 100644 backend/src/db/api/products.js delete mode 100644 backend/src/db/api/roles.js delete mode 100644 backend/src/db/api/shipments.js delete mode 100644 backend/src/db/api/users.js delete mode 100644 backend/src/db/db.config.js delete mode 100644 backend/src/db/migrations/1777487463402.js delete mode 100644 backend/src/db/migrations/20260316000000-create-files.js delete mode 100644 backend/src/db/migrations/20260316001000-create-users-custom-permissions-join-table.js delete mode 100644 backend/src/db/models/customers.js delete mode 100644 backend/src/db/models/file.js delete mode 100644 backend/src/db/models/index.js delete mode 100644 backend/src/db/models/order_items.js delete mode 100644 backend/src/db/models/orders.js delete mode 100644 backend/src/db/models/payments.js delete mode 100644 backend/src/db/models/permissions.js delete mode 100644 backend/src/db/models/product_categories.js delete mode 100644 backend/src/db/models/products.js delete mode 100644 backend/src/db/models/roles.js delete mode 100644 backend/src/db/models/shipments.js delete mode 100644 backend/src/db/models/users.js delete mode 100644 backend/src/db/reset.js delete mode 100644 backend/src/db/seeders/20200430130759-admin-user.js delete mode 100644 backend/src/db/seeders/20200430130760-user-roles.js delete mode 100644 backend/src/db/seeders/20231127130745-sample-data.js delete mode 100644 backend/src/db/utils.js delete mode 100644 backend/src/helpers.js delete mode 100644 backend/src/index.js delete mode 100644 backend/src/middlewares/check-permissions.js delete mode 100644 backend/src/middlewares/upload.js delete mode 100644 backend/src/routes/auth.js delete mode 100644 backend/src/routes/contactForm.js delete mode 100644 backend/src/routes/customers.js delete mode 100644 backend/src/routes/file.js delete mode 100644 backend/src/routes/openai.js delete mode 100644 backend/src/routes/order_items.js delete mode 100644 backend/src/routes/orders.js delete mode 100644 backend/src/routes/organizationLogin.js delete mode 100644 backend/src/routes/payments.js delete mode 100644 backend/src/routes/permissions.js delete mode 100644 backend/src/routes/pexels.js delete mode 100644 backend/src/routes/product_categories.js delete mode 100644 backend/src/routes/products.js delete mode 100644 backend/src/routes/roles.js delete mode 100644 backend/src/routes/search.js delete mode 100644 backend/src/routes/shipments.js delete mode 100644 backend/src/routes/sql.js delete mode 100644 backend/src/routes/users.js delete mode 100644 backend/src/services/auth.js delete mode 100644 backend/src/services/customers.js delete mode 100644 backend/src/services/email/htmlTemplates/addressVerification/emailAddressVerification.html delete mode 100644 backend/src/services/email/htmlTemplates/invitation/invitationTemplate.html delete mode 100644 backend/src/services/email/htmlTemplates/passwordReset/passwordResetEmail.html delete mode 100644 backend/src/services/email/index.js delete mode 100644 backend/src/services/email/list/addressVerification.js delete mode 100644 backend/src/services/email/list/invitation.js delete mode 100644 backend/src/services/email/list/passwordReset.js delete mode 100644 backend/src/services/file.js delete mode 100644 backend/src/services/notifications/errors/forbidden.js delete mode 100644 backend/src/services/notifications/errors/validation.js delete mode 100644 backend/src/services/notifications/helpers.js delete mode 100644 backend/src/services/notifications/list.js delete mode 100644 backend/src/services/openai.js delete mode 100644 backend/src/services/order_items.js delete mode 100644 backend/src/services/orders.js delete mode 100644 backend/src/services/payments.js delete mode 100644 backend/src/services/permissions.js delete mode 100644 backend/src/services/product_categories.js delete mode 100644 backend/src/services/products.js delete mode 100644 backend/src/services/roles.js delete mode 100644 backend/src/services/search.js delete mode 100644 backend/src/services/shipments.js delete mode 100644 backend/src/services/users.js delete mode 100644 backend/watcher.js delete mode 100644 backend/yarn.lock delete mode 100644 docker/.gitignore delete mode 100644 docker/README.md delete mode 100644 docker/docker-compose.yml delete mode 100644 docker/start-backend.sh delete mode 100644 docker/wait-for-it.sh delete mode 100644 frontend/.eslintignore delete mode 100644 frontend/.eslintrc.cjs delete mode 100644 frontend/.gitignore delete mode 100644 frontend/.prettierrc delete mode 100644 frontend/Dockerfile delete mode 100644 frontend/LICENSE-justboil delete mode 100644 frontend/README.md delete mode 100644 frontend/next-env.d.ts delete mode 100644 frontend/next.config.mjs delete mode 100644 frontend/package.json delete mode 100644 frontend/postcss.config.js delete mode 100644 frontend/prettier.config.js delete mode 100644 frontend/public/data-sources/clients.json delete mode 100644 frontend/public/data-sources/history.json delete mode 100644 frontend/public/favicon.svg delete mode 100644 frontend/public/locales/de/common.json delete mode 100644 frontend/public/locales/en/common.json delete mode 100644 frontend/public/locales/es/common.json delete mode 100644 frontend/public/locales/fr/common.json delete mode 100644 frontend/src/colors.ts delete mode 100644 frontend/src/components/AsideMenu.tsx delete mode 100644 frontend/src/components/AsideMenuItem.tsx delete mode 100644 frontend/src/components/AsideMenuLayer.tsx delete mode 100644 frontend/src/components/AsideMenuList.tsx delete mode 100644 frontend/src/components/BaseButton.tsx delete mode 100644 frontend/src/components/BaseButtons.tsx delete mode 100644 frontend/src/components/BaseDivider.tsx delete mode 100644 frontend/src/components/BaseIcon.tsx delete mode 100644 frontend/src/components/BigCalendar.tsx delete mode 100644 frontend/src/components/CardBox.tsx delete mode 100644 frontend/src/components/CardBoxComponentBody.tsx delete mode 100644 frontend/src/components/CardBoxComponentEmpty.tsx delete mode 100644 frontend/src/components/CardBoxComponentFooter.tsx delete mode 100644 frontend/src/components/CardBoxComponentTitle.tsx delete mode 100644 frontend/src/components/CardBoxModal.tsx delete mode 100644 frontend/src/components/ChartLineSample/config.ts delete mode 100644 frontend/src/components/ChartLineSample/index.tsx delete mode 100644 frontend/src/components/ClickOutside.tsx delete mode 100644 frontend/src/components/Customers/CardCustomers.tsx delete mode 100644 frontend/src/components/Customers/ListCustomers.tsx delete mode 100644 frontend/src/components/Customers/TableCustomers.tsx delete mode 100644 frontend/src/components/Customers/configureCustomersCols.tsx delete mode 100644 frontend/src/components/DataGridMultiSelect.tsx delete mode 100644 frontend/src/components/DevModeBadge.tsx delete mode 100644 frontend/src/components/DragDropFilePicker.tsx delete mode 100644 frontend/src/components/ErrorBoundary.tsx delete mode 100644 frontend/src/components/FooterBar.tsx delete mode 100644 frontend/src/components/FormCheckRadio.tsx delete mode 100644 frontend/src/components/FormCheckRadioGroup.tsx delete mode 100644 frontend/src/components/FormField.tsx delete mode 100644 frontend/src/components/FormFilePicker.tsx delete mode 100644 frontend/src/components/FormImagePicker.tsx delete mode 100644 frontend/src/components/IconRounded.tsx delete mode 100644 frontend/src/components/ImageField.tsx delete mode 100644 frontend/src/components/IntroGuide.tsx delete mode 100644 frontend/src/components/KanbanBoard/KanbanBoard.tsx delete mode 100644 frontend/src/components/KanbanBoard/KanbanCard.tsx delete mode 100644 frontend/src/components/KanbanBoard/KanbanColumn.tsx delete mode 100644 frontend/src/components/LanguageSwitcher.tsx delete mode 100644 frontend/src/components/ListActionsPopover.tsx delete mode 100644 frontend/src/components/LoadingSpinner.tsx delete mode 100644 frontend/src/components/Logo/index.tsx delete mode 100644 frontend/src/components/NavBar.tsx delete mode 100644 frontend/src/components/NavBarItem.tsx delete mode 100644 frontend/src/components/NavBarItemPlain.tsx delete mode 100644 frontend/src/components/NavBarMenuList.tsx delete mode 100644 frontend/src/components/NotificationBar.tsx delete mode 100644 frontend/src/components/Order_items/CardOrder_items.tsx delete mode 100644 frontend/src/components/Order_items/ListOrder_items.tsx delete mode 100644 frontend/src/components/Order_items/TableOrder_items.tsx delete mode 100644 frontend/src/components/Order_items/configureOrder_itemsCols.tsx delete mode 100644 frontend/src/components/Orders/CardOrders.tsx delete mode 100644 frontend/src/components/Orders/ListOrders.tsx delete mode 100644 frontend/src/components/Orders/TableOrders.tsx delete mode 100644 frontend/src/components/Orders/configureOrdersCols.tsx delete mode 100644 frontend/src/components/OverlayLayer.tsx delete mode 100644 frontend/src/components/Pagination.tsx delete mode 100644 frontend/src/components/PasswordSetOrReset.tsx delete mode 100644 frontend/src/components/Payments/CardPayments.tsx delete mode 100644 frontend/src/components/Payments/ListPayments.tsx delete mode 100644 frontend/src/components/Payments/TablePayments.tsx delete mode 100644 frontend/src/components/Payments/configurePaymentsCols.tsx delete mode 100644 frontend/src/components/Permissions/CardPermissions.tsx delete mode 100644 frontend/src/components/Permissions/ListPermissions.tsx delete mode 100644 frontend/src/components/Permissions/TablePermissions.tsx delete mode 100644 frontend/src/components/Permissions/configurePermissionsCols.tsx delete mode 100644 frontend/src/components/Product_categories/CardProduct_categories.tsx delete mode 100644 frontend/src/components/Product_categories/ListProduct_categories.tsx delete mode 100644 frontend/src/components/Product_categories/TableProduct_categories.tsx delete mode 100644 frontend/src/components/Product_categories/configureProduct_categoriesCols.tsx delete mode 100644 frontend/src/components/Products/CardProducts.tsx delete mode 100644 frontend/src/components/Products/ListProducts.tsx delete mode 100644 frontend/src/components/Products/TableProducts.tsx delete mode 100644 frontend/src/components/Products/configureProductsCols.tsx delete mode 100644 frontend/src/components/RichTextField.tsx delete mode 100644 frontend/src/components/Roles/CardRoles.tsx delete mode 100644 frontend/src/components/Roles/ListRoles.tsx delete mode 100644 frontend/src/components/Roles/TableRoles.tsx delete mode 100644 frontend/src/components/Roles/configureRolesCols.tsx delete mode 100644 frontend/src/components/Search.tsx delete mode 100644 frontend/src/components/SearchResults.tsx delete mode 100644 frontend/src/components/SectionFullScreen.tsx delete mode 100644 frontend/src/components/SectionMain.tsx delete mode 100644 frontend/src/components/SectionTitle.tsx delete mode 100644 frontend/src/components/SectionTitleLineWithButton.tsx delete mode 100644 frontend/src/components/SelectField.tsx delete mode 100644 frontend/src/components/SelectFieldMany.tsx delete mode 100644 frontend/src/components/Shipments/CardShipments.tsx delete mode 100644 frontend/src/components/Shipments/ListShipments.tsx delete mode 100644 frontend/src/components/Shipments/TableShipments.tsx delete mode 100644 frontend/src/components/Shipments/configureShipmentsCols.tsx delete mode 100644 frontend/src/components/SmartWidget/SmartWidget.tsx delete mode 100644 frontend/src/components/SmartWidget/components/AreaChart.tsx delete mode 100644 frontend/src/components/SmartWidget/components/AreaChart/ApexAreaChart.tsx delete mode 100644 frontend/src/components/SmartWidget/components/AreaChart/ChartJSAreaChart.tsx delete mode 100644 frontend/src/components/SmartWidget/components/BarChart.tsx delete mode 100644 frontend/src/components/SmartWidget/components/BarChart/ApexBarChart.tsx delete mode 100644 frontend/src/components/SmartWidget/components/BarChart/ChartJSBarChart.tsx delete mode 100644 frontend/src/components/SmartWidget/components/FunnelChart.tsx delete mode 100644 frontend/src/components/SmartWidget/components/LineChart.tsx delete mode 100644 frontend/src/components/SmartWidget/components/LineChart/ApexLineChart.tsx delete mode 100644 frontend/src/components/SmartWidget/components/LineChart/ChartJSLineChart.tsx delete mode 100644 frontend/src/components/SmartWidget/components/PieChart.tsx delete mode 100644 frontend/src/components/SmartWidget/components/PieChart/ApexPieChart.tsx delete mode 100644 frontend/src/components/SmartWidget/components/PieChart/ChartJSPieChart.tsx delete mode 100644 frontend/src/components/SmartWidget/models/widget.model.ts delete mode 100644 frontend/src/components/SmartWidget/widgetHelpers.tsx delete mode 100644 frontend/src/components/SwitchField.tsx delete mode 100644 frontend/src/components/TableSampleClients.tsx delete mode 100644 frontend/src/components/Uploaders/FilesUploader.js delete mode 100644 frontend/src/components/Uploaders/ImagesUploader.js delete mode 100644 frontend/src/components/Uploaders/UploadService.js delete mode 100644 frontend/src/components/UserAvatar.tsx delete mode 100644 frontend/src/components/UserAvatarCurrentUser.tsx delete mode 100644 frontend/src/components/UserCard.tsx delete mode 100644 frontend/src/components/Users/CardUsers.tsx delete mode 100644 frontend/src/components/Users/ListUsers.tsx delete mode 100644 frontend/src/components/Users/TableUsers.tsx delete mode 100644 frontend/src/components/Users/configureUsersCols.tsx delete mode 100644 frontend/src/components/WidgetCreator/RoleSelect.tsx delete mode 100644 frontend/src/components/WidgetCreator/WidgetCreator.tsx delete mode 100644 frontend/src/config.ts delete mode 100644 frontend/src/css/_app.css delete mode 100644 frontend/src/css/_calendar.css delete mode 100644 frontend/src/css/_checkbox-radio-switch.css delete mode 100644 frontend/src/css/_helper.css delete mode 100644 frontend/src/css/_progress.css delete mode 100644 frontend/src/css/_rich-text.css delete mode 100644 frontend/src/css/_scrollbars.css delete mode 100644 frontend/src/css/_select-dropdown.css delete mode 100644 frontend/src/css/_table.css delete mode 100644 frontend/src/css/_theme.css delete mode 100644 frontend/src/css/main.css delete mode 100644 frontend/src/css/tailwind/_base.css delete mode 100644 frontend/src/css/tailwind/_components.css delete mode 100644 frontend/src/css/tailwind/_utilities.css delete mode 100644 frontend/src/helpers/dataFormatter.js delete mode 100644 frontend/src/helpers/fileSaver.ts delete mode 100644 frontend/src/helpers/humanize.ts delete mode 100644 frontend/src/helpers/notifyStateHandler.ts delete mode 100644 frontend/src/helpers/pexels.ts delete mode 100644 frontend/src/helpers/userPermissions.ts delete mode 100644 frontend/src/hooks/sampleData.ts delete mode 100644 frontend/src/hooks/useDevCompilationStatus.ts delete mode 100644 frontend/src/i18n.ts delete mode 100644 frontend/src/interfaces/index.ts delete mode 100644 frontend/src/layouts/Authenticated.tsx delete mode 100644 frontend/src/layouts/Guest.tsx delete mode 100644 frontend/src/menuAside.ts delete mode 100644 frontend/src/menuNavBar.ts delete mode 100644 frontend/src/pages/_app.tsx delete mode 100644 frontend/src/pages/api/hello.js delete mode 100644 frontend/src/pages/api/logError.ts delete mode 100644 frontend/src/pages/customers/[customersId].tsx delete mode 100644 frontend/src/pages/customers/customers-edit.tsx delete mode 100644 frontend/src/pages/customers/customers-list.tsx delete mode 100644 frontend/src/pages/customers/customers-new.tsx delete mode 100644 frontend/src/pages/customers/customers-table.tsx delete mode 100644 frontend/src/pages/customers/customers-view.tsx delete mode 100644 frontend/src/pages/dashboard.tsx delete mode 100644 frontend/src/pages/error.tsx delete mode 100644 frontend/src/pages/forgot.tsx delete mode 100644 frontend/src/pages/forms.tsx delete mode 100644 frontend/src/pages/index.tsx delete mode 100644 frontend/src/pages/login.tsx delete mode 100644 frontend/src/pages/order_items/[order_itemsId].tsx delete mode 100644 frontend/src/pages/order_items/order_items-edit.tsx delete mode 100644 frontend/src/pages/order_items/order_items-list.tsx delete mode 100644 frontend/src/pages/order_items/order_items-new.tsx delete mode 100644 frontend/src/pages/order_items/order_items-table.tsx delete mode 100644 frontend/src/pages/order_items/order_items-view.tsx delete mode 100644 frontend/src/pages/orders/[ordersId].tsx delete mode 100644 frontend/src/pages/orders/orders-edit.tsx delete mode 100644 frontend/src/pages/orders/orders-list.tsx delete mode 100644 frontend/src/pages/orders/orders-new.tsx delete mode 100644 frontend/src/pages/orders/orders-table.tsx delete mode 100644 frontend/src/pages/orders/orders-view.tsx delete mode 100644 frontend/src/pages/password-reset.tsx delete mode 100644 frontend/src/pages/payments/[paymentsId].tsx delete mode 100644 frontend/src/pages/payments/payments-edit.tsx delete mode 100644 frontend/src/pages/payments/payments-list.tsx delete mode 100644 frontend/src/pages/payments/payments-new.tsx delete mode 100644 frontend/src/pages/payments/payments-table.tsx delete mode 100644 frontend/src/pages/payments/payments-view.tsx delete mode 100644 frontend/src/pages/permissions/[permissionsId].tsx delete mode 100644 frontend/src/pages/permissions/permissions-edit.tsx delete mode 100644 frontend/src/pages/permissions/permissions-list.tsx delete mode 100644 frontend/src/pages/permissions/permissions-new.tsx delete mode 100644 frontend/src/pages/permissions/permissions-table.tsx delete mode 100644 frontend/src/pages/permissions/permissions-view.tsx delete mode 100644 frontend/src/pages/privacy-policy.tsx delete mode 100644 frontend/src/pages/product_categories/[product_categoriesId].tsx delete mode 100644 frontend/src/pages/product_categories/product_categories-edit.tsx delete mode 100644 frontend/src/pages/product_categories/product_categories-list.tsx delete mode 100644 frontend/src/pages/product_categories/product_categories-new.tsx delete mode 100644 frontend/src/pages/product_categories/product_categories-table.tsx delete mode 100644 frontend/src/pages/product_categories/product_categories-view.tsx delete mode 100644 frontend/src/pages/products/[productsId].tsx delete mode 100644 frontend/src/pages/products/products-edit.tsx delete mode 100644 frontend/src/pages/products/products-list.tsx delete mode 100644 frontend/src/pages/products/products-new.tsx delete mode 100644 frontend/src/pages/products/products-table.tsx delete mode 100644 frontend/src/pages/products/products-view.tsx delete mode 100644 frontend/src/pages/profile.tsx delete mode 100644 frontend/src/pages/register.tsx delete mode 100644 frontend/src/pages/roles/[rolesId].tsx delete mode 100644 frontend/src/pages/roles/roles-edit.tsx delete mode 100644 frontend/src/pages/roles/roles-list.tsx delete mode 100644 frontend/src/pages/roles/roles-new.tsx delete mode 100644 frontend/src/pages/roles/roles-table.tsx delete mode 100644 frontend/src/pages/roles/roles-view.tsx delete mode 100644 frontend/src/pages/search.tsx delete mode 100644 frontend/src/pages/shipments/[shipmentsId].tsx delete mode 100644 frontend/src/pages/shipments/shipments-edit.tsx delete mode 100644 frontend/src/pages/shipments/shipments-list.tsx delete mode 100644 frontend/src/pages/shipments/shipments-new.tsx delete mode 100644 frontend/src/pages/shipments/shipments-table.tsx delete mode 100644 frontend/src/pages/shipments/shipments-view.tsx delete mode 100644 frontend/src/pages/tables.tsx delete mode 100644 frontend/src/pages/terms-of-use.tsx delete mode 100644 frontend/src/pages/users/[usersId].tsx delete mode 100644 frontend/src/pages/users/users-edit.tsx delete mode 100644 frontend/src/pages/users/users-list.tsx delete mode 100644 frontend/src/pages/users/users-new.tsx delete mode 100644 frontend/src/pages/users/users-table.tsx delete mode 100644 frontend/src/pages/users/users-view.tsx delete mode 100644 frontend/src/pages/verify-email.tsx delete mode 100644 frontend/src/stores/authSlice.ts delete mode 100644 frontend/src/stores/customers/customersSlice.ts delete mode 100644 frontend/src/stores/hooks.ts delete mode 100644 frontend/src/stores/introSteps.ts delete mode 100644 frontend/src/stores/mainSlice.ts delete mode 100644 frontend/src/stores/openAiSlice.ts delete mode 100644 frontend/src/stores/order_items/order_itemsSlice.ts delete mode 100644 frontend/src/stores/orders/ordersSlice.ts delete mode 100644 frontend/src/stores/payments/paymentsSlice.ts delete mode 100644 frontend/src/stores/permissions/permissionsSlice.ts delete mode 100644 frontend/src/stores/product_categories/product_categoriesSlice.ts delete mode 100644 frontend/src/stores/products/productsSlice.ts delete mode 100644 frontend/src/stores/roles/rolesSlice.ts delete mode 100644 frontend/src/stores/shipments/shipmentsSlice.ts delete mode 100644 frontend/src/stores/store.ts delete mode 100644 frontend/src/stores/styleSlice.ts delete mode 100644 frontend/src/stores/users/usersSlice.ts delete mode 100644 frontend/src/stores/usersSlice.ts delete mode 100644 frontend/src/styles.ts delete mode 100644 frontend/tailwind.config.js delete mode 100644 frontend/tsconfig.json delete mode 100644 frontend/yarn.lock delete mode 100644 nginx.conf delete mode 100644 package.json create mode 160000 webT diff --git a/502.html b/502.html deleted file mode 100644 index d7c0448..0000000 --- a/502.html +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - Service Starting - - - - -
-

Loading the app, just a moment…

-

The application is currently launching. The page will automatically refresh once site is - available.

-
-

Store Operations Hub

-

Back-office hub to manage products, customers, orders, fulfillment, and payments in one dashboard.

-
-
- -
-
-
- -
-
- - - - \ No newline at end of file diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 970d54f..0000000 --- a/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -FROM node:20.15.1-alpine AS builder -RUN apk add --no-cache git -WORKDIR /app -COPY frontend/package.json frontend/yarn.lock ./ -RUN yarn install --pure-lockfile -COPY frontend . -RUN yarn build - - - -FROM node:20.15.1-alpine -WORKDIR /app -COPY backend/package.json backend/yarn.lock ./ -RUN yarn install --pure-lockfile -COPY backend . - -COPY --from=builder /app/build /app/public -CMD ["yarn", "start"] - - - diff --git a/Dockerfile.dev b/Dockerfile.dev deleted file mode 100644 index a8353d5..0000000 --- a/Dockerfile.dev +++ /dev/null @@ -1,85 +0,0 @@ -# Base image for Node.js dependencies -FROM node:20.15.1-alpine AS frontend-deps -RUN apk add --no-cache git -WORKDIR /app/frontend -COPY frontend/package.json frontend/yarn.lock ./ -RUN yarn install --pure-lockfile - -FROM node:20.15.1-alpine AS backend-deps -RUN apk add --no-cache git -WORKDIR /app/backend -COPY backend/package.json backend/yarn.lock ./ -RUN yarn install --pure-lockfile - -FROM node:20.15.1-alpine AS app-shell-deps -RUN apk add --no-cache git -WORKDIR /app/app-shell -COPY app-shell/package.json app-shell/yarn.lock ./ -RUN yarn install --pure-lockfile - -# Nginx setup and application build -FROM node:20.15.1-alpine AS build -RUN apk add --no-cache git nginx curl -RUN apk add --no-cache lsof procps -RUN yarn global add concurrently - -RUN apk add --no-cache \ - chromium \ - nss \ - freetype \ - harfbuzz \ - ttf-freefont \ - fontconfig - -ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true -ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser - -RUN mkdir -p /app/pids - -# Make sure to add yarn global bin to PATH -ENV PATH /root/.yarn/bin:/root/.config/yarn/global/node_modules/.bin:$PATH - -# Copy dependencies -WORKDIR /app -COPY --from=frontend-deps /app/frontend /app/frontend -COPY --from=backend-deps /app/backend /app/backend -COPY --from=app-shell-deps /app/app-shell /app/app-shell - -COPY frontend /app/frontend -COPY backend /app/backend -COPY app-shell /app/app-shell -COPY docker /app/docker - -# Copy all files from root to /app -COPY . /app - -# Copy Nginx configuration -COPY nginx.conf /etc/nginx/nginx.conf - -# Copy custom error page -COPY 502.html /usr/share/nginx/html/502.html - -# Change owner and permissions of the error page -RUN chown nginx:nginx /usr/share/nginx/html/502.html && \ - chmod 644 /usr/share/nginx/html/502.html - -# Expose the port the app runs on -EXPOSE 8080 -ENV NODE_ENV=dev_stage -ENV FRONT_PORT=3001 -ENV BACKEND_PORT=3000 -ENV APP_SHELL_PORT=4000 - - -CMD ["sh", "-c", "\ - yarn --cwd /app/frontend dev & echo $! > /app/pids/frontend.pid && \ - yarn --cwd /app/backend start & echo $! > /app/pids/backend.pid && \ - sleep 10 && nginx -g 'daemon off;' & \ - NGINX_PID=$! && \ - echo 'Waiting for backend (port 3000) to be available...' && \ - while ! nc -z localhost ${BACKEND_PORT}; do \ - sleep 2; \ - done && \ - echo 'Backend is up. Starting app_shell for Git check...' && \ - yarn --cwd /app/app-shell start && \ - wait $NGINX_PID"] \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 5d69ed7..0000000 --- a/LICENSE +++ /dev/null @@ -1 +0,0 @@ -https://flatlogic.com/ diff --git a/README.md b/README.md deleted file mode 100644 index 7787039..0000000 --- a/README.md +++ /dev/null @@ -1,244 +0,0 @@ - - -# Store Operations Hub - - -## This project was generated by [Flatlogic Platform](https://flatlogic.com). - - - - Frontend: [React.js](https://flatlogic.com/templates?framework%5B%5D=react&sort=default) - - - - - - - - - - - - - Backend: [NodeJS](https://flatlogic.com/templates?backend%5B%5D=nodejs&sort=default) - -
Backend Folder Structure - - The generated application has the following backend folder structure: - - `src` folder which contains your working files that will be used later to create the build. The src folder contains folders as: - - - `auth` - config the library for authentication and authorization; - - - `db` - contains such folders as: - - - `api` - documentation that is automatically generated by jsdoc or other tools; - - - `migrations` - is a skeleton of the database or all the actions that users do with the database; - - - `models`- what will represent the database for the backend; - - - `seeders` - the entity that creates the data for the database. - - - `routes` - this folder would contain all the routes that you have created using Express Router and what they do would be exported from a Controller file; - - - `services` - contains such folders as `emails` and `notifications`. -
- - - - - - - - - - - - Database: PostgreSQL - - - - app-shel: Core application framework that provides essential infrastructure services -for the entire application. - ----------------------- -### We offer 2 ways how to start the project locally: by running Frontend and Backend or with Docker. ------------------------ - -## To start the project: - -### Backend: - -> Please change current folder: `cd backend` - - - -#### Install local dependencies: -`yarn install` - - ------------ - -#### Adjust local db: -##### 1. Install postgres: - -MacOS: - -`brew install postgres` - - > if you don’t have ‘brew‘ please install it (https://brew.sh) and repeat step `brew install postgres`. - -Ubuntu: - -`sudo apt update` - -`sudo apt install postgresql postgresql-contrib` - -##### 2. Create db and admin user: -Before run and test connection, make sure you have created a database as described in the above configuration. You can use the `psql` command to create a user and database. - -`psql postgres --u postgres` - -Next, type this command for creating a new user with password then give access for creating the database. - -`postgres-# CREATE ROLE admin WITH LOGIN PASSWORD 'admin_pass';` - -`postgres-# ALTER ROLE admin CREATEDB;` - -Quit `psql` then log in again using the new user that previously created. - -`postgres-# \q` - -`psql postgres -U admin` - -Type this command to creating a new database. - -`postgres=> CREATE DATABASE db_{your_project_name};` - -Then give that new user privileges to the new database then quit the `psql`. - -`postgres=> GRANT ALL PRIVILEGES ON DATABASE db_{your_project_name} TO admin;` - -`postgres=> \q` - - - - - - ------------ - - -#### Create database: -`yarn db:create` - -#### Start production build: -`yarn start` - - - - - -### Frontend: - -> Please change current folder: `cd frontend` - - - - - - - - - - - - -## To start the project with Docker: -### Description: - -The project contains the **docker folder** and the `Dockerfile`. - -The `Dockerfile` is used to Deploy the project to Google Cloud. - -The **docker folder** contains a couple of helper scripts: - -- `docker-compose.yml` (all our services: web, backend, db are described here) -- `start-backend.sh` (starts backend, but only after the database) -- `wait-for-it.sh` (imported from https://github.com/vishnubob/wait-for-it) - - > To avoid breaking the application, we recommend you don't edit the following files: everything that includes the **docker folder** and `Dokerfile`. - -## Run services: - -1. Install docker compose (https://docs.docker.com/compose/install/) - -2. Move to `docker` folder. All next steps should be done from this folder. - - ``` cd docker ``` - -3. Make executables from `wait-for-it.sh` and `start-backend.sh`: - - ``` chmod +x start-backend.sh && chmod +x wait-for-it.sh ``` - -4. Download dependend projects for services. - -5. Review the docker-compose.yml file. Make sure that all services have Dockerfiles. Only db service doesn't require a Dockerfile. - -6. Make sure you have needed ports (see them in `ports`) available on your local machine. - -7. Start services: - - 7.1. With an empty database `rm -rf data && docker-compose up` - - 7.2. With a stored (from previus runs) database data `docker-compose up` - -8. Check http://localhost:3000 - -9. Stop services: - - 9.1. Just press `Ctr+C` - -## Most common errors: - -1. `connection refused` - - There could be many reasons, but the most common are: - - - The port is not open on the destination machine. - - - The port is open on the destination machine, but its backlog of pending connections is full. - - - A firewall between the client and server is blocking access (also check local firewalls). - - After checking for firewalls and that the port is open, use telnet to connect to the IP/port to test connectivity. This removes any potential issues from your application. - - ***MacOS:*** - - If you suspect that your SSH service might be down, you can run this command to find out: - - `sudo service ssh status` - - If the command line returns a status of down, then you’ve likely found the reason behind your connectivity error. - - ***Ubuntu:*** - - Sometimes a connection refused error can also indicate that there is an IP address conflict on your network. You can search for possible IP conflicts by running: - - `arp-scan -I eth0 -l | grep ` - - `arp-scan -I eth0 -l | grep ` - - and - - `arping ` - -2. `yarn db:create` creates database with the assembled tables (on MacOS with Postgres database) - - The workaround - put the next commands to your Postgres database terminal: - - `DROP SCHEMA public CASCADE;` - - `CREATE SCHEMA public;` - - `GRANT ALL ON SCHEMA public TO postgres;` - - `GRANT ALL ON SCHEMA public TO public;` - - Afterwards, continue to start your project in the backend directory by running: - - `yarn start` \ No newline at end of file diff --git a/backend/.env b/backend/.env deleted file mode 100644 index 25241b7..0000000 --- a/backend/.env +++ /dev/null @@ -1 +0,0 @@ -PORT=8080 diff --git a/backend/.eslintignore b/backend/.eslintignore deleted file mode 100644 index 3fabb75..0000000 --- a/backend/.eslintignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore generated and runtime files -node_modules/ -tmp/ -logs/ diff --git a/backend/.eslintrc.cjs b/backend/.eslintrc.cjs deleted file mode 100644 index f312476..0000000 --- a/backend/.eslintrc.cjs +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - env: { - node: true, - es2021: true - }, - extends: [ - 'eslint:recommended' - ], - plugins: [ - 'import' - ], - rules: { - 'import/no-unresolved': 'error' - } -}; diff --git a/backend/.prettierrc b/backend/.prettierrc deleted file mode 100644 index bb087f2..0000000 --- a/backend/.prettierrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "singleQuote": true, - "tabWidth": 2, - "printWidth": 80, - "trailingComma": "all", - "quoteProps": "as-needed", - "jsxSingleQuote": true, - "bracketSpacing": true, - "bracketSameLine": false, - "arrowParens": "always" -} diff --git a/backend/.sequelizerc b/backend/.sequelizerc deleted file mode 100644 index fe89188..0000000 --- a/backend/.sequelizerc +++ /dev/null @@ -1,7 +0,0 @@ -const path = require('path'); -module.exports = { - "config": path.resolve("src", "db", "db.config.js"), - "models-path": path.resolve("src", "db", "models"), - "seeders-path": path.resolve("src", "db", "seeders"), - "migrations-path": path.resolve("src", "db", "migrations") -}; \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile deleted file mode 100644 index 581cb98..0000000 --- a/backend/Dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -FROM node:20.15.1-alpine - -RUN apk update && apk add bash -# Create app directory -WORKDIR /usr/src/app - -# Install app dependencies -# A wildcard is used to ensure both package.json AND package-lock.json are copied -# where available (npm@5+) -COPY package*.json ./ - -RUN yarn install -# If you are building your code for production -# RUN npm ci --only=production - - -# Bundle app source -COPY . . - - -EXPOSE 8080 - -CMD [ "yarn", "start" ] diff --git a/backend/README.md b/backend/README.md deleted file mode 100644 index 7ab62af..0000000 --- a/backend/README.md +++ /dev/null @@ -1,56 +0,0 @@ - -#Store Operations Hub - template backend, - -#### Run App on local machine: - -##### Install local dependencies: -- `yarn install` - ------------- - -##### Adjust local db: -###### 1. Install postgres: - - MacOS: - - `brew install postgres` - -- Ubuntu: - - `sudo apt update` - - `sudo apt install postgresql postgresql-contrib` - -###### 2. Create db and admin user: - - Before run and test connection, make sure you have created a database as described in the above configuration. You can use the `psql` command to create a user and database. - - `psql postgres --u postgres` - -- Next, type this command for creating a new user with password then give access for creating the database. - - `postgres-# CREATE ROLE admin WITH LOGIN PASSWORD 'admin_pass';` - - `postgres-# ALTER ROLE admin CREATEDB;` - -- Quit `psql` then log in again using the new user that previously created. - - `postgres-# \q` - - `psql postgres -U admin` - -- Type this command to creating a new database. - - `postgres=> CREATE DATABASE db_store_operations_hub;` - -- Then give that new user privileges to the new database then quit the `psql`. - - `postgres=> GRANT ALL PRIVILEGES ON DATABASE db_store_operations_hub TO admin;` - - `postgres=> \q` - ------------- - -#### Api Documentation (Swagger) - -http://localhost:8080/api-docs (local host) - -http://host_name/api-docs - ------------- - - ##### Setup database tables or update after schema change - - `yarn db:migrate` - - ##### Seed the initial data (admin accounts, relevant for the first setup): - - `yarn db:seed` - - ##### Start build: - - `yarn start` diff --git a/backend/package.json b/backend/package.json deleted file mode 100644 index f94924a..0000000 --- a/backend/package.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "name": "storeoperationshub", - "description": "Store Operations Hub - template backend", - "scripts": { - "start": "npm run db:migrate && npm run db:seed && npm run watch", - "lint": "eslint . --ext .js", - "db:migrate": "sequelize-cli db:migrate", - "db:seed": "sequelize-cli db:seed:all", - "db:drop": "sequelize-cli db:drop", - "db:create": "sequelize-cli db:create", - "watch": "node watcher.js" - }, - "dependencies": { - "@google-cloud/storage": "^5.18.2", - "axios": "^1.6.7", - "bcrypt": "5.1.1", - "chokidar": "^4.0.3", - "cors": "2.8.5", - "csv-parser": "^3.0.0", - "express": "4.18.2", - "formidable": "1.2.2", - "helmet": "4.1.1", - "json2csv": "^5.0.7", - "jsonwebtoken": "8.5.1", - "lodash": "4.17.21", - "moment": "2.30.1", - "multer": "^1.4.4", - "mysql2": "2.2.5", - "nodemailer": "6.9.9", - "passport": "^0.7.0", - "passport-google-oauth2": "^0.2.0", - "passport-jwt": "^4.0.1", - "passport-microsoft": "^0.1.0", - "pg": "8.4.1", - "pg-hstore": "2.3.4", - "sequelize": "6.35.2", - "sequelize-json-schema": "^2.1.1", - "sqlite": "4.0.15", - "swagger-jsdoc": "^6.2.8", - "swagger-ui-express": "^5.0.0", - "tedious": "^18.2.4" - }, - "engines": { - "node": ">=18" - }, - "private": true, - "devDependencies": { - "cross-env": "7.0.3", - "eslint": "^8.23.1", - "eslint-plugin-import": "^2.29.1", - "mocha": "8.1.3", - "node-mocks-http": "1.9.0", - "nodemon": "2.0.5", - "sequelize-cli": "6.6.2" - } -} diff --git a/backend/src/ai/LocalAIApi.js b/backend/src/ai/LocalAIApi.js deleted file mode 100644 index fd571ae..0000000 --- a/backend/src/ai/LocalAIApi.js +++ /dev/null @@ -1,484 +0,0 @@ -"use strict"; - -const fs = require("fs"); -const path = require("path"); -const http = require("http"); -const https = require("https"); -const { URL } = require("url"); - -let CONFIG_CACHE = null; - -class LocalAIApi { - static createResponse(params, options) { - return createResponse(params, options); - } - - static request(pathValue, payload, options) { - return request(pathValue, payload, options); - } - - static fetchStatus(aiRequestId, options) { - return fetchStatus(aiRequestId, options); - } - - static awaitResponse(aiRequestId, options) { - return awaitResponse(aiRequestId, options); - } - - static extractText(response) { - return extractText(response); - } - - static decodeJsonFromResponse(response) { - return decodeJsonFromResponse(response); - } -} - -async function createResponse(params, options = {}) { - const payload = { ...(params || {}) }; - - if (!Array.isArray(payload.input) || payload.input.length === 0) { - return { - success: false, - error: "input_missing", - message: 'Parameter "input" is required and must be a non-empty array.', - }; - } - - const cfg = config(); - if (!payload.model) { - payload.model = cfg.defaultModel; - } - - const initial = await request(options.path, payload, options); - if (!initial.success) { - return initial; - } - - const data = initial.data; - if (data && typeof data === "object" && data.ai_request_id) { - const pollTimeout = Number(options.poll_timeout ?? 300); - const pollInterval = Number(options.poll_interval ?? 5); - return await awaitResponse(data.ai_request_id, { - interval: pollInterval, - timeout: pollTimeout, - headers: options.headers, - timeout_per_call: options.timeout, - verify_tls: options.verify_tls, - }); - } - - return initial; -} - -async function request(pathValue, payload = {}, options = {}) { - const cfg = config(); - const resolvedPath = pathValue || options.path || cfg.responsesPath; - - if (!resolvedPath) { - return { - success: false, - error: "project_id_missing", - message: "PROJECT_ID is not defined; cannot resolve AI proxy endpoint.", - }; - } - - if (!cfg.projectUuid) { - return { - success: false, - error: "project_uuid_missing", - message: "PROJECT_UUID is not defined; aborting AI request.", - }; - } - - const bodyPayload = { ...(payload || {}) }; - if (!bodyPayload.project_uuid) { - bodyPayload.project_uuid = cfg.projectUuid; - } - - const url = buildUrl(resolvedPath, cfg.baseUrl); - const timeout = resolveTimeout(options.timeout, cfg.timeout); - const verifyTls = resolveVerifyTls(options.verify_tls, cfg.verifyTls); - - const headers = { - Accept: "application/json", - "Content-Type": "application/json", - [cfg.projectHeader]: cfg.projectUuid, - }; - if (Array.isArray(options.headers)) { - for (const header of options.headers) { - if (typeof header === "string" && header.includes(":")) { - const [name, value] = header.split(":", 2); - headers[name.trim()] = value.trim(); - } - } - } - - const body = JSON.stringify(bodyPayload); - return sendRequest(url, "POST", body, headers, timeout, verifyTls); -} - -async function fetchStatus(aiRequestId, options = {}) { - const cfg = config(); - if (!cfg.projectUuid) { - return { - success: false, - error: "project_uuid_missing", - message: "PROJECT_UUID is not defined; aborting status check.", - }; - } - - const statusPath = resolveStatusPath(aiRequestId, cfg); - const url = buildUrl(statusPath, cfg.baseUrl); - const timeout = resolveTimeout(options.timeout, cfg.timeout); - const verifyTls = resolveVerifyTls(options.verify_tls, cfg.verifyTls); - - const headers = { - Accept: "application/json", - [cfg.projectHeader]: cfg.projectUuid, - }; - if (Array.isArray(options.headers)) { - for (const header of options.headers) { - if (typeof header === "string" && header.includes(":")) { - const [name, value] = header.split(":", 2); - headers[name.trim()] = value.trim(); - } - } - } - - return sendRequest(url, "GET", null, headers, timeout, verifyTls); -} - -async function awaitResponse(aiRequestId, options = {}) { - const timeout = Number(options.timeout ?? 300); - const interval = Math.max(Number(options.interval ?? 5), 1); - const deadline = Date.now() + Math.max(timeout, interval) * 1000; - - while (true) { - const statusResp = await fetchStatus(aiRequestId, { - headers: options.headers, - timeout: options.timeout_per_call, - verify_tls: options.verify_tls, - }); - - if (statusResp.success) { - const data = statusResp.data || {}; - if (data && typeof data === "object") { - if (data.status === "success") { - return { - success: true, - status: 200, - data: data.response || data, - }; - } - if (data.status === "failed") { - return { - success: false, - status: 500, - error: String(data.error || "AI request failed"), - data, - }; - } - } - } else { - return statusResp; - } - - if (Date.now() >= deadline) { - return { - success: false, - error: "timeout", - message: "Timed out waiting for AI response.", - }; - } - - await sleep(interval * 1000); - } -} - -function extractText(response) { - const payload = response && typeof response === "object" ? response.data || response : null; - if (!payload || typeof payload !== "object") { - return ""; - } - - if (Array.isArray(payload.output)) { - let combined = ""; - for (const item of payload.output) { - if (!item || !Array.isArray(item.content)) { - continue; - } - for (const block of item.content) { - if ( - block && - typeof block === "object" && - block.type === "output_text" && - typeof block.text === "string" && - block.text.length > 0 - ) { - combined += block.text; - } - } - } - if (combined) { - return combined; - } - } - - if ( - payload.choices && - payload.choices[0] && - payload.choices[0].message && - typeof payload.choices[0].message.content === "string" - ) { - return payload.choices[0].message.content; - } - - return ""; -} - -function decodeJsonFromResponse(response) { - const text = extractText(response); - if (!text) { - throw new Error("No text found in AI response."); - } - - const parsed = parseJson(text); - if (parsed.ok && parsed.value && typeof parsed.value === "object") { - return parsed.value; - } - - const stripped = stripJsonFence(text); - if (stripped !== text) { - const parsedStripped = parseJson(stripped); - if (parsedStripped.ok && parsedStripped.value && typeof parsedStripped.value === "object") { - return parsedStripped.value; - } - throw new Error(`JSON parse failed after stripping fences: ${parsedStripped.error}`); - } - - throw new Error(`JSON parse failed: ${parsed.error}`); -} - -function config() { - if (CONFIG_CACHE) { - return CONFIG_CACHE; - } - - ensureEnvLoaded(); - - const baseUrl = process.env.AI_PROXY_BASE_URL || "https://flatlogic.com"; - const projectId = process.env.PROJECT_ID || null; - let responsesPath = process.env.AI_RESPONSES_PATH || null; - if (!responsesPath && projectId) { - responsesPath = `/projects/${projectId}/ai-request`; - } - - const timeout = resolveTimeout(process.env.AI_TIMEOUT, 30); - const verifyTls = resolveVerifyTls(process.env.AI_VERIFY_TLS, true); - - CONFIG_CACHE = { - baseUrl, - responsesPath, - projectId, - projectUuid: process.env.PROJECT_UUID || null, - projectHeader: process.env.AI_PROJECT_HEADER || "project-uuid", - defaultModel: process.env.AI_DEFAULT_MODEL || "gpt-5-mini", - timeout, - verifyTls, - }; - - return CONFIG_CACHE; -} - -function buildUrl(pathValue, baseUrl) { - const trimmed = String(pathValue || "").trim(); - if (trimmed === "") { - return baseUrl; - } - if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) { - return trimmed; - } - if (trimmed.startsWith("/")) { - return `${baseUrl}${trimmed}`; - } - return `${baseUrl}/${trimmed}`; -} - -function resolveStatusPath(aiRequestId, cfg) { - const basePath = (cfg.responsesPath || "").replace(/\/+$/, ""); - if (!basePath) { - return `/ai-request/${encodeURIComponent(String(aiRequestId))}/status`; - } - const normalized = basePath.endsWith("/ai-request") ? basePath : `${basePath}/ai-request`; - return `${normalized}/${encodeURIComponent(String(aiRequestId))}/status`; -} - -function sendRequest(urlString, method, body, headers, timeoutSeconds, verifyTls) { - return new Promise((resolve) => { - let targetUrl; - try { - targetUrl = new URL(urlString); - } catch (err) { - resolve({ - success: false, - error: "invalid_url", - message: err.message, - }); - return; - } - - const isHttps = targetUrl.protocol === "https:"; - const requestFn = isHttps ? https.request : http.request; - const options = { - protocol: targetUrl.protocol, - hostname: targetUrl.hostname, - port: targetUrl.port || (isHttps ? 443 : 80), - path: `${targetUrl.pathname}${targetUrl.search}`, - method: method.toUpperCase(), - headers, - timeout: Math.max(Number(timeoutSeconds || 30), 1) * 1000, - }; - if (isHttps) { - options.rejectUnauthorized = Boolean(verifyTls); - } - - const req = requestFn(options, (res) => { - let responseBody = ""; - res.setEncoding("utf8"); - res.on("data", (chunk) => { - responseBody += chunk; - }); - res.on("end", () => { - const status = res.statusCode || 0; - const parsed = parseJson(responseBody); - const payload = parsed.ok ? parsed.value : responseBody; - - if (status >= 200 && status < 300) { - const result = { - success: true, - status, - data: payload, - }; - if (!parsed.ok) { - result.json_error = parsed.error; - } - resolve(result); - return; - } - - const errorMessage = - parsed.ok && payload && typeof payload === "object" - ? String(payload.error || payload.message || "AI proxy request failed") - : String(responseBody || "AI proxy request failed"); - - resolve({ - success: false, - status, - error: errorMessage, - response: payload, - json_error: parsed.ok ? undefined : parsed.error, - }); - }); - }); - - req.on("timeout", () => { - req.destroy(new Error("request_timeout")); - }); - - req.on("error", (err) => { - resolve({ - success: false, - error: "request_failed", - message: err.message, - }); - }); - - if (body) { - req.write(body); - } - req.end(); - }); -} - -function parseJson(value) { - if (typeof value !== "string" || value.trim() === "") { - return { ok: false, error: "empty_response" }; - } - try { - return { ok: true, value: JSON.parse(value) }; - } catch (err) { - return { ok: false, error: err.message }; - } -} - -function stripJsonFence(text) { - const trimmed = text.trim(); - if (trimmed.startsWith("```json")) { - return trimmed.replace(/^```json/, "").replace(/```$/, "").trim(); - } - if (trimmed.startsWith("```")) { - return trimmed.replace(/^```/, "").replace(/```$/, "").trim(); - } - return text; -} - -function resolveTimeout(value, fallback) { - const parsed = Number.parseInt(String(value ?? fallback), 10); - return Number.isNaN(parsed) ? Number(fallback) : parsed; -} - -function resolveVerifyTls(value, fallback) { - if (value === undefined || value === null) { - return Boolean(fallback); - } - return String(value).toLowerCase() !== "false" && String(value) !== "0"; -} - -function ensureEnvLoaded() { - if (process.env.PROJECT_UUID && process.env.PROJECT_ID) { - return; - } - - const envPath = path.resolve(__dirname, "../../../../.env"); - if (!fs.existsSync(envPath)) { - return; - } - - let content; - try { - content = fs.readFileSync(envPath, "utf8"); - } catch (err) { - throw new Error(`Failed to read executor .env: ${err.message}`); - } - - for (const line of content.split(/\r?\n/)) { - const trimmed = line.trim(); - if (!trimmed || trimmed.startsWith("#") || !trimmed.includes("=")) { - continue; - } - const [rawKey, ...rest] = trimmed.split("="); - const key = rawKey.trim(); - if (!key) { - continue; - } - const value = rest.join("=").trim().replace(/^['"]|['"]$/g, ""); - if (!process.env[key]) { - process.env[key] = value; - } - } -} - -function sleep(ms) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -module.exports = { - LocalAIApi, - createResponse, - request, - fetchStatus, - awaitResponse, - extractText, - decodeJsonFromResponse, -}; diff --git a/backend/src/auth/auth.js b/backend/src/auth/auth.js deleted file mode 100644 index 251c149..0000000 --- a/backend/src/auth/auth.js +++ /dev/null @@ -1,68 +0,0 @@ -const config = require('../config'); -const providers = config.providers; -const helpers = require('../helpers'); -const db = require('../db/models'); - -const passport = require('passport'); -const JWTstrategy = require('passport-jwt').Strategy; -const ExtractJWT = require('passport-jwt').ExtractJwt; -const GoogleStrategy = require('passport-google-oauth2').Strategy; -const MicrosoftStrategy = require('passport-microsoft').Strategy; -const UsersDBApi = require('../db/api/users'); - - -passport.use(new JWTstrategy({ - passReqToCallback: true, - secretOrKey: config.secret_key, - jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken() -}, async (req, token, done) => { - try { - const user = await UsersDBApi.findBy( {email: token.user.email}); - - if (user && user.disabled) { - return done (new Error(`User '${user.email}' is disabled`)); - } - - req.currentUser = user; - - return done(null, user); - } catch (error) { - done(error); - } -})); - -passport.use(new GoogleStrategy({ - clientID: config.google.clientId, - clientSecret: config.google.clientSecret, - callbackURL: config.apiUrl + '/auth/signin/google/callback', - passReqToCallback: true - }, - function (request, accessToken, refreshToken, profile, done) { - socialStrategy(profile.email, profile, providers.GOOGLE, done); - } -)); - - -passport.use(new MicrosoftStrategy({ - clientID: config.microsoft.clientId, - clientSecret: config.microsoft.clientSecret, - callbackURL: config.apiUrl + '/auth/signin/microsoft/callback', - passReqToCallback: true - }, - function (request, accessToken, refreshToken, profile, done) { - const email = profile._json.mail || profile._json.userPrincipalName; - socialStrategy(email, profile, providers.MICROSOFT, done); - } -)); - -function socialStrategy(email, profile, provider, done) { - db.users.findOrCreate({where: {email, provider}}).then(([user, created]) => { - const body = { - id: user.id, - email: user.email, - name: profile.displayName, - }; - const token = helpers.jwtSign({user: body}); - return done(null, {token}); - }); -} diff --git a/backend/src/config.js b/backend/src/config.js deleted file mode 100644 index 69b7bb6..0000000 --- a/backend/src/config.js +++ /dev/null @@ -1,79 +0,0 @@ - - - -const os = require('os'); - -const config = { - gcloud: { - bucket: "fldemo-files", - hash: "afeefb9d49f5b7977577876b99532ac7" - }, - bcrypt: { - saltRounds: 12 - }, - admin_pass: "400e0c7b", - user_pass: "09432b1b11f5", - admin_email: "admin@flatlogic.com", - providers: { - LOCAL: 'local', - GOOGLE: 'google', - MICROSOFT: 'microsoft' - }, - secret_key: process.env.SECRET_KEY || '400e0c7b-bbce-48ee-82c0-09432b1b11f5', - remote: '', - port: process.env.NODE_ENV === "production" ? "" : "8080", - hostUI: process.env.NODE_ENV === "production" ? "" : "http://localhost", - portUI: process.env.NODE_ENV === "production" ? "" : "3000", - - portUIProd: process.env.NODE_ENV === "production" ? "" : ":3000", - - swaggerUI: process.env.NODE_ENV === "production" ? "" : "http://localhost", - swaggerPort: process.env.NODE_ENV === "production" ? "" : ":8080", - google: { - clientId: process.env.GOOGLE_CLIENT_ID || '', - clientSecret: process.env.GOOGLE_CLIENT_SECRET || '', - }, - microsoft: { - clientId: process.env.MS_CLIENT_ID || '', - clientSecret: process.env.MS_CLIENT_SECRET || '', - }, - uploadDir: os.tmpdir(), - email: { - from: 'Store Operations Hub ', - host: 'email-smtp.us-east-1.amazonaws.com', - port: 587, - auth: { - user: process.env.EMAIL_USER || '', - pass: process.env.EMAIL_PASS, - }, - tls: { - rejectUnauthorized: false - } - }, - roles: { - - admin: 'Administrator', - - - - user: 'Payments Analyst', - - }, - - project_uuid: '400e0c7b-bbce-48ee-82c0-09432b1b11f5', - flHost: process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'dev_stage' ? 'https://flatlogic.com/projects' : 'http://localhost:3000/projects', - - - gpt_key: process.env.GPT_KEY || '', -}; - -config.pexelsKey = process.env.PEXELS_KEY || ''; - -config.pexelsQuery = 'Organized warehouse shelves at dawn'; -config.host = process.env.NODE_ENV === "production" ? config.remote : "http://localhost"; -config.apiUrl = `${config.host}${config.port ? `:${config.port}` : ``}/api`; -config.swaggerUrl = `${config.swaggerUI}${config.swaggerPort}`; -config.uiUrl = `${config.hostUI}${config.portUI ? `:${config.portUI}` : ``}/#`; -config.backUrl = `${config.hostUI}${config.portUI ? `:${config.portUI}` : ``}`; - -module.exports = config; diff --git a/backend/src/db/api/customers.js b/backend/src/db/api/customers.js deleted file mode 100644 index 8e34a24..0000000 --- a/backend/src/db/api/customers.js +++ /dev/null @@ -1,541 +0,0 @@ - -const db = require('../models'); -const FileDBApi = require('./file'); -const crypto = require('crypto'); -const Utils = require('../utils'); - - - -const Sequelize = db.Sequelize; -const Op = Sequelize.Op; - -module.exports = class CustomersDBApi { - - - - static async create(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const customers = await db.customers.create( - { - id: data.id || undefined, - - customer_code: data.customer_code - || - null - , - - full_name: data.full_name - || - null - , - - email: data.email - || - null - , - - phone: data.phone - || - null - , - - billing_address: data.billing_address - || - null - , - - shipping_address: data.shipping_address - || - null - , - - customer_status: data.customer_status - || - null - , - - registered_at: data.registered_at - || - null - , - - notes: data.notes - || - null - , - - importHash: data.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - - - - - - - return customers; - } - - - static async bulkImport(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - // Prepare data - wrapping individual data transformations in a map() method - const customersData = data.map((item, index) => ({ - id: item.id || undefined, - - customer_code: item.customer_code - || - null - , - - full_name: item.full_name - || - null - , - - email: item.email - || - null - , - - phone: item.phone - || - null - , - - billing_address: item.billing_address - || - null - , - - shipping_address: item.shipping_address - || - null - , - - customer_status: item.customer_status - || - null - , - - registered_at: item.registered_at - || - null - , - - notes: item.notes - || - null - , - - importHash: item.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - createdAt: new Date(Date.now() + index * 1000), - })); - - // Bulk create items - const customers = await db.customers.bulkCreate(customersData, { transaction }); - - // For each item created, replace relation files - - - return customers; - } - - static async update(id, data, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - - const customers = await db.customers.findByPk(id, {}, {transaction}); - - - - - const updatePayload = {}; - - if (data.customer_code !== undefined) updatePayload.customer_code = data.customer_code; - - - if (data.full_name !== undefined) updatePayload.full_name = data.full_name; - - - if (data.email !== undefined) updatePayload.email = data.email; - - - if (data.phone !== undefined) updatePayload.phone = data.phone; - - - if (data.billing_address !== undefined) updatePayload.billing_address = data.billing_address; - - - if (data.shipping_address !== undefined) updatePayload.shipping_address = data.shipping_address; - - - if (data.customer_status !== undefined) updatePayload.customer_status = data.customer_status; - - - if (data.registered_at !== undefined) updatePayload.registered_at = data.registered_at; - - - if (data.notes !== undefined) updatePayload.notes = data.notes; - - - updatePayload.updatedById = currentUser.id; - - await customers.update(updatePayload, {transaction}); - - - - - - - - - - return customers; - } - - static async deleteByIds(ids, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const customers = await db.customers.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); - - await db.sequelize.transaction(async (transaction) => { - for (const record of customers) { - await record.update( - {deletedBy: currentUser.id}, - {transaction} - ); - } - for (const record of customers) { - await record.destroy({transaction}); - } - }); - - - return customers; - } - - static async remove(id, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - const customers = await db.customers.findByPk(id, options); - - await customers.update({ - deletedBy: currentUser.id - }, { - transaction, - }); - - await customers.destroy({ - transaction - }); - - return customers; - } - - static async findBy(where, options) { - const transaction = (options && options.transaction) || undefined; - - const customers = await db.customers.findOne( - { where }, - { transaction }, - ); - - if (!customers) { - return customers; - } - - const output = customers.get({plain: true}); - - - - - - - - - output.orders_customer = await customers.getOrders_customer({ - transaction - }); - - - - - - - - return output; - } - - static async findAll( - filter, - options - ) { - const limit = filter.limit || 0; - let offset = 0; - let where = {}; - const currentPage = +filter.page; - - - - - - offset = currentPage * limit; - - const orderBy = null; - - const transaction = (options && options.transaction) || undefined; - - let include = [ - - - - ]; - - if (filter) { - if (filter.id) { - where = { - ...where, - ['id']: Utils.uuid(filter.id), - }; - } - - - if (filter.customer_code) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'customers', - 'customer_code', - filter.customer_code, - ), - }; - } - - if (filter.full_name) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'customers', - 'full_name', - filter.full_name, - ), - }; - } - - if (filter.email) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'customers', - 'email', - filter.email, - ), - }; - } - - if (filter.phone) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'customers', - 'phone', - filter.phone, - ), - }; - } - - if (filter.billing_address) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'customers', - 'billing_address', - filter.billing_address, - ), - }; - } - - if (filter.shipping_address) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'customers', - 'shipping_address', - filter.shipping_address, - ), - }; - } - - if (filter.notes) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'customers', - 'notes', - filter.notes, - ), - }; - } - - - - - - - if (filter.registered_atRange) { - const [start, end] = filter.registered_atRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - registered_at: { - ...where.registered_at, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - registered_at: { - ...where.registered_at, - [Op.lte]: end, - }, - }; - } - } - - - if (filter.active !== undefined) { - where = { - ...where, - active: filter.active === true || filter.active === 'true' - }; - } - - - if (filter.customer_status) { - where = { - ...where, - customer_status: filter.customer_status, - }; - } - - - - - - if (filter.createdAtRange) { - const [start, end] = filter.createdAtRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - ['createdAt']: { - ...where.createdAt, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - ['createdAt']: { - ...where.createdAt, - [Op.lte]: end, - }, - }; - } - } - } - - - - - const queryOptions = { - where, - include, - distinct: true, - order: filter.field && filter.sort - ? [[filter.field, filter.sort]] - : [['createdAt', 'desc']], - transaction: options?.transaction, - logging: console.log - }; - - if (!options?.countOnly) { - queryOptions.limit = limit ? Number(limit) : undefined; - queryOptions.offset = offset ? Number(offset) : undefined; - } - - try { - const { rows, count } = await db.customers.findAndCountAll(queryOptions); - - return { - rows: options?.countOnly ? [] : rows, - count: count - }; - } catch (error) { - console.error('Error executing query:', error); - throw error; - } - } - - static async findAllAutocomplete(query, limit, offset, ) { - let where = {}; - - - - if (query) { - where = { - [Op.or]: [ - { ['id']: Utils.uuid(query) }, - Utils.ilike( - 'customers', - 'full_name', - query, - ), - ], - }; - } - - const records = await db.customers.findAll({ - attributes: [ 'id', 'full_name' ], - where, - limit: limit ? Number(limit) : undefined, - offset: offset ? Number(offset) : undefined, - orderBy: [['full_name', 'ASC']], - }); - - return records.map((record) => ({ - id: record.id, - label: record.full_name, - })); - } - - -}; - diff --git a/backend/src/db/api/file.js b/backend/src/db/api/file.js deleted file mode 100644 index f4f7121..0000000 --- a/backend/src/db/api/file.js +++ /dev/null @@ -1,87 +0,0 @@ -const db = require('../models'); -const assert = require('assert'); -const services = require('../../services/file'); - -module.exports = class FileDBApi { - static async replaceRelationFiles( - relation, - rawFiles, - options, - ) { - assert(relation.belongsTo, 'belongsTo is required'); - assert( - relation.belongsToColumn, - 'belongsToColumn is required', - ); - assert(relation.belongsToId, 'belongsToId is required'); - - let files = []; - - if (Array.isArray(rawFiles)) { - files = rawFiles; - } else { - files = rawFiles ? [rawFiles] : []; - } - - await this._removeLegacyFiles(relation, files, options); - await this._addFiles(relation, files, options); - } - - static async _addFiles(relation, files, options) { - const transaction = (options && options.transaction) || undefined; - const currentUser = (options && options.currentUser) || {id: null}; - - const inexistentFiles = files.filter( - (file) => !!file.new, - ); - - for (const file of inexistentFiles) { - await db.file.create( - { - belongsTo: relation.belongsTo, - belongsToColumn: relation.belongsToColumn, - belongsToId: relation.belongsToId, - name: file.name, - sizeInBytes: file.sizeInBytes, - privateUrl: file.privateUrl, - publicUrl: file.publicUrl, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { - transaction, - }, - ); - } - } - - static async _removeLegacyFiles( - relation, - files, - options, - ) { - const transaction = (options && options.transaction) || undefined; - - const filesToDelete = await db.file.findAll({ - where: { - belongsTo: relation.belongsTo, - belongsToId: relation.belongsToId, - belongsToColumn: relation.belongsToColumn, - id: { - [db.Sequelize.Op - .notIn]: files - .filter((file) => !file.new) - .map((file) => file.id) - }, - }, - transaction, - }); - - for (let file of filesToDelete) { - await services.deleteGCloud(file.privateUrl); - await file.destroy({ - transaction, - }); - } - } -}; diff --git a/backend/src/db/api/order_items.js b/backend/src/db/api/order_items.js deleted file mode 100644 index 7657e17..0000000 --- a/backend/src/db/api/order_items.js +++ /dev/null @@ -1,639 +0,0 @@ - -const db = require('../models'); -const FileDBApi = require('./file'); -const crypto = require('crypto'); -const Utils = require('../utils'); - - - -const Sequelize = db.Sequelize; -const Op = Sequelize.Op; - -module.exports = class Order_itemsDBApi { - - - - static async create(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const order_items = await db.order_items.create( - { - id: data.id || undefined, - - product_name_snapshot: data.product_name_snapshot - || - null - , - - sku_snapshot: data.sku_snapshot - || - null - , - - unit_price: data.unit_price - || - null - , - - quantity: data.quantity - || - null - , - - line_discount_amount: data.line_discount_amount - || - null - , - - line_tax_amount: data.line_tax_amount - || - null - , - - line_total_amount: data.line_total_amount - || - null - , - - item_fulfillment_status: data.item_fulfillment_status - || - null - , - - importHash: data.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - - await order_items.setOrder( data.order || null, { - transaction, - }); - - await order_items.setProduct( data.product || null, { - transaction, - }); - - - - - - - return order_items; - } - - - static async bulkImport(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - // Prepare data - wrapping individual data transformations in a map() method - const order_itemsData = data.map((item, index) => ({ - id: item.id || undefined, - - product_name_snapshot: item.product_name_snapshot - || - null - , - - sku_snapshot: item.sku_snapshot - || - null - , - - unit_price: item.unit_price - || - null - , - - quantity: item.quantity - || - null - , - - line_discount_amount: item.line_discount_amount - || - null - , - - line_tax_amount: item.line_tax_amount - || - null - , - - line_total_amount: item.line_total_amount - || - null - , - - item_fulfillment_status: item.item_fulfillment_status - || - null - , - - importHash: item.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - createdAt: new Date(Date.now() + index * 1000), - })); - - // Bulk create items - const order_items = await db.order_items.bulkCreate(order_itemsData, { transaction }); - - // For each item created, replace relation files - - - return order_items; - } - - static async update(id, data, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - - const order_items = await db.order_items.findByPk(id, {}, {transaction}); - - - - - const updatePayload = {}; - - if (data.product_name_snapshot !== undefined) updatePayload.product_name_snapshot = data.product_name_snapshot; - - - if (data.sku_snapshot !== undefined) updatePayload.sku_snapshot = data.sku_snapshot; - - - if (data.unit_price !== undefined) updatePayload.unit_price = data.unit_price; - - - if (data.quantity !== undefined) updatePayload.quantity = data.quantity; - - - if (data.line_discount_amount !== undefined) updatePayload.line_discount_amount = data.line_discount_amount; - - - if (data.line_tax_amount !== undefined) updatePayload.line_tax_amount = data.line_tax_amount; - - - if (data.line_total_amount !== undefined) updatePayload.line_total_amount = data.line_total_amount; - - - if (data.item_fulfillment_status !== undefined) updatePayload.item_fulfillment_status = data.item_fulfillment_status; - - - updatePayload.updatedById = currentUser.id; - - await order_items.update(updatePayload, {transaction}); - - - - if (data.order !== undefined) { - await order_items.setOrder( - - data.order, - - { transaction } - ); - } - - if (data.product !== undefined) { - await order_items.setProduct( - - data.product, - - { transaction } - ); - } - - - - - - - - return order_items; - } - - static async deleteByIds(ids, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const order_items = await db.order_items.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); - - await db.sequelize.transaction(async (transaction) => { - for (const record of order_items) { - await record.update( - {deletedBy: currentUser.id}, - {transaction} - ); - } - for (const record of order_items) { - await record.destroy({transaction}); - } - }); - - - return order_items; - } - - static async remove(id, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - const order_items = await db.order_items.findByPk(id, options); - - await order_items.update({ - deletedBy: currentUser.id - }, { - transaction, - }); - - await order_items.destroy({ - transaction - }); - - return order_items; - } - - static async findBy(where, options) { - const transaction = (options && options.transaction) || undefined; - - const order_items = await db.order_items.findOne( - { where }, - { transaction }, - ); - - if (!order_items) { - return order_items; - } - - const output = order_items.get({plain: true}); - - - - - - - - - - - - - - output.order = await order_items.getOrder({ - transaction - }); - - - output.product = await order_items.getProduct({ - transaction - }); - - - - return output; - } - - static async findAll( - filter, - options - ) { - const limit = filter.limit || 0; - let offset = 0; - let where = {}; - const currentPage = +filter.page; - - - - - - offset = currentPage * limit; - - const orderBy = null; - - const transaction = (options && options.transaction) || undefined; - - let include = [ - - { - model: db.orders, - as: 'order', - - where: filter.order ? { - [Op.or]: [ - { id: { [Op.in]: filter.order.split('|').map(term => Utils.uuid(term)) } }, - { - order_number: { - [Op.or]: filter.order.split('|').map(term => ({ [Op.iLike]: `%${term}%` })) - } - }, - ] - } : {}, - - }, - - { - model: db.products, - as: 'product', - - where: filter.product ? { - [Op.or]: [ - { id: { [Op.in]: filter.product.split('|').map(term => Utils.uuid(term)) } }, - { - name: { - [Op.or]: filter.product.split('|').map(term => ({ [Op.iLike]: `%${term}%` })) - } - }, - ] - } : {}, - - }, - - - - ]; - - if (filter) { - if (filter.id) { - where = { - ...where, - ['id']: Utils.uuid(filter.id), - }; - } - - - if (filter.product_name_snapshot) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'order_items', - 'product_name_snapshot', - filter.product_name_snapshot, - ), - }; - } - - if (filter.sku_snapshot) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'order_items', - 'sku_snapshot', - filter.sku_snapshot, - ), - }; - } - - - - - - - if (filter.unit_priceRange) { - const [start, end] = filter.unit_priceRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - unit_price: { - ...where.unit_price, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - unit_price: { - ...where.unit_price, - [Op.lte]: end, - }, - }; - } - } - - if (filter.quantityRange) { - const [start, end] = filter.quantityRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - quantity: { - ...where.quantity, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - quantity: { - ...where.quantity, - [Op.lte]: end, - }, - }; - } - } - - if (filter.line_discount_amountRange) { - const [start, end] = filter.line_discount_amountRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - line_discount_amount: { - ...where.line_discount_amount, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - line_discount_amount: { - ...where.line_discount_amount, - [Op.lte]: end, - }, - }; - } - } - - if (filter.line_tax_amountRange) { - const [start, end] = filter.line_tax_amountRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - line_tax_amount: { - ...where.line_tax_amount, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - line_tax_amount: { - ...where.line_tax_amount, - [Op.lte]: end, - }, - }; - } - } - - if (filter.line_total_amountRange) { - const [start, end] = filter.line_total_amountRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - line_total_amount: { - ...where.line_total_amount, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - line_total_amount: { - ...where.line_total_amount, - [Op.lte]: end, - }, - }; - } - } - - - if (filter.active !== undefined) { - where = { - ...where, - active: filter.active === true || filter.active === 'true' - }; - } - - - if (filter.item_fulfillment_status) { - where = { - ...where, - item_fulfillment_status: filter.item_fulfillment_status, - }; - } - - - - - - - - - - if (filter.createdAtRange) { - const [start, end] = filter.createdAtRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - ['createdAt']: { - ...where.createdAt, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - ['createdAt']: { - ...where.createdAt, - [Op.lte]: end, - }, - }; - } - } - } - - - - - const queryOptions = { - where, - include, - distinct: true, - order: filter.field && filter.sort - ? [[filter.field, filter.sort]] - : [['createdAt', 'desc']], - transaction: options?.transaction, - logging: console.log - }; - - if (!options?.countOnly) { - queryOptions.limit = limit ? Number(limit) : undefined; - queryOptions.offset = offset ? Number(offset) : undefined; - } - - try { - const { rows, count } = await db.order_items.findAndCountAll(queryOptions); - - return { - rows: options?.countOnly ? [] : rows, - count: count - }; - } catch (error) { - console.error('Error executing query:', error); - throw error; - } - } - - static async findAllAutocomplete(query, limit, offset, ) { - let where = {}; - - - - if (query) { - where = { - [Op.or]: [ - { ['id']: Utils.uuid(query) }, - Utils.ilike( - 'order_items', - 'product_name_snapshot', - query, - ), - ], - }; - } - - const records = await db.order_items.findAll({ - attributes: [ 'id', 'product_name_snapshot' ], - where, - limit: limit ? Number(limit) : undefined, - offset: offset ? Number(offset) : undefined, - orderBy: [['product_name_snapshot', 'ASC']], - }); - - return records.map((record) => ({ - id: record.id, - label: record.product_name_snapshot, - })); - } - - -}; - diff --git a/backend/src/db/api/orders.js b/backend/src/db/api/orders.js deleted file mode 100644 index 5bc2533..0000000 --- a/backend/src/db/api/orders.js +++ /dev/null @@ -1,1031 +0,0 @@ - -const db = require('../models'); -const FileDBApi = require('./file'); -const crypto = require('crypto'); -const Utils = require('../utils'); - - - -const Sequelize = db.Sequelize; -const Op = Sequelize.Op; - -module.exports = class OrdersDBApi { - - - - static async create(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const orders = await db.orders.create( - { - id: data.id || undefined, - - order_number: data.order_number - || - null - , - - order_status: data.order_status - || - null - , - - fulfillment_status: data.fulfillment_status - || - null - , - - payment_status: data.payment_status - || - null - , - - placed_at: data.placed_at - || - null - , - - packed_at: data.packed_at - || - null - , - - shipped_at: data.shipped_at - || - null - , - - delivered_at: data.delivered_at - || - null - , - - subtotal_amount: data.subtotal_amount - || - null - , - - discount_amount: data.discount_amount - || - null - , - - tax_amount: data.tax_amount - || - null - , - - shipping_amount: data.shipping_amount - || - null - , - - total_amount: data.total_amount - || - null - , - - currency: data.currency - || - null - , - - shipping_name: data.shipping_name - || - null - , - - shipping_address: data.shipping_address - || - null - , - - billing_name: data.billing_name - || - null - , - - billing_address: data.billing_address - || - null - , - - notes_internal: data.notes_internal - || - null - , - - customer_note: data.customer_note - || - null - , - - tracking_number: data.tracking_number - || - null - , - - carrier: data.carrier - || - null - , - - importHash: data.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - - await orders.setCustomer( data.customer || null, { - transaction, - }); - - await orders.setAssigned_to( data.assigned_to || null, { - transaction, - }); - - - - - - - return orders; - } - - - static async bulkImport(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - // Prepare data - wrapping individual data transformations in a map() method - const ordersData = data.map((item, index) => ({ - id: item.id || undefined, - - order_number: item.order_number - || - null - , - - order_status: item.order_status - || - null - , - - fulfillment_status: item.fulfillment_status - || - null - , - - payment_status: item.payment_status - || - null - , - - placed_at: item.placed_at - || - null - , - - packed_at: item.packed_at - || - null - , - - shipped_at: item.shipped_at - || - null - , - - delivered_at: item.delivered_at - || - null - , - - subtotal_amount: item.subtotal_amount - || - null - , - - discount_amount: item.discount_amount - || - null - , - - tax_amount: item.tax_amount - || - null - , - - shipping_amount: item.shipping_amount - || - null - , - - total_amount: item.total_amount - || - null - , - - currency: item.currency - || - null - , - - shipping_name: item.shipping_name - || - null - , - - shipping_address: item.shipping_address - || - null - , - - billing_name: item.billing_name - || - null - , - - billing_address: item.billing_address - || - null - , - - notes_internal: item.notes_internal - || - null - , - - customer_note: item.customer_note - || - null - , - - tracking_number: item.tracking_number - || - null - , - - carrier: item.carrier - || - null - , - - importHash: item.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - createdAt: new Date(Date.now() + index * 1000), - })); - - // Bulk create items - const orders = await db.orders.bulkCreate(ordersData, { transaction }); - - // For each item created, replace relation files - - - return orders; - } - - static async update(id, data, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - - const orders = await db.orders.findByPk(id, {}, {transaction}); - - - - - const updatePayload = {}; - - if (data.order_number !== undefined) updatePayload.order_number = data.order_number; - - - if (data.order_status !== undefined) updatePayload.order_status = data.order_status; - - - if (data.fulfillment_status !== undefined) updatePayload.fulfillment_status = data.fulfillment_status; - - - if (data.payment_status !== undefined) updatePayload.payment_status = data.payment_status; - - - if (data.placed_at !== undefined) updatePayload.placed_at = data.placed_at; - - - if (data.packed_at !== undefined) updatePayload.packed_at = data.packed_at; - - - if (data.shipped_at !== undefined) updatePayload.shipped_at = data.shipped_at; - - - if (data.delivered_at !== undefined) updatePayload.delivered_at = data.delivered_at; - - - if (data.subtotal_amount !== undefined) updatePayload.subtotal_amount = data.subtotal_amount; - - - if (data.discount_amount !== undefined) updatePayload.discount_amount = data.discount_amount; - - - if (data.tax_amount !== undefined) updatePayload.tax_amount = data.tax_amount; - - - if (data.shipping_amount !== undefined) updatePayload.shipping_amount = data.shipping_amount; - - - if (data.total_amount !== undefined) updatePayload.total_amount = data.total_amount; - - - if (data.currency !== undefined) updatePayload.currency = data.currency; - - - if (data.shipping_name !== undefined) updatePayload.shipping_name = data.shipping_name; - - - if (data.shipping_address !== undefined) updatePayload.shipping_address = data.shipping_address; - - - if (data.billing_name !== undefined) updatePayload.billing_name = data.billing_name; - - - if (data.billing_address !== undefined) updatePayload.billing_address = data.billing_address; - - - if (data.notes_internal !== undefined) updatePayload.notes_internal = data.notes_internal; - - - if (data.customer_note !== undefined) updatePayload.customer_note = data.customer_note; - - - if (data.tracking_number !== undefined) updatePayload.tracking_number = data.tracking_number; - - - if (data.carrier !== undefined) updatePayload.carrier = data.carrier; - - - updatePayload.updatedById = currentUser.id; - - await orders.update(updatePayload, {transaction}); - - - - if (data.customer !== undefined) { - await orders.setCustomer( - - data.customer, - - { transaction } - ); - } - - if (data.assigned_to !== undefined) { - await orders.setAssigned_to( - - data.assigned_to, - - { transaction } - ); - } - - - - - - - - return orders; - } - - static async deleteByIds(ids, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const orders = await db.orders.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); - - await db.sequelize.transaction(async (transaction) => { - for (const record of orders) { - await record.update( - {deletedBy: currentUser.id}, - {transaction} - ); - } - for (const record of orders) { - await record.destroy({transaction}); - } - }); - - - return orders; - } - - static async remove(id, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - const orders = await db.orders.findByPk(id, options); - - await orders.update({ - deletedBy: currentUser.id - }, { - transaction, - }); - - await orders.destroy({ - transaction - }); - - return orders; - } - - static async findBy(where, options) { - const transaction = (options && options.transaction) || undefined; - - const orders = await db.orders.findOne( - { where }, - { transaction }, - ); - - if (!orders) { - return orders; - } - - const output = orders.get({plain: true}); - - - - - - - - - - output.order_items_order = await orders.getOrder_items_order({ - transaction - }); - - - output.payments_order = await orders.getPayments_order({ - transaction - }); - - - output.shipments_order = await orders.getShipments_order({ - transaction - }); - - - - output.customer = await orders.getCustomer({ - transaction - }); - - - output.assigned_to = await orders.getAssigned_to({ - transaction - }); - - - - return output; - } - - static async findAll( - filter, - options - ) { - const limit = filter.limit || 0; - let offset = 0; - let where = {}; - const currentPage = +filter.page; - - - - - - offset = currentPage * limit; - - const orderBy = null; - - const transaction = (options && options.transaction) || undefined; - - let include = [ - - { - model: db.customers, - as: 'customer', - - where: filter.customer ? { - [Op.or]: [ - { id: { [Op.in]: filter.customer.split('|').map(term => Utils.uuid(term)) } }, - { - full_name: { - [Op.or]: filter.customer.split('|').map(term => ({ [Op.iLike]: `%${term}%` })) - } - }, - ] - } : {}, - - }, - - { - model: db.users, - as: 'assigned_to', - - where: filter.assigned_to ? { - [Op.or]: [ - { id: { [Op.in]: filter.assigned_to.split('|').map(term => Utils.uuid(term)) } }, - { - firstName: { - [Op.or]: filter.assigned_to.split('|').map(term => ({ [Op.iLike]: `%${term}%` })) - } - }, - ] - } : {}, - - }, - - - - ]; - - if (filter) { - if (filter.id) { - where = { - ...where, - ['id']: Utils.uuid(filter.id), - }; - } - - - if (filter.order_number) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'orders', - 'order_number', - filter.order_number, - ), - }; - } - - if (filter.currency) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'orders', - 'currency', - filter.currency, - ), - }; - } - - if (filter.shipping_name) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'orders', - 'shipping_name', - filter.shipping_name, - ), - }; - } - - if (filter.shipping_address) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'orders', - 'shipping_address', - filter.shipping_address, - ), - }; - } - - if (filter.billing_name) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'orders', - 'billing_name', - filter.billing_name, - ), - }; - } - - if (filter.billing_address) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'orders', - 'billing_address', - filter.billing_address, - ), - }; - } - - if (filter.notes_internal) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'orders', - 'notes_internal', - filter.notes_internal, - ), - }; - } - - if (filter.customer_note) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'orders', - 'customer_note', - filter.customer_note, - ), - }; - } - - if (filter.tracking_number) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'orders', - 'tracking_number', - filter.tracking_number, - ), - }; - } - - if (filter.carrier) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'orders', - 'carrier', - filter.carrier, - ), - }; - } - - - - - - - if (filter.placed_atRange) { - const [start, end] = filter.placed_atRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - placed_at: { - ...where.placed_at, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - placed_at: { - ...where.placed_at, - [Op.lte]: end, - }, - }; - } - } - - if (filter.packed_atRange) { - const [start, end] = filter.packed_atRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - packed_at: { - ...where.packed_at, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - packed_at: { - ...where.packed_at, - [Op.lte]: end, - }, - }; - } - } - - if (filter.shipped_atRange) { - const [start, end] = filter.shipped_atRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - shipped_at: { - ...where.shipped_at, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - shipped_at: { - ...where.shipped_at, - [Op.lte]: end, - }, - }; - } - } - - if (filter.delivered_atRange) { - const [start, end] = filter.delivered_atRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - delivered_at: { - ...where.delivered_at, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - delivered_at: { - ...where.delivered_at, - [Op.lte]: end, - }, - }; - } - } - - if (filter.subtotal_amountRange) { - const [start, end] = filter.subtotal_amountRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - subtotal_amount: { - ...where.subtotal_amount, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - subtotal_amount: { - ...where.subtotal_amount, - [Op.lte]: end, - }, - }; - } - } - - if (filter.discount_amountRange) { - const [start, end] = filter.discount_amountRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - discount_amount: { - ...where.discount_amount, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - discount_amount: { - ...where.discount_amount, - [Op.lte]: end, - }, - }; - } - } - - if (filter.tax_amountRange) { - const [start, end] = filter.tax_amountRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - tax_amount: { - ...where.tax_amount, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - tax_amount: { - ...where.tax_amount, - [Op.lte]: end, - }, - }; - } - } - - if (filter.shipping_amountRange) { - const [start, end] = filter.shipping_amountRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - shipping_amount: { - ...where.shipping_amount, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - shipping_amount: { - ...where.shipping_amount, - [Op.lte]: end, - }, - }; - } - } - - if (filter.total_amountRange) { - const [start, end] = filter.total_amountRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - total_amount: { - ...where.total_amount, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - total_amount: { - ...where.total_amount, - [Op.lte]: end, - }, - }; - } - } - - - if (filter.active !== undefined) { - where = { - ...where, - active: filter.active === true || filter.active === 'true' - }; - } - - - if (filter.order_status) { - where = { - ...where, - order_status: filter.order_status, - }; - } - - if (filter.fulfillment_status) { - where = { - ...where, - fulfillment_status: filter.fulfillment_status, - }; - } - - if (filter.payment_status) { - where = { - ...where, - payment_status: filter.payment_status, - }; - } - - - - - - - - - - if (filter.createdAtRange) { - const [start, end] = filter.createdAtRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - ['createdAt']: { - ...where.createdAt, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - ['createdAt']: { - ...where.createdAt, - [Op.lte]: end, - }, - }; - } - } - } - - - - - const queryOptions = { - where, - include, - distinct: true, - order: filter.field && filter.sort - ? [[filter.field, filter.sort]] - : [['createdAt', 'desc']], - transaction: options?.transaction, - logging: console.log - }; - - if (!options?.countOnly) { - queryOptions.limit = limit ? Number(limit) : undefined; - queryOptions.offset = offset ? Number(offset) : undefined; - } - - try { - const { rows, count } = await db.orders.findAndCountAll(queryOptions); - - return { - rows: options?.countOnly ? [] : rows, - count: count - }; - } catch (error) { - console.error('Error executing query:', error); - throw error; - } - } - - static async findAllAutocomplete(query, limit, offset, ) { - let where = {}; - - - - if (query) { - where = { - [Op.or]: [ - { ['id']: Utils.uuid(query) }, - Utils.ilike( - 'orders', - 'order_number', - query, - ), - ], - }; - } - - const records = await db.orders.findAll({ - attributes: [ 'id', 'order_number' ], - where, - limit: limit ? Number(limit) : undefined, - offset: offset ? Number(offset) : undefined, - orderBy: [['order_number', 'ASC']], - }); - - return records.map((record) => ({ - id: record.id, - label: record.order_number, - })); - } - - -}; - diff --git a/backend/src/db/api/payments.js b/backend/src/db/api/payments.js deleted file mode 100644 index 44ed25d..0000000 --- a/backend/src/db/api/payments.js +++ /dev/null @@ -1,693 +0,0 @@ - -const db = require('../models'); -const FileDBApi = require('./file'); -const crypto = require('crypto'); -const Utils = require('../utils'); - - - -const Sequelize = db.Sequelize; -const Op = Sequelize.Op; - -module.exports = class PaymentsDBApi { - - - - static async create(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const payments = await db.payments.create( - { - id: data.id || undefined, - - payment_reference: data.payment_reference - || - null - , - - amount: data.amount - || - null - , - - currency: data.currency - || - null - , - - payment_method: data.payment_method - || - null - , - - payment_provider: data.payment_provider - || - null - , - - payment_status: data.payment_status - || - null - , - - initiated_at: data.initiated_at - || - null - , - - captured_at: data.captured_at - || - null - , - - refunded_at: data.refunded_at - || - null - , - - provider_transaction_id: data.provider_transaction_id - || - null - , - - failure_reason: data.failure_reason - || - null - , - - is_test: data.is_test - || - false - - , - - importHash: data.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - - await payments.setOrder( data.order || null, { - transaction, - }); - - - - - - - return payments; - } - - - static async bulkImport(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - // Prepare data - wrapping individual data transformations in a map() method - const paymentsData = data.map((item, index) => ({ - id: item.id || undefined, - - payment_reference: item.payment_reference - || - null - , - - amount: item.amount - || - null - , - - currency: item.currency - || - null - , - - payment_method: item.payment_method - || - null - , - - payment_provider: item.payment_provider - || - null - , - - payment_status: item.payment_status - || - null - , - - initiated_at: item.initiated_at - || - null - , - - captured_at: item.captured_at - || - null - , - - refunded_at: item.refunded_at - || - null - , - - provider_transaction_id: item.provider_transaction_id - || - null - , - - failure_reason: item.failure_reason - || - null - , - - is_test: item.is_test - || - false - - , - - importHash: item.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - createdAt: new Date(Date.now() + index * 1000), - })); - - // Bulk create items - const payments = await db.payments.bulkCreate(paymentsData, { transaction }); - - // For each item created, replace relation files - - - return payments; - } - - static async update(id, data, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - - const payments = await db.payments.findByPk(id, {}, {transaction}); - - - - - const updatePayload = {}; - - if (data.payment_reference !== undefined) updatePayload.payment_reference = data.payment_reference; - - - if (data.amount !== undefined) updatePayload.amount = data.amount; - - - if (data.currency !== undefined) updatePayload.currency = data.currency; - - - if (data.payment_method !== undefined) updatePayload.payment_method = data.payment_method; - - - if (data.payment_provider !== undefined) updatePayload.payment_provider = data.payment_provider; - - - if (data.payment_status !== undefined) updatePayload.payment_status = data.payment_status; - - - if (data.initiated_at !== undefined) updatePayload.initiated_at = data.initiated_at; - - - if (data.captured_at !== undefined) updatePayload.captured_at = data.captured_at; - - - if (data.refunded_at !== undefined) updatePayload.refunded_at = data.refunded_at; - - - if (data.provider_transaction_id !== undefined) updatePayload.provider_transaction_id = data.provider_transaction_id; - - - if (data.failure_reason !== undefined) updatePayload.failure_reason = data.failure_reason; - - - if (data.is_test !== undefined) updatePayload.is_test = data.is_test; - - - updatePayload.updatedById = currentUser.id; - - await payments.update(updatePayload, {transaction}); - - - - if (data.order !== undefined) { - await payments.setOrder( - - data.order, - - { transaction } - ); - } - - - - - - - - return payments; - } - - static async deleteByIds(ids, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const payments = await db.payments.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); - - await db.sequelize.transaction(async (transaction) => { - for (const record of payments) { - await record.update( - {deletedBy: currentUser.id}, - {transaction} - ); - } - for (const record of payments) { - await record.destroy({transaction}); - } - }); - - - return payments; - } - - static async remove(id, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - const payments = await db.payments.findByPk(id, options); - - await payments.update({ - deletedBy: currentUser.id - }, { - transaction, - }); - - await payments.destroy({ - transaction - }); - - return payments; - } - - static async findBy(where, options) { - const transaction = (options && options.transaction) || undefined; - - const payments = await db.payments.findOne( - { where }, - { transaction }, - ); - - if (!payments) { - return payments; - } - - const output = payments.get({plain: true}); - - - - - - - - - - - - - - output.order = await payments.getOrder({ - transaction - }); - - - - return output; - } - - static async findAll( - filter, - options - ) { - const limit = filter.limit || 0; - let offset = 0; - let where = {}; - const currentPage = +filter.page; - - - - - - offset = currentPage * limit; - - const orderBy = null; - - const transaction = (options && options.transaction) || undefined; - - let include = [ - - { - model: db.orders, - as: 'order', - - where: filter.order ? { - [Op.or]: [ - { id: { [Op.in]: filter.order.split('|').map(term => Utils.uuid(term)) } }, - { - order_number: { - [Op.or]: filter.order.split('|').map(term => ({ [Op.iLike]: `%${term}%` })) - } - }, - ] - } : {}, - - }, - - - - ]; - - if (filter) { - if (filter.id) { - where = { - ...where, - ['id']: Utils.uuid(filter.id), - }; - } - - - if (filter.payment_reference) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'payments', - 'payment_reference', - filter.payment_reference, - ), - }; - } - - if (filter.currency) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'payments', - 'currency', - filter.currency, - ), - }; - } - - if (filter.provider_transaction_id) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'payments', - 'provider_transaction_id', - filter.provider_transaction_id, - ), - }; - } - - if (filter.failure_reason) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'payments', - 'failure_reason', - filter.failure_reason, - ), - }; - } - - - - - if (filter.calendarStart && filter.calendarEnd) { - where = { - ...where, - [Op.or]: [ - { - initiated_at: { - [Op.between]: [filter.calendarStart, filter.calendarEnd], - }, - }, - { - captured_at: { - [Op.between]: [filter.calendarStart, filter.calendarEnd], - }, - }, - ], - }; - } - - - - if (filter.amountRange) { - const [start, end] = filter.amountRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - amount: { - ...where.amount, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - amount: { - ...where.amount, - [Op.lte]: end, - }, - }; - } - } - - if (filter.initiated_atRange) { - const [start, end] = filter.initiated_atRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - initiated_at: { - ...where.initiated_at, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - initiated_at: { - ...where.initiated_at, - [Op.lte]: end, - }, - }; - } - } - - if (filter.captured_atRange) { - const [start, end] = filter.captured_atRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - captured_at: { - ...where.captured_at, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - captured_at: { - ...where.captured_at, - [Op.lte]: end, - }, - }; - } - } - - if (filter.refunded_atRange) { - const [start, end] = filter.refunded_atRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - refunded_at: { - ...where.refunded_at, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - refunded_at: { - ...where.refunded_at, - [Op.lte]: end, - }, - }; - } - } - - - if (filter.active !== undefined) { - where = { - ...where, - active: filter.active === true || filter.active === 'true' - }; - } - - - if (filter.payment_method) { - where = { - ...where, - payment_method: filter.payment_method, - }; - } - - if (filter.payment_provider) { - where = { - ...where, - payment_provider: filter.payment_provider, - }; - } - - if (filter.payment_status) { - where = { - ...where, - payment_status: filter.payment_status, - }; - } - - if (filter.is_test) { - where = { - ...where, - is_test: filter.is_test, - }; - } - - - - - - - - if (filter.createdAtRange) { - const [start, end] = filter.createdAtRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - ['createdAt']: { - ...where.createdAt, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - ['createdAt']: { - ...where.createdAt, - [Op.lte]: end, - }, - }; - } - } - } - - - - - const queryOptions = { - where, - include, - distinct: true, - order: filter.field && filter.sort - ? [[filter.field, filter.sort]] - : [['createdAt', 'desc']], - transaction: options?.transaction, - logging: console.log - }; - - if (!options?.countOnly) { - queryOptions.limit = limit ? Number(limit) : undefined; - queryOptions.offset = offset ? Number(offset) : undefined; - } - - try { - const { rows, count } = await db.payments.findAndCountAll(queryOptions); - - return { - rows: options?.countOnly ? [] : rows, - count: count - }; - } catch (error) { - console.error('Error executing query:', error); - throw error; - } - } - - static async findAllAutocomplete(query, limit, offset, ) { - let where = {}; - - - - if (query) { - where = { - [Op.or]: [ - { ['id']: Utils.uuid(query) }, - Utils.ilike( - 'payments', - 'payment_reference', - query, - ), - ], - }; - } - - const records = await db.payments.findAll({ - attributes: [ 'id', 'payment_reference' ], - where, - limit: limit ? Number(limit) : undefined, - offset: offset ? Number(offset) : undefined, - orderBy: [['payment_reference', 'ASC']], - }); - - return records.map((record) => ({ - id: record.id, - label: record.payment_reference, - })); - } - - -}; - diff --git a/backend/src/db/api/permissions.js b/backend/src/db/api/permissions.js deleted file mode 100644 index 2625f43..0000000 --- a/backend/src/db/api/permissions.js +++ /dev/null @@ -1,336 +0,0 @@ - -const db = require('../models'); -const FileDBApi = require('./file'); -const crypto = require('crypto'); -const Utils = require('../utils'); - - - -const Sequelize = db.Sequelize; -const Op = Sequelize.Op; - -module.exports = class PermissionsDBApi { - - - - static async create(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const permissions = await db.permissions.create( - { - id: data.id || undefined, - - name: data.name - || - null - , - - importHash: data.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - - - - - - - return permissions; - } - - - static async bulkImport(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - // Prepare data - wrapping individual data transformations in a map() method - const permissionsData = data.map((item, index) => ({ - id: item.id || undefined, - - name: item.name - || - null - , - - importHash: item.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - createdAt: new Date(Date.now() + index * 1000), - })); - - // Bulk create items - const permissions = await db.permissions.bulkCreate(permissionsData, { transaction }); - - // For each item created, replace relation files - - - return permissions; - } - - static async update(id, data, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - - const permissions = await db.permissions.findByPk(id, {}, {transaction}); - - - - - const updatePayload = {}; - - if (data.name !== undefined) updatePayload.name = data.name; - - - updatePayload.updatedById = currentUser.id; - - await permissions.update(updatePayload, {transaction}); - - - - - - - - - - return permissions; - } - - static async deleteByIds(ids, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const permissions = await db.permissions.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); - - await db.sequelize.transaction(async (transaction) => { - for (const record of permissions) { - await record.update( - {deletedBy: currentUser.id}, - {transaction} - ); - } - for (const record of permissions) { - await record.destroy({transaction}); - } - }); - - - return permissions; - } - - static async remove(id, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - const permissions = await db.permissions.findByPk(id, options); - - await permissions.update({ - deletedBy: currentUser.id - }, { - transaction, - }); - - await permissions.destroy({ - transaction - }); - - return permissions; - } - - static async findBy(where, options) { - const transaction = (options && options.transaction) || undefined; - - const permissions = await db.permissions.findOne( - { where }, - { transaction }, - ); - - if (!permissions) { - return permissions; - } - - const output = permissions.get({plain: true}); - - - - - - - - - - - - - - - return output; - } - - static async findAll( - filter, - options - ) { - const limit = filter.limit || 0; - let offset = 0; - let where = {}; - const currentPage = +filter.page; - - - - - - offset = currentPage * limit; - - const orderBy = null; - - const transaction = (options && options.transaction) || undefined; - - let include = [ - - - - ]; - - if (filter) { - if (filter.id) { - where = { - ...where, - ['id']: Utils.uuid(filter.id), - }; - } - - - if (filter.name) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'permissions', - 'name', - filter.name, - ), - }; - } - - - - - - - - if (filter.active !== undefined) { - where = { - ...where, - active: filter.active === true || filter.active === 'true' - }; - } - - - - - - - if (filter.createdAtRange) { - const [start, end] = filter.createdAtRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - ['createdAt']: { - ...where.createdAt, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - ['createdAt']: { - ...where.createdAt, - [Op.lte]: end, - }, - }; - } - } - } - - - - - const queryOptions = { - where, - include, - distinct: true, - order: filter.field && filter.sort - ? [[filter.field, filter.sort]] - : [['createdAt', 'desc']], - transaction: options?.transaction, - logging: console.log - }; - - if (!options?.countOnly) { - queryOptions.limit = limit ? Number(limit) : undefined; - queryOptions.offset = offset ? Number(offset) : undefined; - } - - try { - const { rows, count } = await db.permissions.findAndCountAll(queryOptions); - - return { - rows: options?.countOnly ? [] : rows, - count: count - }; - } catch (error) { - console.error('Error executing query:', error); - throw error; - } - } - - static async findAllAutocomplete(query, limit, offset, ) { - let where = {}; - - - - if (query) { - where = { - [Op.or]: [ - { ['id']: Utils.uuid(query) }, - Utils.ilike( - 'permissions', - 'name', - query, - ), - ], - }; - } - - const records = await db.permissions.findAll({ - attributes: [ 'id', 'name' ], - where, - limit: limit ? Number(limit) : undefined, - offset: offset ? Number(offset) : undefined, - orderBy: [['name', 'ASC']], - }); - - return records.map((record) => ({ - id: record.id, - label: record.name, - })); - } - - -}; - diff --git a/backend/src/db/api/product_categories.js b/backend/src/db/api/product_categories.js deleted file mode 100644 index f0bb4a4..0000000 --- a/backend/src/db/api/product_categories.js +++ /dev/null @@ -1,447 +0,0 @@ - -const db = require('../models'); -const FileDBApi = require('./file'); -const crypto = require('crypto'); -const Utils = require('../utils'); - - - -const Sequelize = db.Sequelize; -const Op = Sequelize.Op; - -module.exports = class Product_categoriesDBApi { - - - - static async create(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const product_categories = await db.product_categories.create( - { - id: data.id || undefined, - - name: data.name - || - null - , - - slug: data.slug - || - null - , - - description: data.description - || - null - , - - is_active: data.is_active - || - false - - , - - importHash: data.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - - await product_categories.setParent_category( data.parent_category || null, { - transaction, - }); - - - - - - - return product_categories; - } - - - static async bulkImport(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - // Prepare data - wrapping individual data transformations in a map() method - const product_categoriesData = data.map((item, index) => ({ - id: item.id || undefined, - - name: item.name - || - null - , - - slug: item.slug - || - null - , - - description: item.description - || - null - , - - is_active: item.is_active - || - false - - , - - importHash: item.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - createdAt: new Date(Date.now() + index * 1000), - })); - - // Bulk create items - const product_categories = await db.product_categories.bulkCreate(product_categoriesData, { transaction }); - - // For each item created, replace relation files - - - return product_categories; - } - - static async update(id, data, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - - const product_categories = await db.product_categories.findByPk(id, {}, {transaction}); - - - - - const updatePayload = {}; - - if (data.name !== undefined) updatePayload.name = data.name; - - - if (data.slug !== undefined) updatePayload.slug = data.slug; - - - if (data.description !== undefined) updatePayload.description = data.description; - - - if (data.is_active !== undefined) updatePayload.is_active = data.is_active; - - - updatePayload.updatedById = currentUser.id; - - await product_categories.update(updatePayload, {transaction}); - - - - if (data.parent_category !== undefined) { - await product_categories.setParent_category( - - data.parent_category, - - { transaction } - ); - } - - - - - - - - return product_categories; - } - - static async deleteByIds(ids, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const product_categories = await db.product_categories.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); - - await db.sequelize.transaction(async (transaction) => { - for (const record of product_categories) { - await record.update( - {deletedBy: currentUser.id}, - {transaction} - ); - } - for (const record of product_categories) { - await record.destroy({transaction}); - } - }); - - - return product_categories; - } - - static async remove(id, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - const product_categories = await db.product_categories.findByPk(id, options); - - await product_categories.update({ - deletedBy: currentUser.id - }, { - transaction, - }); - - await product_categories.destroy({ - transaction - }); - - return product_categories; - } - - static async findBy(where, options) { - const transaction = (options && options.transaction) || undefined; - - const product_categories = await db.product_categories.findOne( - { where }, - { transaction }, - ); - - if (!product_categories) { - return product_categories; - } - - const output = product_categories.get({plain: true}); - - - - - - - - output.products_category = await product_categories.getProducts_category({ - transaction - }); - - - - - - - - output.parent_category = await product_categories.getParent_category({ - transaction - }); - - - - return output; - } - - static async findAll( - filter, - options - ) { - const limit = filter.limit || 0; - let offset = 0; - let where = {}; - const currentPage = +filter.page; - - - - - - offset = currentPage * limit; - - const orderBy = null; - - const transaction = (options && options.transaction) || undefined; - - let include = [ - - { - model: db.product_categories, - as: 'parent_category', - - where: filter.parent_category ? { - [Op.or]: [ - { id: { [Op.in]: filter.parent_category.split('|').map(term => Utils.uuid(term)) } }, - { - name: { - [Op.or]: filter.parent_category.split('|').map(term => ({ [Op.iLike]: `%${term}%` })) - } - }, - ] - } : {}, - - }, - - - - ]; - - if (filter) { - if (filter.id) { - where = { - ...where, - ['id']: Utils.uuid(filter.id), - }; - } - - - if (filter.name) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'product_categories', - 'name', - filter.name, - ), - }; - } - - if (filter.slug) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'product_categories', - 'slug', - filter.slug, - ), - }; - } - - if (filter.description) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'product_categories', - 'description', - filter.description, - ), - }; - } - - - - - - - - if (filter.active !== undefined) { - where = { - ...where, - active: filter.active === true || filter.active === 'true' - }; - } - - - if (filter.is_active) { - where = { - ...where, - is_active: filter.is_active, - }; - } - - - - - - - - if (filter.createdAtRange) { - const [start, end] = filter.createdAtRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - ['createdAt']: { - ...where.createdAt, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - ['createdAt']: { - ...where.createdAt, - [Op.lte]: end, - }, - }; - } - } - } - - - - - const queryOptions = { - where, - include, - distinct: true, - order: filter.field && filter.sort - ? [[filter.field, filter.sort]] - : [['createdAt', 'desc']], - transaction: options?.transaction, - logging: console.log - }; - - if (!options?.countOnly) { - queryOptions.limit = limit ? Number(limit) : undefined; - queryOptions.offset = offset ? Number(offset) : undefined; - } - - try { - const { rows, count } = await db.product_categories.findAndCountAll(queryOptions); - - return { - rows: options?.countOnly ? [] : rows, - count: count - }; - } catch (error) { - console.error('Error executing query:', error); - throw error; - } - } - - static async findAllAutocomplete(query, limit, offset, ) { - let where = {}; - - - - if (query) { - where = { - [Op.or]: [ - { ['id']: Utils.uuid(query) }, - Utils.ilike( - 'product_categories', - 'name', - query, - ), - ], - }; - } - - const records = await db.product_categories.findAll({ - attributes: [ 'id', 'name' ], - where, - limit: limit ? Number(limit) : undefined, - offset: offset ? Number(offset) : undefined, - orderBy: [['name', 'ASC']], - }); - - return records.map((record) => ({ - id: record.id, - label: record.name, - })); - } - - -}; - diff --git a/backend/src/db/api/products.js b/backend/src/db/api/products.js deleted file mode 100644 index 7ac039b..0000000 --- a/backend/src/db/api/products.js +++ /dev/null @@ -1,821 +0,0 @@ - -const db = require('../models'); -const FileDBApi = require('./file'); -const crypto = require('crypto'); -const Utils = require('../utils'); - - - -const Sequelize = db.Sequelize; -const Op = Sequelize.Op; - -module.exports = class ProductsDBApi { - - - - static async create(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const products = await db.products.create( - { - id: data.id || undefined, - - name: data.name - || - null - , - - sku: data.sku - || - null - , - - barcode: data.barcode - || - null - , - - short_description: data.short_description - || - null - , - - description: data.description - || - null - , - - price: data.price - || - null - , - - compare_at_price: data.compare_at_price - || - null - , - - cost: data.cost - || - null - , - - stock_on_hand: data.stock_on_hand - || - null - , - - reorder_point: data.reorder_point - || - null - , - - product_status: data.product_status - || - null - , - - track_inventory: data.track_inventory - || - false - - , - - weight: data.weight - || - null - , - - importHash: data.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - - await products.setCategory( data.category || null, { - transaction, - }); - - - - - - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.products.getTableName(), - belongsToColumn: 'images', - belongsToId: products.id, - }, - data.images, - options, - ); - - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.products.getTableName(), - belongsToColumn: 'attachments', - belongsToId: products.id, - }, - data.attachments, - options, - ); - - - return products; - } - - - static async bulkImport(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - // Prepare data - wrapping individual data transformations in a map() method - const productsData = data.map((item, index) => ({ - id: item.id || undefined, - - name: item.name - || - null - , - - sku: item.sku - || - null - , - - barcode: item.barcode - || - null - , - - short_description: item.short_description - || - null - , - - description: item.description - || - null - , - - price: item.price - || - null - , - - compare_at_price: item.compare_at_price - || - null - , - - cost: item.cost - || - null - , - - stock_on_hand: item.stock_on_hand - || - null - , - - reorder_point: item.reorder_point - || - null - , - - product_status: item.product_status - || - null - , - - track_inventory: item.track_inventory - || - false - - , - - weight: item.weight - || - null - , - - importHash: item.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - createdAt: new Date(Date.now() + index * 1000), - })); - - // Bulk create items - const products = await db.products.bulkCreate(productsData, { transaction }); - - // For each item created, replace relation files - - for (let i = 0; i < products.length; i++) { - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.products.getTableName(), - belongsToColumn: 'images', - belongsToId: products[i].id, - }, - data[i].images, - options, - ); - } - - for (let i = 0; i < products.length; i++) { - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.products.getTableName(), - belongsToColumn: 'attachments', - belongsToId: products[i].id, - }, - data[i].attachments, - options, - ); - } - - - return products; - } - - static async update(id, data, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - - const products = await db.products.findByPk(id, {}, {transaction}); - - - - - const updatePayload = {}; - - if (data.name !== undefined) updatePayload.name = data.name; - - - if (data.sku !== undefined) updatePayload.sku = data.sku; - - - if (data.barcode !== undefined) updatePayload.barcode = data.barcode; - - - if (data.short_description !== undefined) updatePayload.short_description = data.short_description; - - - if (data.description !== undefined) updatePayload.description = data.description; - - - if (data.price !== undefined) updatePayload.price = data.price; - - - if (data.compare_at_price !== undefined) updatePayload.compare_at_price = data.compare_at_price; - - - if (data.cost !== undefined) updatePayload.cost = data.cost; - - - if (data.stock_on_hand !== undefined) updatePayload.stock_on_hand = data.stock_on_hand; - - - if (data.reorder_point !== undefined) updatePayload.reorder_point = data.reorder_point; - - - if (data.product_status !== undefined) updatePayload.product_status = data.product_status; - - - if (data.track_inventory !== undefined) updatePayload.track_inventory = data.track_inventory; - - - if (data.weight !== undefined) updatePayload.weight = data.weight; - - - updatePayload.updatedById = currentUser.id; - - await products.update(updatePayload, {transaction}); - - - - if (data.category !== undefined) { - await products.setCategory( - - data.category, - - { transaction } - ); - } - - - - - - - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.products.getTableName(), - belongsToColumn: 'images', - belongsToId: products.id, - }, - data.images, - options, - ); - - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.products.getTableName(), - belongsToColumn: 'attachments', - belongsToId: products.id, - }, - data.attachments, - options, - ); - - - return products; - } - - static async deleteByIds(ids, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const products = await db.products.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); - - await db.sequelize.transaction(async (transaction) => { - for (const record of products) { - await record.update( - {deletedBy: currentUser.id}, - {transaction} - ); - } - for (const record of products) { - await record.destroy({transaction}); - } - }); - - - return products; - } - - static async remove(id, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - const products = await db.products.findByPk(id, options); - - await products.update({ - deletedBy: currentUser.id - }, { - transaction, - }); - - await products.destroy({ - transaction - }); - - return products; - } - - static async findBy(where, options) { - const transaction = (options && options.transaction) || undefined; - - const products = await db.products.findOne( - { where }, - { transaction }, - ); - - if (!products) { - return products; - } - - const output = products.get({plain: true}); - - - - - - - - - - output.order_items_product = await products.getOrder_items_product({ - transaction - }); - - - - - - output.category = await products.getCategory({ - transaction - }); - - - output.images = await products.getImages({ - transaction - }); - - - output.attachments = await products.getAttachments({ - transaction - }); - - - - return output; - } - - static async findAll( - filter, - options - ) { - const limit = filter.limit || 0; - let offset = 0; - let where = {}; - const currentPage = +filter.page; - - - - - - offset = currentPage * limit; - - const orderBy = null; - - const transaction = (options && options.transaction) || undefined; - - let include = [ - - { - model: db.product_categories, - as: 'category', - - where: filter.category ? { - [Op.or]: [ - { id: { [Op.in]: filter.category.split('|').map(term => Utils.uuid(term)) } }, - { - name: { - [Op.or]: filter.category.split('|').map(term => ({ [Op.iLike]: `%${term}%` })) - } - }, - ] - } : {}, - - }, - - - - { - model: db.file, - as: 'images', - }, - - { - model: db.file, - as: 'attachments', - }, - - ]; - - if (filter) { - if (filter.id) { - where = { - ...where, - ['id']: Utils.uuid(filter.id), - }; - } - - - if (filter.name) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'products', - 'name', - filter.name, - ), - }; - } - - if (filter.sku) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'products', - 'sku', - filter.sku, - ), - }; - } - - if (filter.barcode) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'products', - 'barcode', - filter.barcode, - ), - }; - } - - if (filter.short_description) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'products', - 'short_description', - filter.short_description, - ), - }; - } - - if (filter.description) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'products', - 'description', - filter.description, - ), - }; - } - - - - - - - if (filter.priceRange) { - const [start, end] = filter.priceRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - price: { - ...where.price, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - price: { - ...where.price, - [Op.lte]: end, - }, - }; - } - } - - if (filter.compare_at_priceRange) { - const [start, end] = filter.compare_at_priceRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - compare_at_price: { - ...where.compare_at_price, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - compare_at_price: { - ...where.compare_at_price, - [Op.lte]: end, - }, - }; - } - } - - if (filter.costRange) { - const [start, end] = filter.costRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - cost: { - ...where.cost, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - cost: { - ...where.cost, - [Op.lte]: end, - }, - }; - } - } - - if (filter.stock_on_handRange) { - const [start, end] = filter.stock_on_handRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - stock_on_hand: { - ...where.stock_on_hand, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - stock_on_hand: { - ...where.stock_on_hand, - [Op.lte]: end, - }, - }; - } - } - - if (filter.reorder_pointRange) { - const [start, end] = filter.reorder_pointRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - reorder_point: { - ...where.reorder_point, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - reorder_point: { - ...where.reorder_point, - [Op.lte]: end, - }, - }; - } - } - - if (filter.weightRange) { - const [start, end] = filter.weightRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - weight: { - ...where.weight, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - weight: { - ...where.weight, - [Op.lte]: end, - }, - }; - } - } - - - if (filter.active !== undefined) { - where = { - ...where, - active: filter.active === true || filter.active === 'true' - }; - } - - - if (filter.product_status) { - where = { - ...where, - product_status: filter.product_status, - }; - } - - if (filter.track_inventory) { - where = { - ...where, - track_inventory: filter.track_inventory, - }; - } - - - - - - - - if (filter.createdAtRange) { - const [start, end] = filter.createdAtRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - ['createdAt']: { - ...where.createdAt, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - ['createdAt']: { - ...where.createdAt, - [Op.lte]: end, - }, - }; - } - } - } - - - - - const queryOptions = { - where, - include, - distinct: true, - order: filter.field && filter.sort - ? [[filter.field, filter.sort]] - : [['createdAt', 'desc']], - transaction: options?.transaction, - logging: console.log - }; - - if (!options?.countOnly) { - queryOptions.limit = limit ? Number(limit) : undefined; - queryOptions.offset = offset ? Number(offset) : undefined; - } - - try { - const { rows, count } = await db.products.findAndCountAll(queryOptions); - - return { - rows: options?.countOnly ? [] : rows, - count: count - }; - } catch (error) { - console.error('Error executing query:', error); - throw error; - } - } - - static async findAllAutocomplete(query, limit, offset, ) { - let where = {}; - - - - if (query) { - where = { - [Op.or]: [ - { ['id']: Utils.uuid(query) }, - Utils.ilike( - 'products', - 'name', - query, - ), - ], - }; - } - - const records = await db.products.findAll({ - attributes: [ 'id', 'name' ], - where, - limit: limit ? Number(limit) : undefined, - offset: offset ? Number(offset) : undefined, - orderBy: [['name', 'ASC']], - }); - - return records.map((record) => ({ - id: record.id, - label: record.name, - })); - } - - -}; - diff --git a/backend/src/db/api/roles.js b/backend/src/db/api/roles.js deleted file mode 100644 index 9c68b9e..0000000 --- a/backend/src/db/api/roles.js +++ /dev/null @@ -1,406 +0,0 @@ - -const db = require('../models'); -const FileDBApi = require('./file'); -const crypto = require('crypto'); -const Utils = require('../utils'); - - - -const Sequelize = db.Sequelize; -const Op = Sequelize.Op; - -module.exports = class RolesDBApi { - - - - static async create(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const roles = await db.roles.create( - { - id: data.id || undefined, - - name: data.name - || - null - , - - role_customization: data.role_customization - || - null - , - - importHash: data.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - - - - await roles.setPermissions(data.permissions || [], { - transaction, - }); - - - - - return roles; - } - - - static async bulkImport(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - // Prepare data - wrapping individual data transformations in a map() method - const rolesData = data.map((item, index) => ({ - id: item.id || undefined, - - name: item.name - || - null - , - - role_customization: item.role_customization - || - null - , - - importHash: item.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - createdAt: new Date(Date.now() + index * 1000), - })); - - // Bulk create items - const roles = await db.roles.bulkCreate(rolesData, { transaction }); - - // For each item created, replace relation files - - - return roles; - } - - static async update(id, data, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - - const roles = await db.roles.findByPk(id, {}, {transaction}); - - - - - const updatePayload = {}; - - if (data.name !== undefined) updatePayload.name = data.name; - - - if (data.role_customization !== undefined) updatePayload.role_customization = data.role_customization; - - - updatePayload.updatedById = currentUser.id; - - await roles.update(updatePayload, {transaction}); - - - - - - - if (data.permissions !== undefined) { - await roles.setPermissions(data.permissions, { transaction }); - } - - - - - return roles; - } - - static async deleteByIds(ids, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const roles = await db.roles.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); - - await db.sequelize.transaction(async (transaction) => { - for (const record of roles) { - await record.update( - {deletedBy: currentUser.id}, - {transaction} - ); - } - for (const record of roles) { - await record.destroy({transaction}); - } - }); - - - return roles; - } - - static async remove(id, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - const roles = await db.roles.findByPk(id, options); - - await roles.update({ - deletedBy: currentUser.id - }, { - transaction, - }); - - await roles.destroy({ - transaction - }); - - return roles; - } - - static async findBy(where, options) { - const transaction = (options && options.transaction) || undefined; - - const roles = await db.roles.findOne( - { where }, - { transaction }, - ); - - if (!roles) { - return roles; - } - - const output = roles.get({plain: true}); - - - output.users_app_role = await roles.getUsers_app_role({ - transaction - }); - - - - - - - - - - - - - output.permissions = await roles.getPermissions({ - transaction - }); - - - - return output; - } - - static async findAll( - filter, - options - ) { - const limit = filter.limit || 0; - let offset = 0; - let where = {}; - const currentPage = +filter.page; - - - - - - offset = currentPage * limit; - - const orderBy = null; - - const transaction = (options && options.transaction) || undefined; - - let include = [ - - - { - model: db.permissions, - as: 'permissions', - required: false, - }, - - - ]; - - if (filter) { - if (filter.id) { - where = { - ...where, - ['id']: Utils.uuid(filter.id), - }; - } - - - if (filter.name) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'roles', - 'name', - filter.name, - ), - }; - } - - if (filter.role_customization) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'roles', - 'role_customization', - filter.role_customization, - ), - }; - } - - - - - - - - if (filter.active !== undefined) { - where = { - ...where, - active: filter.active === true || filter.active === 'true' - }; - } - - - - - - if (filter.permissions) { - const searchTerms = filter.permissions.split('|'); - - include = [ - { - model: db.permissions, - as: 'permissions_filter', - required: searchTerms.length > 0, - where: searchTerms.length > 0 ? { - [Op.or]: [ - { id: { [Op.in]: searchTerms.map(term => Utils.uuid(term)) } }, - { - name: { - [Op.or]: searchTerms.map(term => ({ [Op.iLike]: `%${term}%` })) - } - } - ] - } : undefined - }, - ...include, - ] - } - - - if (filter.createdAtRange) { - const [start, end] = filter.createdAtRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - ['createdAt']: { - ...where.createdAt, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - ['createdAt']: { - ...where.createdAt, - [Op.lte]: end, - }, - }; - } - } - } - - - - - const queryOptions = { - where, - include, - distinct: true, - order: filter.field && filter.sort - ? [[filter.field, filter.sort]] - : [['createdAt', 'desc']], - transaction: options?.transaction, - logging: console.log - }; - - if (!options?.countOnly) { - queryOptions.limit = limit ? Number(limit) : undefined; - queryOptions.offset = offset ? Number(offset) : undefined; - } - - try { - const { rows, count } = await db.roles.findAndCountAll(queryOptions); - - return { - rows: options?.countOnly ? [] : rows, - count: count - }; - } catch (error) { - console.error('Error executing query:', error); - throw error; - } - } - - static async findAllAutocomplete(query, limit, offset, ) { - let where = {}; - - - - if (query) { - where = { - [Op.or]: [ - { ['id']: Utils.uuid(query) }, - Utils.ilike( - 'roles', - 'name', - query, - ), - ], - }; - } - - const records = await db.roles.findAll({ - attributes: [ 'id', 'name' ], - where, - limit: limit ? Number(limit) : undefined, - offset: offset ? Number(offset) : undefined, - orderBy: [['name', 'ASC']], - }); - - return records.map((record) => ({ - id: record.id, - label: record.name, - })); - } - - -}; - diff --git a/backend/src/db/api/shipments.js b/backend/src/db/api/shipments.js deleted file mode 100644 index bd2b6cf..0000000 --- a/backend/src/db/api/shipments.js +++ /dev/null @@ -1,703 +0,0 @@ - -const db = require('../models'); -const FileDBApi = require('./file'); -const crypto = require('crypto'); -const Utils = require('../utils'); - - - -const Sequelize = db.Sequelize; -const Op = Sequelize.Op; - -module.exports = class ShipmentsDBApi { - - - - static async create(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const shipments = await db.shipments.create( - { - id: data.id || undefined, - - shipment_number: data.shipment_number - || - null - , - - shipment_status: data.shipment_status - || - null - , - - carrier: data.carrier - || - null - , - - service_level: data.service_level - || - null - , - - tracking_number: data.tracking_number - || - null - , - - packed_at: data.packed_at - || - null - , - - shipped_at: data.shipped_at - || - null - , - - delivered_at: data.delivered_at - || - null - , - - shipping_cost: data.shipping_cost - || - null - , - - label_url: data.label_url - || - null - , - - notes: data.notes - || - null - , - - importHash: data.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - - await shipments.setOrder( data.order || null, { - transaction, - }); - - - - - - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.shipments.getTableName(), - belongsToColumn: 'shipping_documents', - belongsToId: shipments.id, - }, - data.shipping_documents, - options, - ); - - - return shipments; - } - - - static async bulkImport(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - // Prepare data - wrapping individual data transformations in a map() method - const shipmentsData = data.map((item, index) => ({ - id: item.id || undefined, - - shipment_number: item.shipment_number - || - null - , - - shipment_status: item.shipment_status - || - null - , - - carrier: item.carrier - || - null - , - - service_level: item.service_level - || - null - , - - tracking_number: item.tracking_number - || - null - , - - packed_at: item.packed_at - || - null - , - - shipped_at: item.shipped_at - || - null - , - - delivered_at: item.delivered_at - || - null - , - - shipping_cost: item.shipping_cost - || - null - , - - label_url: item.label_url - || - null - , - - notes: item.notes - || - null - , - - importHash: item.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - createdAt: new Date(Date.now() + index * 1000), - })); - - // Bulk create items - const shipments = await db.shipments.bulkCreate(shipmentsData, { transaction }); - - // For each item created, replace relation files - - for (let i = 0; i < shipments.length; i++) { - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.shipments.getTableName(), - belongsToColumn: 'shipping_documents', - belongsToId: shipments[i].id, - }, - data[i].shipping_documents, - options, - ); - } - - - return shipments; - } - - static async update(id, data, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - - const shipments = await db.shipments.findByPk(id, {}, {transaction}); - - - - - const updatePayload = {}; - - if (data.shipment_number !== undefined) updatePayload.shipment_number = data.shipment_number; - - - if (data.shipment_status !== undefined) updatePayload.shipment_status = data.shipment_status; - - - if (data.carrier !== undefined) updatePayload.carrier = data.carrier; - - - if (data.service_level !== undefined) updatePayload.service_level = data.service_level; - - - if (data.tracking_number !== undefined) updatePayload.tracking_number = data.tracking_number; - - - if (data.packed_at !== undefined) updatePayload.packed_at = data.packed_at; - - - if (data.shipped_at !== undefined) updatePayload.shipped_at = data.shipped_at; - - - if (data.delivered_at !== undefined) updatePayload.delivered_at = data.delivered_at; - - - if (data.shipping_cost !== undefined) updatePayload.shipping_cost = data.shipping_cost; - - - if (data.label_url !== undefined) updatePayload.label_url = data.label_url; - - - if (data.notes !== undefined) updatePayload.notes = data.notes; - - - updatePayload.updatedById = currentUser.id; - - await shipments.update(updatePayload, {transaction}); - - - - if (data.order !== undefined) { - await shipments.setOrder( - - data.order, - - { transaction } - ); - } - - - - - - - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.shipments.getTableName(), - belongsToColumn: 'shipping_documents', - belongsToId: shipments.id, - }, - data.shipping_documents, - options, - ); - - - return shipments; - } - - static async deleteByIds(ids, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const shipments = await db.shipments.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); - - await db.sequelize.transaction(async (transaction) => { - for (const record of shipments) { - await record.update( - {deletedBy: currentUser.id}, - {transaction} - ); - } - for (const record of shipments) { - await record.destroy({transaction}); - } - }); - - - return shipments; - } - - static async remove(id, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - const shipments = await db.shipments.findByPk(id, options); - - await shipments.update({ - deletedBy: currentUser.id - }, { - transaction, - }); - - await shipments.destroy({ - transaction - }); - - return shipments; - } - - static async findBy(where, options) { - const transaction = (options && options.transaction) || undefined; - - const shipments = await db.shipments.findOne( - { where }, - { transaction }, - ); - - if (!shipments) { - return shipments; - } - - const output = shipments.get({plain: true}); - - - - - - - - - - - - - - output.order = await shipments.getOrder({ - transaction - }); - - - output.shipping_documents = await shipments.getShipping_documents({ - transaction - }); - - - - return output; - } - - static async findAll( - filter, - options - ) { - const limit = filter.limit || 0; - let offset = 0; - let where = {}; - const currentPage = +filter.page; - - - - - - offset = currentPage * limit; - - const orderBy = null; - - const transaction = (options && options.transaction) || undefined; - - let include = [ - - { - model: db.orders, - as: 'order', - - where: filter.order ? { - [Op.or]: [ - { id: { [Op.in]: filter.order.split('|').map(term => Utils.uuid(term)) } }, - { - order_number: { - [Op.or]: filter.order.split('|').map(term => ({ [Op.iLike]: `%${term}%` })) - } - }, - ] - } : {}, - - }, - - - - { - model: db.file, - as: 'shipping_documents', - }, - - ]; - - if (filter) { - if (filter.id) { - where = { - ...where, - ['id']: Utils.uuid(filter.id), - }; - } - - - if (filter.shipment_number) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'shipments', - 'shipment_number', - filter.shipment_number, - ), - }; - } - - if (filter.carrier) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'shipments', - 'carrier', - filter.carrier, - ), - }; - } - - if (filter.service_level) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'shipments', - 'service_level', - filter.service_level, - ), - }; - } - - if (filter.tracking_number) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'shipments', - 'tracking_number', - filter.tracking_number, - ), - }; - } - - if (filter.label_url) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'shipments', - 'label_url', - filter.label_url, - ), - }; - } - - if (filter.notes) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'shipments', - 'notes', - filter.notes, - ), - }; - } - - - - - - - if (filter.packed_atRange) { - const [start, end] = filter.packed_atRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - packed_at: { - ...where.packed_at, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - packed_at: { - ...where.packed_at, - [Op.lte]: end, - }, - }; - } - } - - if (filter.shipped_atRange) { - const [start, end] = filter.shipped_atRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - shipped_at: { - ...where.shipped_at, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - shipped_at: { - ...where.shipped_at, - [Op.lte]: end, - }, - }; - } - } - - if (filter.delivered_atRange) { - const [start, end] = filter.delivered_atRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - delivered_at: { - ...where.delivered_at, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - delivered_at: { - ...where.delivered_at, - [Op.lte]: end, - }, - }; - } - } - - if (filter.shipping_costRange) { - const [start, end] = filter.shipping_costRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - shipping_cost: { - ...where.shipping_cost, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - shipping_cost: { - ...where.shipping_cost, - [Op.lte]: end, - }, - }; - } - } - - - if (filter.active !== undefined) { - where = { - ...where, - active: filter.active === true || filter.active === 'true' - }; - } - - - if (filter.shipment_status) { - where = { - ...where, - shipment_status: filter.shipment_status, - }; - } - - - - - - - - if (filter.createdAtRange) { - const [start, end] = filter.createdAtRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - ['createdAt']: { - ...where.createdAt, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - ['createdAt']: { - ...where.createdAt, - [Op.lte]: end, - }, - }; - } - } - } - - - - - const queryOptions = { - where, - include, - distinct: true, - order: filter.field && filter.sort - ? [[filter.field, filter.sort]] - : [['createdAt', 'desc']], - transaction: options?.transaction, - logging: console.log - }; - - if (!options?.countOnly) { - queryOptions.limit = limit ? Number(limit) : undefined; - queryOptions.offset = offset ? Number(offset) : undefined; - } - - try { - const { rows, count } = await db.shipments.findAndCountAll(queryOptions); - - return { - rows: options?.countOnly ? [] : rows, - count: count - }; - } catch (error) { - console.error('Error executing query:', error); - throw error; - } - } - - static async findAllAutocomplete(query, limit, offset, ) { - let where = {}; - - - - if (query) { - where = { - [Op.or]: [ - { ['id']: Utils.uuid(query) }, - Utils.ilike( - 'shipments', - 'shipment_number', - query, - ), - ], - }; - } - - const records = await db.shipments.findAll({ - attributes: [ 'id', 'shipment_number' ], - where, - limit: limit ? Number(limit) : undefined, - offset: offset ? Number(offset) : undefined, - orderBy: [['shipment_number', 'ASC']], - }); - - return records.map((record) => ({ - id: record.id, - label: record.shipment_number, - })); - } - - -}; - diff --git a/backend/src/db/api/users.js b/backend/src/db/api/users.js deleted file mode 100644 index dcbada0..0000000 --- a/backend/src/db/api/users.js +++ /dev/null @@ -1,938 +0,0 @@ - -const db = require('../models'); -const FileDBApi = require('./file'); -const crypto = require('crypto'); -const Utils = require('../utils'); - -const bcrypt = require('bcrypt'); -const config = require('../../config'); - - - -const Sequelize = db.Sequelize; -const Op = Sequelize.Op; - -module.exports = class UsersDBApi { - - static async create(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - - const users = await db.users.create( - { - id: data.data.id || undefined, - - firstName: data.data.firstName - || - null - , - - lastName: data.data.lastName - || - null - , - - phoneNumber: data.data.phoneNumber - || - null - , - - email: data.data.email - || - null - , - - disabled: data.data.disabled - || - false - - , - - password: data.data.password - || - null - , - - emailVerified: data.data.emailVerified - || - true - - , - - emailVerificationToken: data.data.emailVerificationToken - || - null - , - - emailVerificationTokenExpiresAt: data.data.emailVerificationTokenExpiresAt - || - null - , - - passwordResetToken: data.data.passwordResetToken - || - null - , - - passwordResetTokenExpiresAt: data.data.passwordResetTokenExpiresAt - || - null - , - - provider: data.data.provider - || - null - , - - importHash: data.data.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - - - if (!data.data.app_role) { - const role = await db.roles.findOne({ - where: { name: 'User' }, - }); - if (role) { - await users.setApp_role(role, { - transaction, - }); - } - }else{ - await users.setApp_role(data.data.app_role || null, { - transaction, - }); - } - - - - - await users.setCustom_permissions(data.data.custom_permissions || [], { - transaction, - }); - - - - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.users.getTableName(), - belongsToColumn: 'avatar', - belongsToId: users.id, - }, - data.data.avatar, - options, - ); - - - return users; - } - - - - - static async bulkImport(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - // Prepare data - wrapping individual data transformations in a map() method - const usersData = data.map((item, index) => ({ - id: item.id || undefined, - - firstName: item.firstName - || - null - , - - lastName: item.lastName - || - null - , - - phoneNumber: item.phoneNumber - || - null - , - - email: item.email - || - null - , - - disabled: item.disabled - || - false - - , - - password: item.password - || - null - , - - emailVerified: item.emailVerified - || - false - - , - - emailVerificationToken: item.emailVerificationToken - || - null - , - - emailVerificationTokenExpiresAt: item.emailVerificationTokenExpiresAt - || - null - , - - passwordResetToken: item.passwordResetToken - || - null - , - - passwordResetTokenExpiresAt: item.passwordResetTokenExpiresAt - || - null - , - - provider: item.provider - || - null - , - - importHash: item.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - createdAt: new Date(Date.now() + index * 1000), - })); - - // Bulk create items - const users = await db.users.bulkCreate(usersData, { transaction }); - - // For each item created, replace relation files - - for (let i = 0; i < users.length; i++) { - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.users.getTableName(), - belongsToColumn: 'avatar', - belongsToId: users[i].id, - }, - data[i].avatar, - options, - ); - } - - - return users; - } - - static async update(id, data, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - - const users = await db.users.findByPk(id, {}, {transaction}); - - - - - if (!data?.app_role) { - data.app_role = users?.app_role?.id; - } - if (!data?.custom_permissions) { - data.custom_permissions = users?.custom_permissions?.map(item => item.id); - } - - if (data.password) { - data.password = bcrypt.hashSync( - data.password, - config.bcrypt.saltRounds, - ); - } else { - data.password = users.password; - } - - - const updatePayload = {}; - - if (data.firstName !== undefined) updatePayload.firstName = data.firstName; - - - if (data.lastName !== undefined) updatePayload.lastName = data.lastName; - - - if (data.phoneNumber !== undefined) updatePayload.phoneNumber = data.phoneNumber; - - - if (data.email !== undefined) updatePayload.email = data.email; - - - if (data.disabled !== undefined) updatePayload.disabled = data.disabled; - - - if (data.password !== undefined) updatePayload.password = data.password; - - - if (data.emailVerified !== undefined) updatePayload.emailVerified = data.emailVerified; - - else updatePayload.emailVerified = true; - - - if (data.emailVerificationToken !== undefined) updatePayload.emailVerificationToken = data.emailVerificationToken; - - - if (data.emailVerificationTokenExpiresAt !== undefined) updatePayload.emailVerificationTokenExpiresAt = data.emailVerificationTokenExpiresAt; - - - if (data.passwordResetToken !== undefined) updatePayload.passwordResetToken = data.passwordResetToken; - - - if (data.passwordResetTokenExpiresAt !== undefined) updatePayload.passwordResetTokenExpiresAt = data.passwordResetTokenExpiresAt; - - - if (data.provider !== undefined) updatePayload.provider = data.provider; - - - updatePayload.updatedById = currentUser.id; - - await users.update(updatePayload, {transaction}); - - - - if (data.app_role !== undefined) { - await users.setApp_role( - - data.app_role, - - { transaction } - ); - } - - - - - if (data.custom_permissions !== undefined) { - await users.setCustom_permissions(data.custom_permissions, { transaction }); - } - - - - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.users.getTableName(), - belongsToColumn: 'avatar', - belongsToId: users.id, - }, - data.avatar, - options, - ); - - - return users; - } - - static async deleteByIds(ids, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const users = await db.users.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); - - await db.sequelize.transaction(async (transaction) => { - for (const record of users) { - await record.update( - {deletedBy: currentUser.id}, - {transaction} - ); - } - for (const record of users) { - await record.destroy({transaction}); - } - }); - - - return users; - } - - static async remove(id, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - const users = await db.users.findByPk(id, options); - - await users.update({ - deletedBy: currentUser.id - }, { - transaction, - }); - - await users.destroy({ - transaction - }); - - return users; - } - - static async findBy(where, options) { - const transaction = (options && options.transaction) || undefined; - - const users = await db.users.findOne( - { where }, - { transaction }, - ); - - if (!users) { - return users; - } - - const output = users.get({plain: true}); - - - - - - - - - output.orders_assigned_to = await users.getOrders_assigned_to({ - transaction - }); - - - - - - - output.avatar = await users.getAvatar({ - transaction - }); - - - output.app_role = await users.getApp_role({ - transaction - }); - - if (output.app_role) { - output.app_role_permissions = await output.app_role.getPermissions({ - transaction, - }); - } - - - output.custom_permissions = await users.getCustom_permissions({ - transaction - }); - - - - return output; - } - - static async findAll( - filter, - options - ) { - const limit = filter.limit || 0; - let offset = 0; - let where = {}; - const currentPage = +filter.page; - - - - - - offset = currentPage * limit; - - const orderBy = null; - - const transaction = (options && options.transaction) || undefined; - - let include = [ - - { - model: db.roles, - as: 'app_role', - - where: filter.app_role ? { - [Op.or]: [ - { id: { [Op.in]: filter.app_role.split('|').map(term => Utils.uuid(term)) } }, - { - name: { - [Op.or]: filter.app_role.split('|').map(term => ({ [Op.iLike]: `%${term}%` })) - } - }, - ] - } : {}, - - }, - - - { - model: db.permissions, - as: 'custom_permissions', - required: false, - }, - - - { - model: db.file, - as: 'avatar', - }, - - ]; - - if (filter) { - if (filter.id) { - where = { - ...where, - ['id']: Utils.uuid(filter.id), - }; - } - - - if (filter.firstName) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'users', - 'firstName', - filter.firstName, - ), - }; - } - - if (filter.lastName) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'users', - 'lastName', - filter.lastName, - ), - }; - } - - if (filter.phoneNumber) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'users', - 'phoneNumber', - filter.phoneNumber, - ), - }; - } - - if (filter.email) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'users', - 'email', - filter.email, - ), - }; - } - - if (filter.password) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'users', - 'password', - filter.password, - ), - }; - } - - if (filter.emailVerificationToken) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'users', - 'emailVerificationToken', - filter.emailVerificationToken, - ), - }; - } - - if (filter.passwordResetToken) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'users', - 'passwordResetToken', - filter.passwordResetToken, - ), - }; - } - - if (filter.provider) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'users', - 'provider', - filter.provider, - ), - }; - } - - - - - - - if (filter.emailVerificationTokenExpiresAtRange) { - const [start, end] = filter.emailVerificationTokenExpiresAtRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - emailVerificationTokenExpiresAt: { - ...where.emailVerificationTokenExpiresAt, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - emailVerificationTokenExpiresAt: { - ...where.emailVerificationTokenExpiresAt, - [Op.lte]: end, - }, - }; - } - } - - if (filter.passwordResetTokenExpiresAtRange) { - const [start, end] = filter.passwordResetTokenExpiresAtRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - passwordResetTokenExpiresAt: { - ...where.passwordResetTokenExpiresAt, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - passwordResetTokenExpiresAt: { - ...where.passwordResetTokenExpiresAt, - [Op.lte]: end, - }, - }; - } - } - - - if (filter.active !== undefined) { - where = { - ...where, - active: filter.active === true || filter.active === 'true' - }; - } - - - if (filter.disabled) { - where = { - ...where, - disabled: filter.disabled, - }; - } - - if (filter.emailVerified) { - where = { - ...where, - emailVerified: filter.emailVerified, - }; - } - - - - - - - if (filter.custom_permissions) { - const searchTerms = filter.custom_permissions.split('|'); - - include = [ - { - model: db.permissions, - as: 'custom_permissions_filter', - required: searchTerms.length > 0, - where: searchTerms.length > 0 ? { - [Op.or]: [ - { id: { [Op.in]: searchTerms.map(term => Utils.uuid(term)) } }, - { - name: { - [Op.or]: searchTerms.map(term => ({ [Op.iLike]: `%${term}%` })) - } - } - ] - } : undefined - }, - ...include, - ] - } - - - if (filter.createdAtRange) { - const [start, end] = filter.createdAtRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - ['createdAt']: { - ...where.createdAt, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - ['createdAt']: { - ...where.createdAt, - [Op.lte]: end, - }, - }; - } - } - } - - - - - const queryOptions = { - where, - include, - distinct: true, - order: filter.field && filter.sort - ? [[filter.field, filter.sort]] - : [['createdAt', 'desc']], - transaction: options?.transaction, - logging: console.log - }; - - if (!options?.countOnly) { - queryOptions.limit = limit ? Number(limit) : undefined; - queryOptions.offset = offset ? Number(offset) : undefined; - } - - try { - const { rows, count } = await db.users.findAndCountAll(queryOptions); - - return { - rows: options?.countOnly ? [] : rows, - count: count - }; - } catch (error) { - console.error('Error executing query:', error); - throw error; - } - } - - static async findAllAutocomplete(query, limit, offset, ) { - let where = {}; - - - - if (query) { - where = { - [Op.or]: [ - { ['id']: Utils.uuid(query) }, - Utils.ilike( - 'users', - 'firstName', - query, - ), - ], - }; - } - - const records = await db.users.findAll({ - attributes: [ 'id', 'firstName' ], - where, - limit: limit ? Number(limit) : undefined, - offset: offset ? Number(offset) : undefined, - orderBy: [['firstName', 'ASC']], - }); - - return records.map((record) => ({ - id: record.id, - label: record.firstName, - })); - } - - - static async createFromAuth(data, options) { - const transaction = (options && options.transaction) || undefined; - const users = await db.users.create( - { - email: data.email, - firstName: data.firstName, - authenticationUid: data.authenticationUid, - password: data.password, - - }, - { transaction }, - ); - - const app_role = await db.roles.findOne({ - where: { name: config.roles?.user || "User" }, - }); - if (app_role?.id) { - await users.setApp_role(app_role?.id || null, { - transaction, - }); - } - - await users.update( - { - authenticationUid: users.id, - }, - { transaction }, - ); - - delete users.password; - return users; - } - - static async updatePassword(id, password, options) { - const currentUser = (options && options.currentUser) || { id: null }; - - const transaction = (options && options.transaction) || undefined; - - const users = await db.users.findByPk(id, { - transaction, - }); - - await users.update( - { - password, - authenticationUid: id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - return users; - } - - static async generateEmailVerificationToken(email, options) { - return this._generateToken(['emailVerificationToken', 'emailVerificationTokenExpiresAt'], email, options); - } - - static async generatePasswordResetToken(email, options) { - return this._generateToken(['passwordResetToken', 'passwordResetTokenExpiresAt'], email, options); - } - - static async findByPasswordResetToken(token, options) { - const transaction = (options && options.transaction) || undefined; - - return db.users.findOne( - { - where: { - passwordResetToken: token, - passwordResetTokenExpiresAt: { - [db.Sequelize.Op.gt]: Date.now(), - }, - }, - }, - { transaction }, - ); - } - - static async findByEmailVerificationToken( - token, - options, - ) { - const transaction = (options && options.transaction) || undefined; - return db.users.findOne( - { - where: { - emailVerificationToken: token, - emailVerificationTokenExpiresAt: { - [db.Sequelize.Op.gt]: Date.now(), - }, - }, - }, - { transaction }, - ); - } - - static async markEmailVerified(id, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const users = await db.users.findByPk(id, { - transaction, - }); - - await users.update( - { - emailVerified: true, - updatedById: currentUser.id, - }, - { transaction }, - ); - - return true; - } - - static async _generateToken(keyNames, email, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - const users = await db.users.findOne( - { - where: { email: email.toLowerCase() }, - }, - { - transaction, - }, - ); - - const token = crypto - .randomBytes(20) - .toString('hex'); - const tokenExpiresAt = Date.now() + 360000; - - if(users){ - await users.update( - { - [keyNames[0]]: token, - [keyNames[1]]: tokenExpiresAt, - updatedById: currentUser.id, - }, - {transaction}, - ); - } - - - return token; - } - - - -}; - diff --git a/backend/src/db/db.config.js b/backend/src/db/db.config.js deleted file mode 100644 index 4f07043..0000000 --- a/backend/src/db/db.config.js +++ /dev/null @@ -1,33 +0,0 @@ - - -module.exports = { - production: { - dialect: 'postgres', - username: process.env.DB_USER, - password: process.env.DB_PASS, - database: process.env.DB_NAME, - host: process.env.DB_HOST, - port: process.env.DB_PORT, - logging: console.log, - seederStorage: 'sequelize', - }, - development: { - username: 'postgres', - dialect: 'postgres', - password: '', - database: 'db_store_operations_hub', - host: process.env.DB_HOST || 'localhost', - logging: console.log, - seederStorage: 'sequelize', - }, - dev_stage: { - dialect: 'postgres', - username: process.env.DB_USER, - password: process.env.DB_PASS, - database: process.env.DB_NAME, - host: process.env.DB_HOST, - port: process.env.DB_PORT, - logging: console.log, - seederStorage: 'sequelize', - } -}; diff --git a/backend/src/db/migrations/1777487463402.js b/backend/src/db/migrations/1777487463402.js deleted file mode 100644 index dc558ca..0000000 --- a/backend/src/db/migrations/1777487463402.js +++ /dev/null @@ -1,2873 +0,0 @@ -module.exports = { - /** - * @param {QueryInterface} queryInterface - * @param {Sequelize} Sequelize - * @returns {Promise} - */ - async up(queryInterface, Sequelize) { - /** - * @type {Transaction} - */ - const transaction = await queryInterface.sequelize.transaction(); - try { - - - await queryInterface.createTable('users', { - id: { - type: Sequelize.DataTypes.UUID, - defaultValue: Sequelize.DataTypes.UUIDV4, - primaryKey: true, - }, - createdById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - updatedById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - createdAt: { type: Sequelize.DataTypes.DATE }, - updatedAt: { type: Sequelize.DataTypes.DATE }, - deletedAt: { type: Sequelize.DataTypes.DATE }, - importHash: { - type: Sequelize.DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, { transaction }); - - - - await queryInterface.createTable('roles', { - id: { - type: Sequelize.DataTypes.UUID, - defaultValue: Sequelize.DataTypes.UUIDV4, - primaryKey: true, - }, - createdById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - updatedById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - createdAt: { type: Sequelize.DataTypes.DATE }, - updatedAt: { type: Sequelize.DataTypes.DATE }, - deletedAt: { type: Sequelize.DataTypes.DATE }, - importHash: { - type: Sequelize.DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, { transaction }); - - - - await queryInterface.createTable('permissions', { - id: { - type: Sequelize.DataTypes.UUID, - defaultValue: Sequelize.DataTypes.UUIDV4, - primaryKey: true, - }, - createdById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - updatedById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - createdAt: { type: Sequelize.DataTypes.DATE }, - updatedAt: { type: Sequelize.DataTypes.DATE }, - deletedAt: { type: Sequelize.DataTypes.DATE }, - importHash: { - type: Sequelize.DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, { transaction }); - - - - await queryInterface.createTable('customers', { - id: { - type: Sequelize.DataTypes.UUID, - defaultValue: Sequelize.DataTypes.UUIDV4, - primaryKey: true, - }, - createdById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - updatedById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - createdAt: { type: Sequelize.DataTypes.DATE }, - updatedAt: { type: Sequelize.DataTypes.DATE }, - deletedAt: { type: Sequelize.DataTypes.DATE }, - importHash: { - type: Sequelize.DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, { transaction }); - - - - await queryInterface.createTable('product_categories', { - id: { - type: Sequelize.DataTypes.UUID, - defaultValue: Sequelize.DataTypes.UUIDV4, - primaryKey: true, - }, - createdById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - updatedById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - createdAt: { type: Sequelize.DataTypes.DATE }, - updatedAt: { type: Sequelize.DataTypes.DATE }, - deletedAt: { type: Sequelize.DataTypes.DATE }, - importHash: { - type: Sequelize.DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, { transaction }); - - - - await queryInterface.createTable('products', { - id: { - type: Sequelize.DataTypes.UUID, - defaultValue: Sequelize.DataTypes.UUIDV4, - primaryKey: true, - }, - createdById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - updatedById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - createdAt: { type: Sequelize.DataTypes.DATE }, - updatedAt: { type: Sequelize.DataTypes.DATE }, - deletedAt: { type: Sequelize.DataTypes.DATE }, - importHash: { - type: Sequelize.DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, { transaction }); - - - - await queryInterface.createTable('orders', { - id: { - type: Sequelize.DataTypes.UUID, - defaultValue: Sequelize.DataTypes.UUIDV4, - primaryKey: true, - }, - createdById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - updatedById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - createdAt: { type: Sequelize.DataTypes.DATE }, - updatedAt: { type: Sequelize.DataTypes.DATE }, - deletedAt: { type: Sequelize.DataTypes.DATE }, - importHash: { - type: Sequelize.DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, { transaction }); - - - - await queryInterface.createTable('order_items', { - id: { - type: Sequelize.DataTypes.UUID, - defaultValue: Sequelize.DataTypes.UUIDV4, - primaryKey: true, - }, - createdById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - updatedById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - createdAt: { type: Sequelize.DataTypes.DATE }, - updatedAt: { type: Sequelize.DataTypes.DATE }, - deletedAt: { type: Sequelize.DataTypes.DATE }, - importHash: { - type: Sequelize.DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, { transaction }); - - - - await queryInterface.createTable('payments', { - id: { - type: Sequelize.DataTypes.UUID, - defaultValue: Sequelize.DataTypes.UUIDV4, - primaryKey: true, - }, - createdById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - updatedById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - createdAt: { type: Sequelize.DataTypes.DATE }, - updatedAt: { type: Sequelize.DataTypes.DATE }, - deletedAt: { type: Sequelize.DataTypes.DATE }, - importHash: { - type: Sequelize.DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, { transaction }); - - - - await queryInterface.createTable('shipments', { - id: { - type: Sequelize.DataTypes.UUID, - defaultValue: Sequelize.DataTypes.UUIDV4, - primaryKey: true, - }, - createdById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - updatedById: { - type: Sequelize.DataTypes.UUID, - references: { - key: 'id', - model: 'users', - }, - }, - createdAt: { type: Sequelize.DataTypes.DATE }, - updatedAt: { type: Sequelize.DataTypes.DATE }, - deletedAt: { type: Sequelize.DataTypes.DATE }, - importHash: { - type: Sequelize.DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, { transaction }); - - - - - await queryInterface.addColumn( - 'users', - 'firstName', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'users', - 'lastName', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'users', - 'phoneNumber', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'users', - 'email', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'users', - 'disabled', - { - type: Sequelize.DataTypes.BOOLEAN, - - defaultValue: false, - allowNull: false, - - - - }, - { transaction } - ); - - - - - - - await queryInterface.addColumn( - 'users', - 'password', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'users', - 'emailVerified', - { - type: Sequelize.DataTypes.BOOLEAN, - - defaultValue: false, - allowNull: false, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'users', - 'emailVerificationToken', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'users', - 'emailVerificationTokenExpiresAt', - { - type: Sequelize.DataTypes.DATE, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'users', - 'passwordResetToken', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'users', - 'passwordResetTokenExpiresAt', - { - type: Sequelize.DataTypes.DATE, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'users', - 'provider', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'users', - 'app_roleId', - { - type: Sequelize.DataTypes.UUID, - - - - references: { - model: 'roles', - key: 'id', - }, - - }, - { transaction } - ); - - - - - - - await queryInterface.addColumn( - 'roles', - 'name', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'roles', - 'role_customization', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - - - await queryInterface.addColumn( - 'permissions', - 'name', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'customers', - 'customer_code', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'customers', - 'full_name', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'customers', - 'email', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'customers', - 'phone', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'customers', - 'billing_address', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'customers', - 'shipping_address', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'customers', - 'customer_status', - { - type: Sequelize.DataTypes.ENUM, - - - values: ['active','inactive','blocked'], - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'customers', - 'registered_at', - { - type: Sequelize.DataTypes.DATE, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'customers', - 'notes', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'product_categories', - 'name', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'product_categories', - 'slug', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'product_categories', - 'description', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'product_categories', - 'parent_categoryId', - { - type: Sequelize.DataTypes.UUID, - - - - references: { - model: 'product_categories', - key: 'id', - }, - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'product_categories', - 'is_active', - { - type: Sequelize.DataTypes.BOOLEAN, - - defaultValue: false, - allowNull: false, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'products', - 'name', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'products', - 'sku', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'products', - 'barcode', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'products', - 'short_description', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'products', - 'description', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'products', - 'price', - { - type: Sequelize.DataTypes.DECIMAL, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'products', - 'compare_at_price', - { - type: Sequelize.DataTypes.DECIMAL, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'products', - 'cost', - { - type: Sequelize.DataTypes.DECIMAL, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'products', - 'stock_on_hand', - { - type: Sequelize.DataTypes.INTEGER, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'products', - 'reorder_point', - { - type: Sequelize.DataTypes.INTEGER, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'products', - 'product_status', - { - type: Sequelize.DataTypes.ENUM, - - - values: ['draft','active','archived'], - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'products', - 'categoryId', - { - type: Sequelize.DataTypes.UUID, - - - - references: { - model: 'product_categories', - key: 'id', - }, - - }, - { transaction } - ); - - - - - - - - - await queryInterface.addColumn( - 'products', - 'track_inventory', - { - type: Sequelize.DataTypes.BOOLEAN, - - defaultValue: false, - allowNull: false, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'products', - 'weight', - { - type: Sequelize.DataTypes.DECIMAL, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'order_number', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'customerId', - { - type: Sequelize.DataTypes.UUID, - - - - references: { - model: 'customers', - key: 'id', - }, - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'order_status', - { - type: Sequelize.DataTypes.ENUM, - - - values: ['new','pending_payment','paid','packed','shipped','delivered','cancelled','returned','refunded'], - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'fulfillment_status', - { - type: Sequelize.DataTypes.ENUM, - - - values: ['unfulfilled','partially_fulfilled','fulfilled','returned'], - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'payment_status', - { - type: Sequelize.DataTypes.ENUM, - - - values: ['unpaid','partially_paid','paid','refunded','partially_refunded'], - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'placed_at', - { - type: Sequelize.DataTypes.DATE, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'packed_at', - { - type: Sequelize.DataTypes.DATE, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'shipped_at', - { - type: Sequelize.DataTypes.DATE, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'delivered_at', - { - type: Sequelize.DataTypes.DATE, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'subtotal_amount', - { - type: Sequelize.DataTypes.DECIMAL, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'discount_amount', - { - type: Sequelize.DataTypes.DECIMAL, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'tax_amount', - { - type: Sequelize.DataTypes.DECIMAL, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'shipping_amount', - { - type: Sequelize.DataTypes.DECIMAL, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'total_amount', - { - type: Sequelize.DataTypes.DECIMAL, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'currency', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'shipping_name', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'shipping_address', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'billing_name', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'billing_address', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'notes_internal', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'customer_note', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'tracking_number', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'carrier', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'orders', - 'assigned_toId', - { - type: Sequelize.DataTypes.UUID, - - - - references: { - model: 'users', - key: 'id', - }, - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'order_items', - 'orderId', - { - type: Sequelize.DataTypes.UUID, - - - - references: { - model: 'orders', - key: 'id', - }, - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'order_items', - 'productId', - { - type: Sequelize.DataTypes.UUID, - - - - references: { - model: 'products', - key: 'id', - }, - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'order_items', - 'product_name_snapshot', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'order_items', - 'sku_snapshot', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'order_items', - 'unit_price', - { - type: Sequelize.DataTypes.DECIMAL, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'order_items', - 'quantity', - { - type: Sequelize.DataTypes.INTEGER, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'order_items', - 'line_discount_amount', - { - type: Sequelize.DataTypes.DECIMAL, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'order_items', - 'line_tax_amount', - { - type: Sequelize.DataTypes.DECIMAL, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'order_items', - 'line_total_amount', - { - type: Sequelize.DataTypes.DECIMAL, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'order_items', - 'item_fulfillment_status', - { - type: Sequelize.DataTypes.ENUM, - - - values: ['unfulfilled','fulfilled','returned','cancelled'], - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'payments', - 'payment_reference', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'payments', - 'orderId', - { - type: Sequelize.DataTypes.UUID, - - - - references: { - model: 'orders', - key: 'id', - }, - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'payments', - 'amount', - { - type: Sequelize.DataTypes.DECIMAL, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'payments', - 'currency', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'payments', - 'payment_method', - { - type: Sequelize.DataTypes.ENUM, - - - values: ['card','bank_transfer','cash_on_delivery','wallet','gift_card','other'], - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'payments', - 'payment_provider', - { - type: Sequelize.DataTypes.ENUM, - - - values: ['stripe','paypal','adyen','square','manual','other'], - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'payments', - 'payment_status', - { - type: Sequelize.DataTypes.ENUM, - - - values: ['pending','authorized','captured','failed','refunded','cancelled'], - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'payments', - 'initiated_at', - { - type: Sequelize.DataTypes.DATE, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'payments', - 'captured_at', - { - type: Sequelize.DataTypes.DATE, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'payments', - 'refunded_at', - { - type: Sequelize.DataTypes.DATE, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'payments', - 'provider_transaction_id', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'payments', - 'failure_reason', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'payments', - 'is_test', - { - type: Sequelize.DataTypes.BOOLEAN, - - defaultValue: false, - allowNull: false, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'shipments', - 'shipment_number', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'shipments', - 'orderId', - { - type: Sequelize.DataTypes.UUID, - - - - references: { - model: 'orders', - key: 'id', - }, - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'shipments', - 'shipment_status', - { - type: Sequelize.DataTypes.ENUM, - - - values: ['pending','packed','shipped','in_transit','delivered','returned','lost','cancelled'], - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'shipments', - 'carrier', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'shipments', - 'service_level', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'shipments', - 'tracking_number', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'shipments', - 'packed_at', - { - type: Sequelize.DataTypes.DATE, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'shipments', - 'shipped_at', - { - type: Sequelize.DataTypes.DATE, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'shipments', - 'delivered_at', - { - type: Sequelize.DataTypes.DATE, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'shipments', - 'shipping_cost', - { - type: Sequelize.DataTypes.DECIMAL, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'shipments', - 'label_url', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - - - await queryInterface.addColumn( - 'shipments', - 'notes', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await transaction.commit(); - } catch (err) { - await transaction.rollback(); - throw err; - } - }, - /** - * @param {QueryInterface} queryInterface - * @param {Sequelize} Sequelize - * @returns {Promise} - */ - async down(queryInterface, Sequelize) { - /** - * @type {Transaction} - */ - const transaction = await queryInterface.sequelize.transaction(); - try { - - - await queryInterface.removeColumn( - 'shipments', - 'notes', - { transaction } - ); - - - - - - await queryInterface.removeColumn( - 'shipments', - 'label_url', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'shipments', - 'shipping_cost', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'shipments', - 'delivered_at', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'shipments', - 'shipped_at', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'shipments', - 'packed_at', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'shipments', - 'tracking_number', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'shipments', - 'service_level', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'shipments', - 'carrier', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'shipments', - 'shipment_status', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'shipments', - 'orderId', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'shipments', - 'shipment_number', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'payments', - 'is_test', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'payments', - 'failure_reason', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'payments', - 'provider_transaction_id', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'payments', - 'refunded_at', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'payments', - 'captured_at', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'payments', - 'initiated_at', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'payments', - 'payment_status', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'payments', - 'payment_provider', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'payments', - 'payment_method', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'payments', - 'currency', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'payments', - 'amount', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'payments', - 'orderId', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'payments', - 'payment_reference', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'order_items', - 'item_fulfillment_status', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'order_items', - 'line_total_amount', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'order_items', - 'line_tax_amount', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'order_items', - 'line_discount_amount', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'order_items', - 'quantity', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'order_items', - 'unit_price', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'order_items', - 'sku_snapshot', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'order_items', - 'product_name_snapshot', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'order_items', - 'productId', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'order_items', - 'orderId', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'assigned_toId', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'carrier', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'tracking_number', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'customer_note', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'notes_internal', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'billing_address', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'billing_name', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'shipping_address', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'shipping_name', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'currency', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'total_amount', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'shipping_amount', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'tax_amount', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'discount_amount', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'subtotal_amount', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'delivered_at', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'shipped_at', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'packed_at', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'placed_at', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'payment_status', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'fulfillment_status', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'order_status', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'customerId', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'orders', - 'order_number', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'products', - 'weight', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'products', - 'track_inventory', - { transaction } - ); - - - - - - - - await queryInterface.removeColumn( - 'products', - 'categoryId', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'products', - 'product_status', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'products', - 'reorder_point', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'products', - 'stock_on_hand', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'products', - 'cost', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'products', - 'compare_at_price', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'products', - 'price', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'products', - 'description', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'products', - 'short_description', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'products', - 'barcode', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'products', - 'sku', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'products', - 'name', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'product_categories', - 'is_active', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'product_categories', - 'parent_categoryId', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'product_categories', - 'description', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'product_categories', - 'slug', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'product_categories', - 'name', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'customers', - 'notes', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'customers', - 'registered_at', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'customers', - 'customer_status', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'customers', - 'shipping_address', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'customers', - 'billing_address', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'customers', - 'phone', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'customers', - 'email', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'customers', - 'full_name', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'customers', - 'customer_code', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'permissions', - 'name', - { transaction } - ); - - - - - - await queryInterface.removeColumn( - 'roles', - 'role_customization', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'roles', - 'name', - { transaction } - ); - - - - - - await queryInterface.removeColumn( - 'users', - 'app_roleId', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'users', - 'provider', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'users', - 'passwordResetTokenExpiresAt', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'users', - 'passwordResetToken', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'users', - 'emailVerificationTokenExpiresAt', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'users', - 'emailVerificationToken', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'users', - 'emailVerified', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'users', - 'password', - { transaction } - ); - - - - - - await queryInterface.removeColumn( - 'users', - 'disabled', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'users', - 'email', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'users', - 'phoneNumber', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'users', - 'lastName', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'users', - 'firstName', - { transaction } - ); - - - - await queryInterface.dropTable('shipments', { transaction }); - - - - await queryInterface.dropTable('payments', { transaction }); - - - - await queryInterface.dropTable('order_items', { transaction }); - - - - await queryInterface.dropTable('orders', { transaction }); - - - - await queryInterface.dropTable('products', { transaction }); - - - - await queryInterface.dropTable('product_categories', { transaction }); - - - - await queryInterface.dropTable('customers', { transaction }); - - - - await queryInterface.dropTable('permissions', { transaction }); - - - - await queryInterface.dropTable('roles', { transaction }); - - - - await queryInterface.dropTable('users', { transaction }); - - - await transaction.commit(); - } catch (err) { - await transaction.rollback(); - throw err; - } - } -}; diff --git a/backend/src/db/migrations/20260316000000-create-files.js b/backend/src/db/migrations/20260316000000-create-files.js deleted file mode 100644 index 69e9594..0000000 --- a/backend/src/db/migrations/20260316000000-create-files.js +++ /dev/null @@ -1,124 +0,0 @@ -module.exports = { - async up(queryInterface, Sequelize) { - const transaction = await queryInterface.sequelize.transaction(); - - try { - const rows = await queryInterface.sequelize.query( - "SELECT to_regclass('public.files') AS regclass_name;", - { - transaction, - type: Sequelize.QueryTypes.SELECT, - }, - ); - const tableName = rows[0].regclass_name; - - if (tableName) { - await transaction.commit(); - return; - } - - await queryInterface.createTable( - 'files', - { - id: { - type: Sequelize.DataTypes.UUID, - defaultValue: Sequelize.DataTypes.UUIDV4, - primaryKey: true, - }, - belongsTo: { - type: Sequelize.DataTypes.STRING(255), - allowNull: true, - }, - belongsToId: { - type: Sequelize.DataTypes.UUID, - allowNull: true, - }, - belongsToColumn: { - type: Sequelize.DataTypes.STRING(255), - allowNull: true, - }, - name: { - type: Sequelize.DataTypes.STRING(2083), - allowNull: false, - }, - sizeInBytes: { - type: Sequelize.DataTypes.INTEGER, - allowNull: true, - }, - privateUrl: { - type: Sequelize.DataTypes.STRING(2083), - allowNull: true, - }, - publicUrl: { - type: Sequelize.DataTypes.STRING(2083), - allowNull: false, - }, - createdAt: { - type: Sequelize.DataTypes.DATE, - allowNull: false, - }, - updatedAt: { - type: Sequelize.DataTypes.DATE, - allowNull: false, - }, - deletedAt: { - type: Sequelize.DataTypes.DATE, - allowNull: true, - }, - createdById: { - type: Sequelize.DataTypes.UUID, - allowNull: true, - references: { - key: 'id', - model: 'users', - }, - onDelete: 'SET NULL', - onUpdate: 'CASCADE', - }, - updatedById: { - type: Sequelize.DataTypes.UUID, - allowNull: true, - references: { - key: 'id', - model: 'users', - }, - onDelete: 'SET NULL', - onUpdate: 'CASCADE', - }, - }, - { transaction }, - ); - - await transaction.commit(); - } catch (err) { - await transaction.rollback(); - throw err; - } - }, - - async down(queryInterface, Sequelize) { - const transaction = await queryInterface.sequelize.transaction(); - - try { - const rows = await queryInterface.sequelize.query( - "SELECT to_regclass('public.files') AS regclass_name;", - { - transaction, - type: Sequelize.QueryTypes.SELECT, - }, - ); - const tableName = rows[0].regclass_name; - - if (!tableName) { - await transaction.commit(); - return; - } - - await queryInterface.dropTable('files', { transaction }); - await transaction.commit(); - } catch (err) { - await transaction.rollback(); - throw err; - } - }, -}; diff --git a/backend/src/db/migrations/20260316001000-create-users-custom-permissions-join-table.js b/backend/src/db/migrations/20260316001000-create-users-custom-permissions-join-table.js deleted file mode 100644 index c0e5634..0000000 --- a/backend/src/db/migrations/20260316001000-create-users-custom-permissions-join-table.js +++ /dev/null @@ -1,77 +0,0 @@ -module.exports = { - async up(queryInterface, Sequelize) { - const transaction = await queryInterface.sequelize.transaction(); - - try { - const rows = await queryInterface.sequelize.query( - "SELECT to_regclass('public.\"usersCustom_permissionsPermissions\"') AS regclass_name;", - { - transaction, - type: Sequelize.QueryTypes.SELECT, - }, - ); - const tableName = rows[0].regclass_name; - - if (tableName) { - await transaction.commit(); - return; - } - - await queryInterface.createTable( - 'usersCustom_permissionsPermissions', - { - createdAt: { - type: Sequelize.DataTypes.DATE, - allowNull: false, - }, - updatedAt: { - type: Sequelize.DataTypes.DATE, - allowNull: false, - }, - users_custom_permissionsId: { - type: Sequelize.DataTypes.UUID, - allowNull: false, - primaryKey: true, - }, - permissionId: { - type: Sequelize.DataTypes.UUID, - allowNull: false, - primaryKey: true, - }, - }, - { transaction }, - ); - - await transaction.commit(); - } catch (err) { - await transaction.rollback(); - throw err; - } - }, - - async down(queryInterface, Sequelize) { - const transaction = await queryInterface.sequelize.transaction(); - - try { - const rows = await queryInterface.sequelize.query( - "SELECT to_regclass('public.\"usersCustom_permissionsPermissions\"') AS regclass_name;", - { - transaction, - type: Sequelize.QueryTypes.SELECT, - }, - ); - const tableName = rows[0].regclass_name; - - if (!tableName) { - await transaction.commit(); - return; - } - - await queryInterface.dropTable('usersCustom_permissionsPermissions', { transaction }); - await transaction.commit(); - } catch (err) { - await transaction.rollback(); - throw err; - } - }, -}; diff --git a/backend/src/db/models/customers.js b/backend/src/db/models/customers.js deleted file mode 100644 index d28c4ac..0000000 --- a/backend/src/db/models/customers.js +++ /dev/null @@ -1,151 +0,0 @@ -const config = require('../../config'); -const providers = config.providers; -const crypto = require('crypto'); -const bcrypt = require('bcrypt'); -const moment = require('moment'); - -module.exports = function(sequelize, DataTypes) { - const customers = sequelize.define( - 'customers', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - -customer_code: { - type: DataTypes.TEXT, - - - - }, - -full_name: { - type: DataTypes.TEXT, - - - - }, - -email: { - type: DataTypes.TEXT, - - - - }, - -phone: { - type: DataTypes.TEXT, - - - - }, - -billing_address: { - type: DataTypes.TEXT, - - - - }, - -shipping_address: { - type: DataTypes.TEXT, - - - - }, - -customer_status: { - type: DataTypes.ENUM, - - - - values: [ - -"active", - - -"inactive", - - -"blocked" - - ], - - }, - -registered_at: { - type: DataTypes.DATE, - - - - }, - -notes: { - type: DataTypes.TEXT, - - - - }, - - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { - timestamps: true, - paranoid: true, - freezeTableName: true, - }, - ); - - customers.associate = (db) => { - - -/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity - - - - - - - - - db.customers.hasMany(db.orders, { - as: 'orders_customer', - foreignKey: { - name: 'customerId', - }, - constraints: false, - }); - - - - - - -//end loop - - - - - - - db.customers.belongsTo(db.users, { - as: 'createdBy', - }); - - db.customers.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - - - return customers; -}; - - diff --git a/backend/src/db/models/file.js b/backend/src/db/models/file.js deleted file mode 100644 index 7703bb6..0000000 --- a/backend/src/db/models/file.js +++ /dev/null @@ -1,53 +0,0 @@ -module.exports = function(sequelize, DataTypes) { - const file = sequelize.define( - 'file', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - belongsTo: DataTypes.STRING(255), - belongsToId: DataTypes.UUID, - belongsToColumn: DataTypes.STRING(255), - name: { - type: DataTypes.STRING(2083), - allowNull: false, - validate: { - notEmpty: true, - }, - }, - sizeInBytes: { - type: DataTypes.INTEGER, - allowNull: true, - }, - privateUrl: { - type: DataTypes.STRING(2083), - allowNull: true, - }, - publicUrl: { - type: DataTypes.STRING(2083), - allowNull: false, - validate: { - notEmpty: true, - }, - }, - }, - { - timestamps: true, - paranoid: true, - }, - ); - - file.associate = (db) => { - db.file.belongsTo(db.users, { - as: 'createdBy', - }); - - db.file.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - return file; -}; diff --git a/backend/src/db/models/index.js b/backend/src/db/models/index.js deleted file mode 100644 index 4a3852f..0000000 --- a/backend/src/db/models/index.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const path = require('path'); -const Sequelize = require('sequelize'); -const basename = path.basename(__filename); -const env = process.env.NODE_ENV || 'development'; -const config = require("../db.config")[env]; -const db = {}; - -let sequelize; -console.log(env); -if (config.use_env_variable) { - sequelize = new Sequelize(process.env[config.use_env_variable], config); -} else { - sequelize = new Sequelize(config.database, config.username, config.password, config); -} - -fs - .readdirSync(__dirname) - .filter(file => { - return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js'); - }) - .forEach(file => { - const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes) - db[model.name] = model; - }); - -Object.keys(db).forEach(modelName => { - if (db[modelName].associate) { - db[modelName].associate(db); - } -}); - -db.sequelize = sequelize; -db.Sequelize = Sequelize; - -module.exports = db; diff --git a/backend/src/db/models/order_items.js b/backend/src/db/models/order_items.js deleted file mode 100644 index 98f235a..0000000 --- a/backend/src/db/models/order_items.js +++ /dev/null @@ -1,155 +0,0 @@ -const config = require('../../config'); -const providers = config.providers; -const crypto = require('crypto'); -const bcrypt = require('bcrypt'); -const moment = require('moment'); - -module.exports = function(sequelize, DataTypes) { - const order_items = sequelize.define( - 'order_items', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - -product_name_snapshot: { - type: DataTypes.TEXT, - - - - }, - -sku_snapshot: { - type: DataTypes.TEXT, - - - - }, - -unit_price: { - type: DataTypes.DECIMAL, - - - - }, - -quantity: { - type: DataTypes.INTEGER, - - - - }, - -line_discount_amount: { - type: DataTypes.DECIMAL, - - - - }, - -line_tax_amount: { - type: DataTypes.DECIMAL, - - - - }, - -line_total_amount: { - type: DataTypes.DECIMAL, - - - - }, - -item_fulfillment_status: { - type: DataTypes.ENUM, - - - - values: [ - -"unfulfilled", - - -"fulfilled", - - -"returned", - - -"cancelled" - - ], - - }, - - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { - timestamps: true, - paranoid: true, - freezeTableName: true, - }, - ); - - order_items.associate = (db) => { - - -/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity - - - - - - - - - - - - - -//end loop - - - - db.order_items.belongsTo(db.orders, { - as: 'order', - foreignKey: { - name: 'orderId', - }, - constraints: false, - }); - - db.order_items.belongsTo(db.products, { - as: 'product', - foreignKey: { - name: 'productId', - }, - constraints: false, - }); - - - - - db.order_items.belongsTo(db.users, { - as: 'createdBy', - }); - - db.order_items.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - - - return order_items; -}; - - diff --git a/backend/src/db/models/orders.js b/backend/src/db/models/orders.js deleted file mode 100644 index 728bc06..0000000 --- a/backend/src/db/models/orders.js +++ /dev/null @@ -1,325 +0,0 @@ -const config = require('../../config'); -const providers = config.providers; -const crypto = require('crypto'); -const bcrypt = require('bcrypt'); -const moment = require('moment'); - -module.exports = function(sequelize, DataTypes) { - const orders = sequelize.define( - 'orders', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - -order_number: { - type: DataTypes.TEXT, - - - - }, - -order_status: { - type: DataTypes.ENUM, - - - - values: [ - -"new", - - -"pending_payment", - - -"paid", - - -"packed", - - -"shipped", - - -"delivered", - - -"cancelled", - - -"returned", - - -"refunded" - - ], - - }, - -fulfillment_status: { - type: DataTypes.ENUM, - - - - values: [ - -"unfulfilled", - - -"partially_fulfilled", - - -"fulfilled", - - -"returned" - - ], - - }, - -payment_status: { - type: DataTypes.ENUM, - - - - values: [ - -"unpaid", - - -"partially_paid", - - -"paid", - - -"refunded", - - -"partially_refunded" - - ], - - }, - -placed_at: { - type: DataTypes.DATE, - - - - }, - -packed_at: { - type: DataTypes.DATE, - - - - }, - -shipped_at: { - type: DataTypes.DATE, - - - - }, - -delivered_at: { - type: DataTypes.DATE, - - - - }, - -subtotal_amount: { - type: DataTypes.DECIMAL, - - - - }, - -discount_amount: { - type: DataTypes.DECIMAL, - - - - }, - -tax_amount: { - type: DataTypes.DECIMAL, - - - - }, - -shipping_amount: { - type: DataTypes.DECIMAL, - - - - }, - -total_amount: { - type: DataTypes.DECIMAL, - - - - }, - -currency: { - type: DataTypes.TEXT, - - - - }, - -shipping_name: { - type: DataTypes.TEXT, - - - - }, - -shipping_address: { - type: DataTypes.TEXT, - - - - }, - -billing_name: { - type: DataTypes.TEXT, - - - - }, - -billing_address: { - type: DataTypes.TEXT, - - - - }, - -notes_internal: { - type: DataTypes.TEXT, - - - - }, - -customer_note: { - type: DataTypes.TEXT, - - - - }, - -tracking_number: { - type: DataTypes.TEXT, - - - - }, - -carrier: { - type: DataTypes.TEXT, - - - - }, - - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { - timestamps: true, - paranoid: true, - freezeTableName: true, - }, - ); - - orders.associate = (db) => { - - -/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity - - - - - - - - - - db.orders.hasMany(db.order_items, { - as: 'order_items_order', - foreignKey: { - name: 'orderId', - }, - constraints: false, - }); - - - db.orders.hasMany(db.payments, { - as: 'payments_order', - foreignKey: { - name: 'orderId', - }, - constraints: false, - }); - - - db.orders.hasMany(db.shipments, { - as: 'shipments_order', - foreignKey: { - name: 'orderId', - }, - constraints: false, - }); - - - -//end loop - - - - db.orders.belongsTo(db.customers, { - as: 'customer', - foreignKey: { - name: 'customerId', - }, - constraints: false, - }); - - db.orders.belongsTo(db.users, { - as: 'assigned_to', - foreignKey: { - name: 'assigned_toId', - }, - constraints: false, - }); - - - - - db.orders.belongsTo(db.users, { - as: 'createdBy', - }); - - db.orders.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - - - return orders; -}; - - diff --git a/backend/src/db/models/payments.js b/backend/src/db/models/payments.js deleted file mode 100644 index 135a6b5..0000000 --- a/backend/src/db/models/payments.js +++ /dev/null @@ -1,226 +0,0 @@ -const config = require('../../config'); -const providers = config.providers; -const crypto = require('crypto'); -const bcrypt = require('bcrypt'); -const moment = require('moment'); - -module.exports = function(sequelize, DataTypes) { - const payments = sequelize.define( - 'payments', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - -payment_reference: { - type: DataTypes.TEXT, - - - - }, - -amount: { - type: DataTypes.DECIMAL, - - - - }, - -currency: { - type: DataTypes.TEXT, - - - - }, - -payment_method: { - type: DataTypes.ENUM, - - - - values: [ - -"card", - - -"bank_transfer", - - -"cash_on_delivery", - - -"wallet", - - -"gift_card", - - -"other" - - ], - - }, - -payment_provider: { - type: DataTypes.ENUM, - - - - values: [ - -"stripe", - - -"paypal", - - -"adyen", - - -"square", - - -"manual", - - -"other" - - ], - - }, - -payment_status: { - type: DataTypes.ENUM, - - - - values: [ - -"pending", - - -"authorized", - - -"captured", - - -"failed", - - -"refunded", - - -"cancelled" - - ], - - }, - -initiated_at: { - type: DataTypes.DATE, - - - - }, - -captured_at: { - type: DataTypes.DATE, - - - - }, - -refunded_at: { - type: DataTypes.DATE, - - - - }, - -provider_transaction_id: { - type: DataTypes.TEXT, - - - - }, - -failure_reason: { - type: DataTypes.TEXT, - - - - }, - -is_test: { - type: DataTypes.BOOLEAN, - - allowNull: false, - defaultValue: false, - - - - }, - - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { - timestamps: true, - paranoid: true, - freezeTableName: true, - }, - ); - - payments.associate = (db) => { - - -/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity - - - - - - - - - - - - - -//end loop - - - - db.payments.belongsTo(db.orders, { - as: 'order', - foreignKey: { - name: 'orderId', - }, - constraints: false, - }); - - - - - db.payments.belongsTo(db.users, { - as: 'createdBy', - }); - - db.payments.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - - - return payments; -}; - - diff --git a/backend/src/db/models/permissions.js b/backend/src/db/models/permissions.js deleted file mode 100644 index 923a603..0000000 --- a/backend/src/db/models/permissions.js +++ /dev/null @@ -1,75 +0,0 @@ -const config = require('../../config'); -const providers = config.providers; -const crypto = require('crypto'); -const bcrypt = require('bcrypt'); -const moment = require('moment'); - -module.exports = function(sequelize, DataTypes) { - const permissions = sequelize.define( - 'permissions', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - -name: { - type: DataTypes.TEXT, - - - - }, - - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { - timestamps: true, - paranoid: true, - freezeTableName: true, - }, - ); - - permissions.associate = (db) => { - - -/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity - - - - - - - - - - - - - -//end loop - - - - - - - db.permissions.belongsTo(db.users, { - as: 'createdBy', - }); - - db.permissions.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - - - return permissions; -}; - - diff --git a/backend/src/db/models/product_categories.js b/backend/src/db/models/product_categories.js deleted file mode 100644 index 0553b8f..0000000 --- a/backend/src/db/models/product_categories.js +++ /dev/null @@ -1,115 +0,0 @@ -const config = require('../../config'); -const providers = config.providers; -const crypto = require('crypto'); -const bcrypt = require('bcrypt'); -const moment = require('moment'); - -module.exports = function(sequelize, DataTypes) { - const product_categories = sequelize.define( - 'product_categories', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - -name: { - type: DataTypes.TEXT, - - - - }, - -slug: { - type: DataTypes.TEXT, - - - - }, - -description: { - type: DataTypes.TEXT, - - - - }, - -is_active: { - type: DataTypes.BOOLEAN, - - allowNull: false, - defaultValue: false, - - - - }, - - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { - timestamps: true, - paranoid: true, - freezeTableName: true, - }, - ); - - product_categories.associate = (db) => { - - -/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity - - - - - - - - db.product_categories.hasMany(db.products, { - as: 'products_category', - foreignKey: { - name: 'categoryId', - }, - constraints: false, - }); - - - - - - - -//end loop - - - - db.product_categories.belongsTo(db.product_categories, { - as: 'parent_category', - foreignKey: { - name: 'parent_categoryId', - }, - constraints: false, - }); - - - - - db.product_categories.belongsTo(db.users, { - as: 'createdBy', - }); - - db.product_categories.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - - - return product_categories; -}; - - diff --git a/backend/src/db/models/products.js b/backend/src/db/models/products.js deleted file mode 100644 index 51cb494..0000000 --- a/backend/src/db/models/products.js +++ /dev/null @@ -1,210 +0,0 @@ -const config = require('../../config'); -const providers = config.providers; -const crypto = require('crypto'); -const bcrypt = require('bcrypt'); -const moment = require('moment'); - -module.exports = function(sequelize, DataTypes) { - const products = sequelize.define( - 'products', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - -name: { - type: DataTypes.TEXT, - - - - }, - -sku: { - type: DataTypes.TEXT, - - - - }, - -barcode: { - type: DataTypes.TEXT, - - - - }, - -short_description: { - type: DataTypes.TEXT, - - - - }, - -description: { - type: DataTypes.TEXT, - - - - }, - -price: { - type: DataTypes.DECIMAL, - - - - }, - -compare_at_price: { - type: DataTypes.DECIMAL, - - - - }, - -cost: { - type: DataTypes.DECIMAL, - - - - }, - -stock_on_hand: { - type: DataTypes.INTEGER, - - - - }, - -reorder_point: { - type: DataTypes.INTEGER, - - - - }, - -product_status: { - type: DataTypes.ENUM, - - - - values: [ - -"draft", - - -"active", - - -"archived" - - ], - - }, - -track_inventory: { - type: DataTypes.BOOLEAN, - - allowNull: false, - defaultValue: false, - - - - }, - -weight: { - type: DataTypes.DECIMAL, - - - - }, - - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { - timestamps: true, - paranoid: true, - freezeTableName: true, - }, - ); - - products.associate = (db) => { - - -/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity - - - - - - - - - - db.products.hasMany(db.order_items, { - as: 'order_items_product', - foreignKey: { - name: 'productId', - }, - constraints: false, - }); - - - - - -//end loop - - - - db.products.belongsTo(db.product_categories, { - as: 'category', - foreignKey: { - name: 'categoryId', - }, - constraints: false, - }); - - - - db.products.hasMany(db.file, { - as: 'images', - foreignKey: 'belongsToId', - constraints: false, - scope: { - belongsTo: db.products.getTableName(), - belongsToColumn: 'images', - }, - }); - - db.products.hasMany(db.file, { - as: 'attachments', - foreignKey: 'belongsToId', - constraints: false, - scope: { - belongsTo: db.products.getTableName(), - belongsToColumn: 'attachments', - }, - }); - - - db.products.belongsTo(db.users, { - as: 'createdBy', - }); - - db.products.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - - - return products; -}; - - diff --git a/backend/src/db/models/roles.js b/backend/src/db/models/roles.js deleted file mode 100644 index 713b308..0000000 --- a/backend/src/db/models/roles.js +++ /dev/null @@ -1,108 +0,0 @@ -const config = require('../../config'); -const providers = config.providers; -const crypto = require('crypto'); -const bcrypt = require('bcrypt'); -const moment = require('moment'); - -module.exports = function(sequelize, DataTypes) { - const roles = sequelize.define( - 'roles', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - -name: { - type: DataTypes.TEXT, - - - - }, - -role_customization: { - type: DataTypes.TEXT, - - - - }, - - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { - timestamps: true, - paranoid: true, - freezeTableName: true, - }, - ); - - roles.associate = (db) => { - - db.roles.belongsToMany(db.permissions, { - as: 'permissions', - foreignKey: { - name: 'roles_permissionsId', - }, - constraints: false, - through: 'rolesPermissionsPermissions', - }); - - db.roles.belongsToMany(db.permissions, { - as: 'permissions_filter', - foreignKey: { - name: 'roles_permissionsId', - }, - constraints: false, - through: 'rolesPermissionsPermissions', - }); - - -/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity - - - db.roles.hasMany(db.users, { - as: 'users_app_role', - foreignKey: { - name: 'app_roleId', - }, - constraints: false, - }); - - - - - - - - - - - - -//end loop - - - - - - - db.roles.belongsTo(db.users, { - as: 'createdBy', - }); - - db.roles.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - - - return roles; -}; - - diff --git a/backend/src/db/models/shipments.js b/backend/src/db/models/shipments.js deleted file mode 100644 index 2dc4f0f..0000000 --- a/backend/src/db/models/shipments.js +++ /dev/null @@ -1,190 +0,0 @@ -const config = require('../../config'); -const providers = config.providers; -const crypto = require('crypto'); -const bcrypt = require('bcrypt'); -const moment = require('moment'); - -module.exports = function(sequelize, DataTypes) { - const shipments = sequelize.define( - 'shipments', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - -shipment_number: { - type: DataTypes.TEXT, - - - - }, - -shipment_status: { - type: DataTypes.ENUM, - - - - values: [ - -"pending", - - -"packed", - - -"shipped", - - -"in_transit", - - -"delivered", - - -"returned", - - -"lost", - - -"cancelled" - - ], - - }, - -carrier: { - type: DataTypes.TEXT, - - - - }, - -service_level: { - type: DataTypes.TEXT, - - - - }, - -tracking_number: { - type: DataTypes.TEXT, - - - - }, - -packed_at: { - type: DataTypes.DATE, - - - - }, - -shipped_at: { - type: DataTypes.DATE, - - - - }, - -delivered_at: { - type: DataTypes.DATE, - - - - }, - -shipping_cost: { - type: DataTypes.DECIMAL, - - - - }, - -label_url: { - type: DataTypes.TEXT, - - - - }, - -notes: { - type: DataTypes.TEXT, - - - - }, - - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { - timestamps: true, - paranoid: true, - freezeTableName: true, - }, - ); - - shipments.associate = (db) => { - - -/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity - - - - - - - - - - - - - -//end loop - - - - db.shipments.belongsTo(db.orders, { - as: 'order', - foreignKey: { - name: 'orderId', - }, - constraints: false, - }); - - - - db.shipments.hasMany(db.file, { - as: 'shipping_documents', - foreignKey: 'belongsToId', - constraints: false, - scope: { - belongsTo: db.shipments.getTableName(), - belongsToColumn: 'shipping_documents', - }, - }); - - - db.shipments.belongsTo(db.users, { - as: 'createdBy', - }); - - db.shipments.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - - - return shipments; -}; - - diff --git a/backend/src/db/models/users.js b/backend/src/db/models/users.js deleted file mode 100644 index e12c388..0000000 --- a/backend/src/db/models/users.js +++ /dev/null @@ -1,241 +0,0 @@ -const config = require('../../config'); -const providers = config.providers; -const crypto = require('crypto'); -const bcrypt = require('bcrypt'); -const moment = require('moment'); - -module.exports = function(sequelize, DataTypes) { - const users = sequelize.define( - 'users', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - -firstName: { - type: DataTypes.TEXT, - - - - }, - -lastName: { - type: DataTypes.TEXT, - - - - }, - -phoneNumber: { - type: DataTypes.TEXT, - - - - }, - -email: { - type: DataTypes.TEXT, - - - - }, - -disabled: { - type: DataTypes.BOOLEAN, - - allowNull: false, - defaultValue: false, - - - - }, - -password: { - type: DataTypes.TEXT, - - - - }, - -emailVerified: { - type: DataTypes.BOOLEAN, - - allowNull: false, - defaultValue: false, - - - - }, - -emailVerificationToken: { - type: DataTypes.TEXT, - - - - }, - -emailVerificationTokenExpiresAt: { - type: DataTypes.DATE, - - - - }, - -passwordResetToken: { - type: DataTypes.TEXT, - - - - }, - -passwordResetTokenExpiresAt: { - type: DataTypes.DATE, - - - - }, - -provider: { - type: DataTypes.TEXT, - - - - }, - - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { - timestamps: true, - paranoid: true, - freezeTableName: true, - }, - ); - - users.associate = (db) => { - - db.users.belongsToMany(db.permissions, { - as: 'custom_permissions', - foreignKey: { - name: 'users_custom_permissionsId', - }, - constraints: false, - through: 'usersCustom_permissionsPermissions', - }); - - db.users.belongsToMany(db.permissions, { - as: 'custom_permissions_filter', - foreignKey: { - name: 'users_custom_permissionsId', - }, - constraints: false, - through: 'usersCustom_permissionsPermissions', - }); - - -/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity - - - - - - - - - db.users.hasMany(db.orders, { - as: 'orders_assigned_to', - foreignKey: { - name: 'assigned_toId', - }, - constraints: false, - }); - - - - - - -//end loop - - - - db.users.belongsTo(db.roles, { - as: 'app_role', - foreignKey: { - name: 'app_roleId', - }, - constraints: false, - }); - - - - db.users.hasMany(db.file, { - as: 'avatar', - foreignKey: 'belongsToId', - constraints: false, - scope: { - belongsTo: db.users.getTableName(), - belongsToColumn: 'avatar', - }, - }); - - - db.users.belongsTo(db.users, { - as: 'createdBy', - }); - - db.users.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - - users.beforeCreate((users, options) => { - users = trimStringFields(users); - - if (users.provider !== providers.LOCAL && Object.values(providers).indexOf(users.provider) > -1) { - users.emailVerified = true; - - if (!users.password) { - const password = crypto - .randomBytes(20) - .toString('hex'); - - const hashedPassword = bcrypt.hashSync( - password, - config.bcrypt.saltRounds, - ); - - users.password = hashedPassword - } - } - }); - - users.beforeUpdate((users, options) => { - users = trimStringFields(users); - }); - - - return users; -}; - - -function trimStringFields(users) { - users.email = users.email.trim(); - - users.firstName = users.firstName - ? users.firstName.trim() - : null; - - users.lastName = users.lastName - ? users.lastName.trim() - : null; - - return users; -} - diff --git a/backend/src/db/reset.js b/backend/src/db/reset.js deleted file mode 100644 index 5904d4b..0000000 --- a/backend/src/db/reset.js +++ /dev/null @@ -1,16 +0,0 @@ -const db = require('./models'); -const {execSync} = require("child_process"); - -console.log('Resetting Database'); - -db.sequelize - .sync({ force: true }) - .then(() => { - execSync("sequelize db:seed:all"); - console.log('OK'); - process.exit(); - }) - .catch((error) => { - console.error(error); - process.exit(1); - }); diff --git a/backend/src/db/seeders/20200430130759-admin-user.js b/backend/src/db/seeders/20200430130759-admin-user.js deleted file mode 100644 index 018685e..0000000 --- a/backend/src/db/seeders/20200430130759-admin-user.js +++ /dev/null @@ -1,66 +0,0 @@ -'use strict'; -const bcrypt = require("bcrypt"); -const config = require("../../config"); - -const ids = [ - '193bf4b5-9f07-4bd5-9a43-e7e41f3e96af', - 'af5a87be-8f9c-4630-902a-37a60b7005ba', - '5bc531ab-611f-41f3-9373-b7cc5d09c93d', -] - -module.exports = { - up: async (queryInterface, Sequelize) => { - let admin_hash = bcrypt.hashSync(config.admin_pass, config.bcrypt.saltRounds); - let user_hash = bcrypt.hashSync(config.user_pass, config.bcrypt.saltRounds); - - try { - await queryInterface.bulkInsert('users', [ - { - id: ids[0], - firstName: 'Admin', - email: config.admin_email, - emailVerified: true, - provider: config.providers.LOCAL, - password: admin_hash, - createdAt: new Date(), - updatedAt: new Date() - }, - { - id: ids[1], - firstName: 'John', - email: 'john@doe.com', - emailVerified: true, - provider: config.providers.LOCAL, - password: user_hash, - createdAt: new Date(), - updatedAt: new Date() - }, - { - id: ids[2], - firstName: 'Client', - email: 'client@hello.com', - emailVerified: true, - provider: config.providers.LOCAL, - password: user_hash, - createdAt: new Date(), - updatedAt: new Date() - }, - ]); - } catch (error) { - console.error('Error during bulkInsert:', error); - throw error; - } - }, - down: async (queryInterface, Sequelize) => { - try { - await queryInterface.bulkDelete('users', { - id: { - [Sequelize.Op.in]: ids, - }, - }, {}); - } catch (error) { - console.error('Error during bulkDelete:', error); - throw error; - } -} -} diff --git a/backend/src/db/seeders/20200430130760-user-roles.js b/backend/src/db/seeders/20200430130760-user-roles.js deleted file mode 100644 index c0366ba..0000000 --- a/backend/src/db/seeders/20200430130760-user-roles.js +++ /dev/null @@ -1,954 +0,0 @@ - -const { v4: uuid } = require("uuid"); - -module.exports = { - /** - * @param{import("sequelize").QueryInterface} queryInterface - * @return {Promise} - */ - async up(queryInterface) { - const createdAt = new Date(); - const updatedAt = new Date(); - - /** @type {Map} */ - const idMap = new Map(); - - /** - * @param {string} key - * @return {string} - */ - function getId(key) { - if (idMap.has(key)) { - return idMap.get(key); - } - const id = uuid(); - idMap.set(key, id); - return id; - } - - await queryInterface.bulkInsert("roles", [ - - - { id: getId("Administrator"), name: "Administrator", createdAt, updatedAt }, - - - - { id: getId("StoreOwner"), name: "Store Owner", createdAt, updatedAt }, - - { id: getId("OperationsManager"), name: "Operations Manager", createdAt, updatedAt }, - - { id: getId("CatalogSpecialist"), name: "Catalog Specialist", createdAt, updatedAt }, - - { id: getId("FulfillmentCoordinator"), name: "Fulfillment Coordinator", createdAt, updatedAt }, - - { id: getId("PaymentsAnalyst"), name: "Payments Analyst", createdAt, updatedAt }, - - - - { id: getId("Public"), name: "Public", createdAt, updatedAt }, - ]); - - /** - * @param {string} name - */ - function createPermissions(name) { - return [ - { id: getId(`CREATE_${name.toUpperCase()}`), createdAt, updatedAt, name: `CREATE_${name.toUpperCase()}` }, - { id: getId(`READ_${name.toUpperCase()}`), createdAt, updatedAt, name: `READ_${name.toUpperCase()}` }, - { id: getId(`UPDATE_${name.toUpperCase()}`), createdAt, updatedAt, name: `UPDATE_${name.toUpperCase()}` }, - { id: getId(`DELETE_${name.toUpperCase()}`), createdAt, updatedAt, name: `DELETE_${name.toUpperCase()}` } - ]; - } - - const entities = [ - "users","roles","permissions","customers","product_categories","products","orders","order_items","payments","shipments",, - ]; -await queryInterface.bulkInsert("permissions", entities.flatMap(createPermissions)); -await queryInterface.bulkInsert("permissions", [{ id: getId(`READ_API_DOCS`), createdAt, updatedAt, name: `READ_API_DOCS` }]); -await queryInterface.bulkInsert("permissions", [{ id: getId(`CREATE_SEARCH`), createdAt, updatedAt, name: `CREATE_SEARCH`}]); - - -await queryInterface.sequelize.query(`create table "rolesPermissionsPermissions" -( -"createdAt" timestamp with time zone not null, -"updatedAt" timestamp with time zone not null, -"roles_permissionsId" uuid not null, -"permissionId" uuid not null, -primary key ("roles_permissionsId", "permissionId") -);`); - - -await queryInterface.bulkInsert("rolesPermissionsPermissions", [ - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('CREATE_USERS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('READ_USERS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('UPDATE_USERS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('DELETE_USERS') }, - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('READ_USERS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('UPDATE_USERS') }, - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('CREATE_CUSTOMERS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('READ_CUSTOMERS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('UPDATE_CUSTOMERS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('DELETE_CUSTOMERS') }, - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('CREATE_CUSTOMERS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('READ_CUSTOMERS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('UPDATE_CUSTOMERS') }, - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("CatalogSpecialist"), permissionId: getId('READ_CUSTOMERS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("CatalogSpecialist"), permissionId: getId('UPDATE_CUSTOMERS') }, - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("FulfillmentCoordinator"), permissionId: getId('READ_CUSTOMERS') }, - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("PaymentsAnalyst"), permissionId: getId('READ_CUSTOMERS') }, - - - - - - - - - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('CREATE_PRODUCT_CATEGORIES') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('READ_PRODUCT_CATEGORIES') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('UPDATE_PRODUCT_CATEGORIES') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('DELETE_PRODUCT_CATEGORIES') }, - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('CREATE_PRODUCT_CATEGORIES') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('READ_PRODUCT_CATEGORIES') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('UPDATE_PRODUCT_CATEGORIES') }, - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("CatalogSpecialist"), permissionId: getId('CREATE_PRODUCT_CATEGORIES') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("CatalogSpecialist"), permissionId: getId('READ_PRODUCT_CATEGORIES') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("CatalogSpecialist"), permissionId: getId('UPDATE_PRODUCT_CATEGORIES') }, - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("FulfillmentCoordinator"), permissionId: getId('READ_PRODUCT_CATEGORIES') }, - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('CREATE_PRODUCTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('READ_PRODUCTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('UPDATE_PRODUCTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('DELETE_PRODUCTS') }, - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('CREATE_PRODUCTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('READ_PRODUCTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('UPDATE_PRODUCTS') }, - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("CatalogSpecialist"), permissionId: getId('CREATE_PRODUCTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("CatalogSpecialist"), permissionId: getId('READ_PRODUCTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("CatalogSpecialist"), permissionId: getId('UPDATE_PRODUCTS') }, - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("FulfillmentCoordinator"), permissionId: getId('READ_PRODUCTS') }, - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("PaymentsAnalyst"), permissionId: getId('READ_PRODUCTS') }, - - - - - - - - - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('CREATE_ORDERS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('READ_ORDERS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('UPDATE_ORDERS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('DELETE_ORDERS') }, - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('CREATE_ORDERS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('READ_ORDERS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('UPDATE_ORDERS') }, - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("CatalogSpecialist"), permissionId: getId('READ_ORDERS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("CatalogSpecialist"), permissionId: getId('UPDATE_ORDERS') }, - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("FulfillmentCoordinator"), permissionId: getId('READ_ORDERS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("FulfillmentCoordinator"), permissionId: getId('UPDATE_ORDERS') }, - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("PaymentsAnalyst"), permissionId: getId('READ_ORDERS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("PaymentsAnalyst"), permissionId: getId('UPDATE_ORDERS') }, - - - - - - - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('CREATE_ORDER_ITEMS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('READ_ORDER_ITEMS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('UPDATE_ORDER_ITEMS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('DELETE_ORDER_ITEMS') }, - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('CREATE_ORDER_ITEMS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('READ_ORDER_ITEMS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('UPDATE_ORDER_ITEMS') }, - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("CatalogSpecialist"), permissionId: getId('READ_ORDER_ITEMS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("CatalogSpecialist"), permissionId: getId('UPDATE_ORDER_ITEMS') }, - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("FulfillmentCoordinator"), permissionId: getId('READ_ORDER_ITEMS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("FulfillmentCoordinator"), permissionId: getId('UPDATE_ORDER_ITEMS') }, - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("PaymentsAnalyst"), permissionId: getId('READ_ORDER_ITEMS') }, - - - - - - - - - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('CREATE_PAYMENTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('READ_PAYMENTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('UPDATE_PAYMENTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('DELETE_PAYMENTS') }, - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('CREATE_PAYMENTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('READ_PAYMENTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('UPDATE_PAYMENTS') }, - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("CatalogSpecialist"), permissionId: getId('READ_PAYMENTS') }, - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("FulfillmentCoordinator"), permissionId: getId('READ_PAYMENTS') }, - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("PaymentsAnalyst"), permissionId: getId('CREATE_PAYMENTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("PaymentsAnalyst"), permissionId: getId('READ_PAYMENTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("PaymentsAnalyst"), permissionId: getId('UPDATE_PAYMENTS') }, - - - - - - - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('CREATE_SHIPMENTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('READ_SHIPMENTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('UPDATE_SHIPMENTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('DELETE_SHIPMENTS') }, - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('CREATE_SHIPMENTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('READ_SHIPMENTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('UPDATE_SHIPMENTS') }, - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("CatalogSpecialist"), permissionId: getId('READ_SHIPMENTS') }, - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("FulfillmentCoordinator"), permissionId: getId('CREATE_SHIPMENTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("FulfillmentCoordinator"), permissionId: getId('READ_SHIPMENTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("FulfillmentCoordinator"), permissionId: getId('UPDATE_SHIPMENTS') }, - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("PaymentsAnalyst"), permissionId: getId('READ_SHIPMENTS') }, - - - - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("StoreOwner"), permissionId: getId('CREATE_SEARCH') }, - - { createdAt, updatedAt, roles_permissionsId: getId("OperationsManager"), permissionId: getId('CREATE_SEARCH') }, - - { createdAt, updatedAt, roles_permissionsId: getId("CatalogSpecialist"), permissionId: getId('CREATE_SEARCH') }, - - { createdAt, updatedAt, roles_permissionsId: getId("FulfillmentCoordinator"), permissionId: getId('CREATE_SEARCH') }, - - { createdAt, updatedAt, roles_permissionsId: getId("PaymentsAnalyst"), permissionId: getId('CREATE_SEARCH') }, - - - - - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('CREATE_USERS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_USERS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('UPDATE_USERS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('DELETE_USERS') }, - - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('CREATE_ROLES') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_ROLES') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('UPDATE_ROLES') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('DELETE_ROLES') }, - - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('CREATE_PERMISSIONS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_PERMISSIONS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('UPDATE_PERMISSIONS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('DELETE_PERMISSIONS') }, - - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('CREATE_CUSTOMERS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_CUSTOMERS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('UPDATE_CUSTOMERS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('DELETE_CUSTOMERS') }, - - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('CREATE_PRODUCT_CATEGORIES') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_PRODUCT_CATEGORIES') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('UPDATE_PRODUCT_CATEGORIES') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('DELETE_PRODUCT_CATEGORIES') }, - - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('CREATE_PRODUCTS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_PRODUCTS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('UPDATE_PRODUCTS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('DELETE_PRODUCTS') }, - - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('CREATE_ORDERS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_ORDERS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('UPDATE_ORDERS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('DELETE_ORDERS') }, - - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('CREATE_ORDER_ITEMS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_ORDER_ITEMS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('UPDATE_ORDER_ITEMS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('DELETE_ORDER_ITEMS') }, - - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('CREATE_PAYMENTS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_PAYMENTS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('UPDATE_PAYMENTS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('DELETE_PAYMENTS') }, - - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('CREATE_SHIPMENTS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_SHIPMENTS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('UPDATE_SHIPMENTS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('DELETE_SHIPMENTS') }, - - - - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_API_DOCS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('CREATE_SEARCH') }, - ]); - - - await queryInterface.sequelize.query(`UPDATE "users" SET "app_roleId"='${getId("SuperAdmin")}' WHERE "email"='super_admin@flatlogic.com'`); - await queryInterface.sequelize.query(`UPDATE "users" SET "app_roleId"='${getId("Administrator")}' WHERE "email"='admin@flatlogic.com'`); - - - - - - - await queryInterface.sequelize.query(`UPDATE "users" SET "app_roleId"='${getId("StoreOwner")}' WHERE "email"='client@hello.com'`); - await queryInterface.sequelize.query(`UPDATE "users" SET "app_roleId"='${getId("OperationsManager")}' WHERE "email"='john@doe.com'`); - - - - -} -}; - diff --git a/backend/src/db/seeders/20231127130745-sample-data.js b/backend/src/db/seeders/20231127130745-sample-data.js deleted file mode 100644 index 48582fd..0000000 --- a/backend/src/db/seeders/20231127130745-sample-data.js +++ /dev/null @@ -1,3800 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - -const db = require('../models'); -const Users = db.users; - - - - - - -const Customers = db.customers; - -const ProductCategories = db.product_categories; - -const Products = db.products; - -const Orders = db.orders; - -const OrderItems = db.order_items; - -const Payments = db.payments; - -const Shipments = db.shipments; - - - - - - - -const CustomersData = [ - - { - - - - - "customer_code": "CUST-10001", - - - - - - - "full_name": "Samira Hassan", - - - - - - - "email": "samira.hassan@example.com", - - - - - - - "phone": "+1-415-555-0138", - - - - - - - "billing_address": "455 Market St, San Francisco, CA 94105, USA", - - - - - - - "shipping_address": "455 Market St, San Francisco, CA 94105, USA", - - - - - - - "customer_status": "inactive", - - - - - - - "registered_at": new Date('2026-02-14T10:00:00Z'), - - - - - - - "notes": "Prefers delivery on weekdays.", - - - - }, - - { - - - - - "customer_code": "CUST-10002", - - - - - - - "full_name": "Ethan Brooks", - - - - - - - "email": "ethan.brooks@example.com", - - - - - - - "phone": "+1-646-555-0192", - - - - - - - "billing_address": "18 W 29th St, New York, NY 10001, USA", - - - - - - - "shipping_address": "200 Madison Ave, New York, NY 10016, USA", - - - - - - - "customer_status": "blocked", - - - - - - - "registered_at": new Date('2026-03-02T15:30:00Z'), - - - - - - - "notes": "Leave package with front desk.", - - - - }, - - { - - - - - "customer_code": "CUST-10003", - - - - - - - "full_name": "Priya Nair", - - - - - - - "email": "priya.nair@example.com", - - - - - - - "phone": "+1-312-555-0175", - - - - - - - "billing_address": "233 S Wacker Dr, Chicago, IL 60606, USA", - - - - - - - "shipping_address": "233 S Wacker Dr, Chicago, IL 60606, USA", - - - - - - - "customer_status": "active", - - - - - - - "registered_at": new Date('2026-01-20T09:45:00Z'), - - - - - - - "notes": "VAT exempt documentation on file.", - - - - }, - - { - - - - - "customer_code": "CUST-10004", - - - - - - - "full_name": "Lucas Meyer", - - - - - - - "email": "lucas.meyer@example.com", - - - - - - - "phone": "+1-206-555-0109", - - - - - - - "billing_address": "1201 3rd Ave, Seattle, WA 98101, USA", - - - - - - - "shipping_address": "1201 3rd Ave, Seattle, WA 98101, USA", - - - - - - - "customer_status": "active", - - - - - - - "registered_at": new Date('2025-11-18T13:10:00Z'), - - - - - - - "notes": "No recent orders in 6 months.", - - - - }, - -]; - - - -const ProductCategoriesData = [ - - { - - - - - "name": "Electronics", - - - - - - - "slug": "electronics", - - - - - - - "description": "Devices, accessories, and peripherals.", - - - - - - - // type code here for "relation_one" field - - - - - - - "is_active": true, - - - - }, - - { - - - - - "name": "Audio", - - - - - - - "slug": "audio", - - - - - - - "description": "Headphones, speakers, and audio accessories.", - - - - - - - // type code here for "relation_one" field - - - - - - - "is_active": true, - - - - }, - - { - - - - - "name": "Office", - - - - - - - "slug": "office", - - - - - - - "description": "Office essentials and desk accessories.", - - - - - - - // type code here for "relation_one" field - - - - - - - "is_active": true, - - - - }, - - { - - - - - "name": "Home", - - - - - - - "slug": "home", - - - - - - - "description": "Home goods and small essentials.", - - - - - - - // type code here for "relation_one" field - - - - - - - "is_active": true, - - - - }, - -]; - - - -const ProductsData = [ - - { - - - - - "name": "Wireless Noise-Canceling Headphones", - - - - - - - "sku": "AUD-HDPH-001", - - - - - - - "barcode": "0850001234567", - - - - - - - "short_description": "Over-ear headphones with active noise cancellation.", - - - - - - - "description": "Comfort-fit over-ear headphones with active noise cancellation and up to 30 hours battery life.", - - - - - - - "price": 199.99, - - - - - - - "compare_at_price": 249.99, - - - - - - - "cost": 110.0, - - - - - - - "stock_on_hand": 42, - - - - - - - "reorder_point": 10, - - - - - - - "product_status": "active", - - - - - - - // type code here for "relation_one" field - - - - - - - // type code here for "images" field - - - - - - - // type code here for "files" field - - - - - - - "track_inventory": true, - - - - - - - "weight": 0.55, - - - - }, - - { - - - - - "name": "USB-C Fast Charger 65W", - - - - - - - "sku": "CHG-USBC-065", - - - - - - - "barcode": "0850002345678", - - - - - - - "short_description": "Compact 65W USB-C PD charger.", - - - - - - - "description": "GaN 65W USB-C Power Delivery charger suitable for laptops and phones.", - - - - - - - "price": 39.99, - - - - - - - "compare_at_price": 49.99, - - - - - - - "cost": 18.5, - - - - - - - "stock_on_hand": 120, - - - - - - - "reorder_point": 25, - - - - - - - "product_status": "active", - - - - - - - // type code here for "relation_one" field - - - - - - - // type code here for "images" field - - - - - - - // type code here for "files" field - - - - - - - "track_inventory": true, - - - - - - - "weight": 0.22, - - - - }, - - { - - - - - "name": "Braided USB-C Cable 2m", - - - - - - - "sku": "CBL-USBC-2M", - - - - - - - "barcode": "0850003456789", - - - - - - - "short_description": "Durable braided USB-C to USB-C cable.", - - - - - - - "description": "2-meter braided USB-C cable rated for 100W charging and high-speed data transfer.", - - - - - - - "price": 14.99, - - - - - - - "compare_at_price": 19.99, - - - - - - - "cost": 5.25, - - - - - - - "stock_on_hand": 300, - - - - - - - "reorder_point": 75, - - - - - - - "product_status": "active", - - - - - - - // type code here for "relation_one" field - - - - - - - // type code here for "images" field - - - - - - - // type code here for "files" field - - - - - - - "track_inventory": true, - - - - - - - "weight": 0.09, - - - - }, - - { - - - - - "name": "Ergonomic Desk Mat", - - - - - - - "sku": "OFF-MAT-ERG", - - - - - - - "barcode": "0850004567890", - - - - - - - "short_description": "Non-slip desk mat for office setups.", - - - - - - - "description": "Large non-slip desk mat with smooth surface for keyboard and mouse use.", - - - - - - - "price": 24.99, - - - - - - - "compare_at_price": 29.99, - - - - - - - "cost": 9.75, - - - - - - - "stock_on_hand": 85, - - - - - - - "reorder_point": 20, - - - - - - - "product_status": "archived", - - - - - - - // type code here for "relation_one" field - - - - - - - // type code here for "images" field - - - - - - - // type code here for "files" field - - - - - - - "track_inventory": true, - - - - - - - "weight": 0.65, - - - - }, - -]; - - - -const OrdersData = [ - - { - - - - - "order_number": "ORD-2026-000101", - - - - - - - // type code here for "relation_one" field - - - - - - - "order_status": "delivered", - - - - - - - "fulfillment_status": "fulfilled", - - - - - - - "payment_status": "paid", - - - - - - - "placed_at": new Date('2026-04-20T10:15:00Z'), - - - - - - - "packed_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "shipped_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "delivered_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "subtotal_amount": 214.98, - - - - - - - "discount_amount": 10.0, - - - - - - - "tax_amount": 17.2, - - - - - - - "shipping_amount": 8.99, - - - - - - - "total_amount": 231.17, - - - - - - - "currency": "USD", - - - - - - - "shipping_name": "Samira Hassan", - - - - - - - "shipping_address": "455 Market St, San Francisco, CA 94105, USA", - - - - - - - "billing_name": "Samira Hassan", - - - - - - - "billing_address": "455 Market St, San Francisco, CA 94105, USA", - - - - - - - "notes_internal": "Priority packing requested by customer service.", - - - - - - - "customer_note": "Please ship in minimal packaging.", - - - - - - - "tracking_number": "", - - - - - - - "carrier": "", - - - - - - - // type code here for "relation_one" field - - - - }, - - { - - - - - "order_number": "ORD-2026-000102", - - - - - - - // type code here for "relation_one" field - - - - - - - "order_status": "pending_payment", - - - - - - - "fulfillment_status": "fulfilled", - - - - - - - "payment_status": "partially_refunded", - - - - - - - "placed_at": new Date('2026-04-21T16:40:00Z'), - - - - - - - "packed_at": new Date('2026-04-22T09:05:00Z'), - - - - - - - "shipped_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "delivered_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "subtotal_amount": 39.99, - - - - - - - "discount_amount": 0.0, - - - - - - - "tax_amount": 3.2, - - - - - - - "shipping_amount": 6.99, - - - - - - - "total_amount": 50.18, - - - - - - - "currency": "USD", - - - - - - - "shipping_name": "Ethan Brooks", - - - - - - - "shipping_address": "200 Madison Ave, New York, NY 10016, USA", - - - - - - - "billing_name": "Ethan Brooks", - - - - - - - "billing_address": "18 W 29th St, New York, NY 10001, USA", - - - - - - - "notes_internal": "Hold for address verification completed.", - - - - - - - "customer_note": "Leave with front desk.", - - - - - - - "tracking_number": "", - - - - - - - "carrier": "", - - - - - - - // type code here for "relation_one" field - - - - }, - - { - - - - - "order_number": "ORD-2026-000103", - - - - - - - // type code here for "relation_one" field - - - - - - - "order_status": "shipped", - - - - - - - "fulfillment_status": "fulfilled", - - - - - - - "payment_status": "partially_refunded", - - - - - - - "placed_at": new Date('2026-04-18T12:05:00Z'), - - - - - - - "packed_at": new Date('2026-04-18T16:10:00Z'), - - - - - - - "shipped_at": new Date('2026-04-19T09:20:00Z'), - - - - - - - "delivered_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "subtotal_amount": 199.99, - - - - - - - "discount_amount": 0.0, - - - - - - - "tax_amount": 16.0, - - - - - - - "shipping_amount": 0.0, - - - - - - - "total_amount": 215.99, - - - - - - - "currency": "USD", - - - - - - - "shipping_name": "Priya Nair", - - - - - - - "shipping_address": "233 S Wacker Dr, Chicago, IL 60606, USA", - - - - - - - "billing_name": "Priya Nair", - - - - - - - "billing_address": "233 S Wacker Dr, Chicago, IL 60606, USA", - - - - - - - "notes_internal": "Free shipping applied for threshold.", - - - - - - - "customer_note": "", - - - - - - - "tracking_number": "1Z999AA10123456784", - - - - - - - "carrier": "UPS", - - - - - - - // type code here for "relation_one" field - - - - }, - - { - - - - - "order_number": "ORD-2026-000104", - - - - - - - // type code here for "relation_one" field - - - - - - - "order_status": "packed", - - - - - - - "fulfillment_status": "fulfilled", - - - - - - - "payment_status": "refunded", - - - - - - - "placed_at": new Date('2026-04-28T17:55:00Z'), - - - - - - - "packed_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "shipped_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "delivered_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "subtotal_amount": 52.97, - - - - - - - "discount_amount": 5.0, - - - - - - - "tax_amount": 3.9, - - - - - - - "shipping_amount": 7.99, - - - - - - - "total_amount": 59.86, - - - - - - - "currency": "USD", - - - - - - - "shipping_name": "Daniela Silva", - - - - - - - "shipping_address": "500 W 2nd St, Austin, TX 78701, USA", - - - - - - - "billing_name": "Daniela Silva", - - - - - - - "billing_address": "98 San Jacinto Blvd, Austin, TX 78701, USA", - - - - - - - "notes_internal": "Awaiting payment confirmation.", - - - - - - - "customer_note": "Signature required.", - - - - - - - "tracking_number": "", - - - - - - - "carrier": "", - - - - - - - // type code here for "relation_one" field - - - - }, - -]; - - - -const OrderItemsData = [ - - { - - - - - // type code here for "relation_one" field - - - - - - - // type code here for "relation_one" field - - - - - - - "product_name_snapshot": "Wireless Noise-Canceling Headphones", - - - - - - - "sku_snapshot": "AUD-HDPH-001", - - - - - - - "unit_price": 199.99, - - - - - - - "quantity": 1, - - - - - - - "line_discount_amount": 10.0, - - - - - - - "line_tax_amount": 15.2, - - - - - - - "line_total_amount": 205.19, - - - - - - - "item_fulfillment_status": "fulfilled", - - - - }, - - { - - - - - // type code here for "relation_one" field - - - - - - - // type code here for "relation_one" field - - - - - - - "product_name_snapshot": "Braided USB-C Cable 2m", - - - - - - - "sku_snapshot": "CBL-USBC-2M", - - - - - - - "unit_price": 14.99, - - - - - - - "quantity": 1, - - - - - - - "line_discount_amount": 0.0, - - - - - - - "line_tax_amount": 1.2, - - - - - - - "line_total_amount": 16.19, - - - - - - - "item_fulfillment_status": "fulfilled", - - - - }, - - { - - - - - // type code here for "relation_one" field - - - - - - - // type code here for "relation_one" field - - - - - - - "product_name_snapshot": "USB-C Fast Charger 65W", - - - - - - - "sku_snapshot": "CHG-USBC-065", - - - - - - - "unit_price": 39.99, - - - - - - - "quantity": 1, - - - - - - - "line_discount_amount": 0.0, - - - - - - - "line_tax_amount": 3.2, - - - - - - - "line_total_amount": 43.19, - - - - - - - "item_fulfillment_status": "returned", - - - - }, - - { - - - - - // type code here for "relation_one" field - - - - - - - // type code here for "relation_one" field - - - - - - - "product_name_snapshot": "Smart LED Bulb A19", - - - - - - - "sku_snapshot": "HOM-BULB-A19", - - - - - - - "unit_price": 12.99, - - - - - - - "quantity": 2, - - - - - - - "line_discount_amount": 5.0, - - - - - - - "line_tax_amount": 1.6, - - - - - - - "line_total_amount": 22.58, - - - - - - - "item_fulfillment_status": "returned", - - - - }, - -]; - - - -const PaymentsData = [ - - { - - - - - "payment_reference": "PAY-2026-900001", - - - - - - - // type code here for "relation_one" field - - - - - - - "amount": 231.17, - - - - - - - "currency": "USD", - - - - - - - "payment_method": "cash_on_delivery", - - - - - - - "payment_provider": "other", - - - - - - - "payment_status": "cancelled", - - - - - - - "initiated_at": new Date('2026-04-20T10:16:00Z'), - - - - - - - "captured_at": new Date('2026-04-20T10:16:30Z'), - - - - - - - "refunded_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "provider_transaction_id": "pi_3QExample001", - - - - - - - "failure_reason": "", - - - - - - - "is_test": false, - - - - }, - - { - - - - - "payment_reference": "PAY-2026-900002", - - - - - - - // type code here for "relation_one" field - - - - - - - "amount": 50.18, - - - - - - - "currency": "USD", - - - - - - - "payment_method": "wallet", - - - - - - - "payment_provider": "stripe", - - - - - - - "payment_status": "captured", - - - - - - - "initiated_at": new Date('2026-04-21T16:41:00Z'), - - - - - - - "captured_at": new Date('2026-04-21T16:41:40Z'), - - - - - - - "refunded_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "provider_transaction_id": "txn_Example002", - - - - - - - "failure_reason": "", - - - - - - - "is_test": true, - - - - }, - - { - - - - - "payment_reference": "PAY-2026-900003", - - - - - - - // type code here for "relation_one" field - - - - - - - "amount": 215.99, - - - - - - - "currency": "USD", - - - - - - - "payment_method": "other", - - - - - - - "payment_provider": "manual", - - - - - - - "payment_status": "captured", - - - - - - - "initiated_at": new Date('2026-04-18T12:06:00Z'), - - - - - - - "captured_at": new Date('2026-04-18T12:06:20Z'), - - - - - - - "refunded_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "provider_transaction_id": "ady_Example003", - - - - - - - "failure_reason": "", - - - - - - - "is_test": false, - - - - }, - - { - - - - - "payment_reference": "PAY-2026-900004", - - - - - - - // type code here for "relation_one" field - - - - - - - "amount": 59.86, - - - - - - - "currency": "USD", - - - - - - - "payment_method": "cash_on_delivery", - - - - - - - "payment_provider": "adyen", - - - - - - - "payment_status": "failed", - - - - - - - "initiated_at": new Date('2026-04-28T18:10:00Z'), - - - - - - - "captured_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "refunded_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "provider_transaction_id": "manual_bt_Example004", - - - - - - - "failure_reason": "", - - - - - - - "is_test": true, - - - - }, - -]; - - - -const ShipmentsData = [ - - { - - - - - "shipment_number": "SHP-2026-500001", - - - - - - - // type code here for "relation_one" field - - - - - - - "shipment_status": "shipped", - - - - - - - "carrier": "UPS", - - - - - - - "service_level": "Ground", - - - - - - - "tracking_number": "1Z999AA10123456784", - - - - - - - "packed_at": new Date('2026-04-18T16:10:00Z'), - - - - - - - "shipped_at": new Date('2026-04-19T09:20:00Z'), - - - - - - - "delivered_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "shipping_cost": 0.0, - - - - - - - "label_url": "https://labels.example.com/SHP-2026-500001.pdf", - - - - - - - // type code here for "files" field - - - - - - - "notes": "Left sorting facility on schedule.", - - - - }, - - { - - - - - "shipment_number": "SHP-2026-500002", - - - - - - - // type code here for "relation_one" field - - - - - - - "shipment_status": "delivered", - - - - - - - "carrier": "USPS", - - - - - - - "service_level": "Priority", - - - - - - - "tracking_number": "9400111899220000000000", - - - - - - - "packed_at": new Date('2026-04-22T09:05:00Z'), - - - - - - - "shipped_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "delivered_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "shipping_cost": 6.99, - - - - - - - "label_url": "https://labels.example.com/SHP-2026-500002.pdf", - - - - - - - // type code here for "files" field - - - - - - - "notes": "Ready for pickup by carrier.", - - - - }, - - { - - - - - "shipment_number": "SHP-2026-500003", - - - - - - - // type code here for "relation_one" field - - - - - - - "shipment_status": "packed", - - - - - - - "carrier": "FedEx", - - - - - - - "service_level": "2Day", - - - - - - - "tracking_number": "", - - - - - - - "packed_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "shipped_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "delivered_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "shipping_cost": 8.99, - - - - - - - "label_url": "", - - - - - - - // type code here for "files" field - - - - - - - "notes": "Awaiting packing completion.", - - - - }, - - { - - - - - "shipment_number": "SHP-2026-500004", - - - - - - - // type code here for "relation_one" field - - - - - - - "shipment_status": "packed", - - - - - - - "carrier": "UPS", - - - - - - - "service_level": "Ground", - - - - - - - "tracking_number": "", - - - - - - - "packed_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "shipped_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "delivered_at": new Date('2020-01-01T00:00:00Z'), - - - - - - - "shipping_cost": 7.99, - - - - - - - "label_url": "", - - - - - - - // type code here for "files" field - - - - - - - "notes": "Will ship after payment capture.", - - - - }, - -]; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Similar logic for "relation_many" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - async function associateProductCategoryWithParent_category() { - - const relatedParent_category0 = await ProductCategories.findOne({ - offset: Math.floor(Math.random() * (await ProductCategories.count())), - }); - const ProductCategory0 = await ProductCategories.findOne({ - order: [['id', 'ASC']], - offset: 0 - }); - if (ProductCategory0?.setParent_category) - { - await - ProductCategory0. - setParent_category(relatedParent_category0); - } - - const relatedParent_category1 = await ProductCategories.findOne({ - offset: Math.floor(Math.random() * (await ProductCategories.count())), - }); - const ProductCategory1 = await ProductCategories.findOne({ - order: [['id', 'ASC']], - offset: 1 - }); - if (ProductCategory1?.setParent_category) - { - await - ProductCategory1. - setParent_category(relatedParent_category1); - } - - const relatedParent_category2 = await ProductCategories.findOne({ - offset: Math.floor(Math.random() * (await ProductCategories.count())), - }); - const ProductCategory2 = await ProductCategories.findOne({ - order: [['id', 'ASC']], - offset: 2 - }); - if (ProductCategory2?.setParent_category) - { - await - ProductCategory2. - setParent_category(relatedParent_category2); - } - - const relatedParent_category3 = await ProductCategories.findOne({ - offset: Math.floor(Math.random() * (await ProductCategories.count())), - }); - const ProductCategory3 = await ProductCategories.findOne({ - order: [['id', 'ASC']], - offset: 3 - }); - if (ProductCategory3?.setParent_category) - { - await - ProductCategory3. - setParent_category(relatedParent_category3); - } - - } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - async function associateProductWithCategory() { - - const relatedCategory0 = await ProductCategories.findOne({ - offset: Math.floor(Math.random() * (await ProductCategories.count())), - }); - const Product0 = await Products.findOne({ - order: [['id', 'ASC']], - offset: 0 - }); - if (Product0?.setCategory) - { - await - Product0. - setCategory(relatedCategory0); - } - - const relatedCategory1 = await ProductCategories.findOne({ - offset: Math.floor(Math.random() * (await ProductCategories.count())), - }); - const Product1 = await Products.findOne({ - order: [['id', 'ASC']], - offset: 1 - }); - if (Product1?.setCategory) - { - await - Product1. - setCategory(relatedCategory1); - } - - const relatedCategory2 = await ProductCategories.findOne({ - offset: Math.floor(Math.random() * (await ProductCategories.count())), - }); - const Product2 = await Products.findOne({ - order: [['id', 'ASC']], - offset: 2 - }); - if (Product2?.setCategory) - { - await - Product2. - setCategory(relatedCategory2); - } - - const relatedCategory3 = await ProductCategories.findOne({ - offset: Math.floor(Math.random() * (await ProductCategories.count())), - }); - const Product3 = await Products.findOne({ - order: [['id', 'ASC']], - offset: 3 - }); - if (Product3?.setCategory) - { - await - Product3. - setCategory(relatedCategory3); - } - - } - - - - - - - - - - - - - - - - - - - async function associateOrderWithCustomer() { - - const relatedCustomer0 = await Customers.findOne({ - offset: Math.floor(Math.random() * (await Customers.count())), - }); - const Order0 = await Orders.findOne({ - order: [['id', 'ASC']], - offset: 0 - }); - if (Order0?.setCustomer) - { - await - Order0. - setCustomer(relatedCustomer0); - } - - const relatedCustomer1 = await Customers.findOne({ - offset: Math.floor(Math.random() * (await Customers.count())), - }); - const Order1 = await Orders.findOne({ - order: [['id', 'ASC']], - offset: 1 - }); - if (Order1?.setCustomer) - { - await - Order1. - setCustomer(relatedCustomer1); - } - - const relatedCustomer2 = await Customers.findOne({ - offset: Math.floor(Math.random() * (await Customers.count())), - }); - const Order2 = await Orders.findOne({ - order: [['id', 'ASC']], - offset: 2 - }); - if (Order2?.setCustomer) - { - await - Order2. - setCustomer(relatedCustomer2); - } - - const relatedCustomer3 = await Customers.findOne({ - offset: Math.floor(Math.random() * (await Customers.count())), - }); - const Order3 = await Orders.findOne({ - order: [['id', 'ASC']], - offset: 3 - }); - if (Order3?.setCustomer) - { - await - Order3. - setCustomer(relatedCustomer3); - } - - } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - async function associateOrderWithAssigned_to() { - - const relatedAssigned_to0 = await Users.findOne({ - offset: Math.floor(Math.random() * (await Users.count())), - }); - const Order0 = await Orders.findOne({ - order: [['id', 'ASC']], - offset: 0 - }); - if (Order0?.setAssigned_to) - { - await - Order0. - setAssigned_to(relatedAssigned_to0); - } - - const relatedAssigned_to1 = await Users.findOne({ - offset: Math.floor(Math.random() * (await Users.count())), - }); - const Order1 = await Orders.findOne({ - order: [['id', 'ASC']], - offset: 1 - }); - if (Order1?.setAssigned_to) - { - await - Order1. - setAssigned_to(relatedAssigned_to1); - } - - const relatedAssigned_to2 = await Users.findOne({ - offset: Math.floor(Math.random() * (await Users.count())), - }); - const Order2 = await Orders.findOne({ - order: [['id', 'ASC']], - offset: 2 - }); - if (Order2?.setAssigned_to) - { - await - Order2. - setAssigned_to(relatedAssigned_to2); - } - - const relatedAssigned_to3 = await Users.findOne({ - offset: Math.floor(Math.random() * (await Users.count())), - }); - const Order3 = await Orders.findOne({ - order: [['id', 'ASC']], - offset: 3 - }); - if (Order3?.setAssigned_to) - { - await - Order3. - setAssigned_to(relatedAssigned_to3); - } - - } - - - - - - - - - async function associateOrderItemWithOrder() { - - const relatedOrder0 = await Orders.findOne({ - offset: Math.floor(Math.random() * (await Orders.count())), - }); - const OrderItem0 = await OrderItems.findOne({ - order: [['id', 'ASC']], - offset: 0 - }); - if (OrderItem0?.setOrder) - { - await - OrderItem0. - setOrder(relatedOrder0); - } - - const relatedOrder1 = await Orders.findOne({ - offset: Math.floor(Math.random() * (await Orders.count())), - }); - const OrderItem1 = await OrderItems.findOne({ - order: [['id', 'ASC']], - offset: 1 - }); - if (OrderItem1?.setOrder) - { - await - OrderItem1. - setOrder(relatedOrder1); - } - - const relatedOrder2 = await Orders.findOne({ - offset: Math.floor(Math.random() * (await Orders.count())), - }); - const OrderItem2 = await OrderItems.findOne({ - order: [['id', 'ASC']], - offset: 2 - }); - if (OrderItem2?.setOrder) - { - await - OrderItem2. - setOrder(relatedOrder2); - } - - const relatedOrder3 = await Orders.findOne({ - offset: Math.floor(Math.random() * (await Orders.count())), - }); - const OrderItem3 = await OrderItems.findOne({ - order: [['id', 'ASC']], - offset: 3 - }); - if (OrderItem3?.setOrder) - { - await - OrderItem3. - setOrder(relatedOrder3); - } - - } - - - - - async function associateOrderItemWithProduct() { - - const relatedProduct0 = await Products.findOne({ - offset: Math.floor(Math.random() * (await Products.count())), - }); - const OrderItem0 = await OrderItems.findOne({ - order: [['id', 'ASC']], - offset: 0 - }); - if (OrderItem0?.setProduct) - { - await - OrderItem0. - setProduct(relatedProduct0); - } - - const relatedProduct1 = await Products.findOne({ - offset: Math.floor(Math.random() * (await Products.count())), - }); - const OrderItem1 = await OrderItems.findOne({ - order: [['id', 'ASC']], - offset: 1 - }); - if (OrderItem1?.setProduct) - { - await - OrderItem1. - setProduct(relatedProduct1); - } - - const relatedProduct2 = await Products.findOne({ - offset: Math.floor(Math.random() * (await Products.count())), - }); - const OrderItem2 = await OrderItems.findOne({ - order: [['id', 'ASC']], - offset: 2 - }); - if (OrderItem2?.setProduct) - { - await - OrderItem2. - setProduct(relatedProduct2); - } - - const relatedProduct3 = await Products.findOne({ - offset: Math.floor(Math.random() * (await Products.count())), - }); - const OrderItem3 = await OrderItems.findOne({ - order: [['id', 'ASC']], - offset: 3 - }); - if (OrderItem3?.setProduct) - { - await - OrderItem3. - setProduct(relatedProduct3); - } - - } - - - - - - - - - - - - - - - - - - - - - - - - - - - async function associatePaymentWithOrder() { - - const relatedOrder0 = await Orders.findOne({ - offset: Math.floor(Math.random() * (await Orders.count())), - }); - const Payment0 = await Payments.findOne({ - order: [['id', 'ASC']], - offset: 0 - }); - if (Payment0?.setOrder) - { - await - Payment0. - setOrder(relatedOrder0); - } - - const relatedOrder1 = await Orders.findOne({ - offset: Math.floor(Math.random() * (await Orders.count())), - }); - const Payment1 = await Payments.findOne({ - order: [['id', 'ASC']], - offset: 1 - }); - if (Payment1?.setOrder) - { - await - Payment1. - setOrder(relatedOrder1); - } - - const relatedOrder2 = await Orders.findOne({ - offset: Math.floor(Math.random() * (await Orders.count())), - }); - const Payment2 = await Payments.findOne({ - order: [['id', 'ASC']], - offset: 2 - }); - if (Payment2?.setOrder) - { - await - Payment2. - setOrder(relatedOrder2); - } - - const relatedOrder3 = await Orders.findOne({ - offset: Math.floor(Math.random() * (await Orders.count())), - }); - const Payment3 = await Payments.findOne({ - order: [['id', 'ASC']], - offset: 3 - }); - if (Payment3?.setOrder) - { - await - Payment3. - setOrder(relatedOrder3); - } - - } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - async function associateShipmentWithOrder() { - - const relatedOrder0 = await Orders.findOne({ - offset: Math.floor(Math.random() * (await Orders.count())), - }); - const Shipment0 = await Shipments.findOne({ - order: [['id', 'ASC']], - offset: 0 - }); - if (Shipment0?.setOrder) - { - await - Shipment0. - setOrder(relatedOrder0); - } - - const relatedOrder1 = await Orders.findOne({ - offset: Math.floor(Math.random() * (await Orders.count())), - }); - const Shipment1 = await Shipments.findOne({ - order: [['id', 'ASC']], - offset: 1 - }); - if (Shipment1?.setOrder) - { - await - Shipment1. - setOrder(relatedOrder1); - } - - const relatedOrder2 = await Orders.findOne({ - offset: Math.floor(Math.random() * (await Orders.count())), - }); - const Shipment2 = await Shipments.findOne({ - order: [['id', 'ASC']], - offset: 2 - }); - if (Shipment2?.setOrder) - { - await - Shipment2. - setOrder(relatedOrder2); - } - - const relatedOrder3 = await Orders.findOne({ - offset: Math.floor(Math.random() * (await Orders.count())), - }); - const Shipment3 = await Shipments.findOne({ - order: [['id', 'ASC']], - offset: 3 - }); - if (Shipment3?.setOrder) - { - await - Shipment3. - setOrder(relatedOrder3); - } - - } - - - - - - - - - - - - - - - - - - - - - - - - - - -module.exports = { - up: async (queryInterface, Sequelize) => { - - - - - - - - await Customers.bulkCreate(CustomersData); - - - - - await ProductCategories.bulkCreate(ProductCategoriesData); - - - - - await Products.bulkCreate(ProductsData); - - - - - await Orders.bulkCreate(OrdersData); - - - - - await OrderItems.bulkCreate(OrderItemsData); - - - - - await Payments.bulkCreate(PaymentsData); - - - - - await Shipments.bulkCreate(ShipmentsData); - - - await Promise.all([ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Similar logic for "relation_many" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - await associateProductCategoryWithParent_category(), - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - await associateProductWithCategory(), - - - - - - - - - - - - - - - - - - await associateOrderWithCustomer(), - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - await associateOrderWithAssigned_to(), - - - - - - - - await associateOrderItemWithOrder(), - - - - - await associateOrderItemWithProduct(), - - - - - - - - - - - - - - - - - - - - - - - - - - await associatePaymentWithOrder(), - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - await associateShipmentWithOrder(), - - - - - - - - - - - - - - - - - - - - - - - - - - ]); - - }, - - down: async (queryInterface, Sequelize) => { - - - - - - - await queryInterface.bulkDelete('customers', null, {}); - - - await queryInterface.bulkDelete('product_categories', null, {}); - - - await queryInterface.bulkDelete('products', null, {}); - - - await queryInterface.bulkDelete('orders', null, {}); - - - await queryInterface.bulkDelete('order_items', null, {}); - - - await queryInterface.bulkDelete('payments', null, {}); - - - await queryInterface.bulkDelete('shipments', null, {}); - - - }, -}; \ No newline at end of file diff --git a/backend/src/db/utils.js b/backend/src/db/utils.js deleted file mode 100644 index c253a07..0000000 --- a/backend/src/db/utils.js +++ /dev/null @@ -1,27 +0,0 @@ -const validator = require('validator'); -const { v4: uuid } = require('uuid'); -const Sequelize = require('./models').Sequelize; - -module.exports = class Utils { - static uuid(value) { - let id = value; - - if (!validator.isUUID(id)) { - id = uuid(); - } - - return id; - } - - static ilike(model, column, value) { - return Sequelize.where( - Sequelize.fn( - 'lower', - Sequelize.col(`${model}.${column}`), - ), - { - [Sequelize.Op.like]: `%${value}%`.toLowerCase(), - }, - ); - } -}; diff --git a/backend/src/helpers.js b/backend/src/helpers.js deleted file mode 100644 index c38440d..0000000 --- a/backend/src/helpers.js +++ /dev/null @@ -1,23 +0,0 @@ -const jwt = require('jsonwebtoken'); -const config = require('./config'); - -module.exports = class Helpers { - static wrapAsync(fn) { - return function (req, res, next) { - fn(req, res, next).catch(next); - }; - } - - static commonErrorHandler(error, req, res, next) { - if ([400, 403, 404].includes(error.code)) { - return res.status(error.code).send(error.message); - } - - console.error(error); - return res.status(500).send(error.message); - } - - static jwtSign(data) { - return jwt.sign(data, config.secret_key, {expiresIn: '6h'}); - }; -}; diff --git a/backend/src/index.js b/backend/src/index.js deleted file mode 100644 index 2d3a487..0000000 --- a/backend/src/index.js +++ /dev/null @@ -1,164 +0,0 @@ - -const express = require('express'); -const cors = require('cors'); -const app = express(); -const passport = require('passport'); -const path = require('path'); -const fs = require('fs'); -const bodyParser = require('body-parser'); -const db = require('./db/models'); -const config = require('./config'); -const swaggerUI = require('swagger-ui-express'); -const swaggerJsDoc = require('swagger-jsdoc'); - -const authRoutes = require('./routes/auth'); -const fileRoutes = require('./routes/file'); -const searchRoutes = require('./routes/search'); -const sqlRoutes = require('./routes/sql'); -const pexelsRoutes = require('./routes/pexels'); - -const openaiRoutes = require('./routes/openai'); - - - -const usersRoutes = require('./routes/users'); - -const rolesRoutes = require('./routes/roles'); - -const permissionsRoutes = require('./routes/permissions'); - -const customersRoutes = require('./routes/customers'); - -const product_categoriesRoutes = require('./routes/product_categories'); - -const productsRoutes = require('./routes/products'); - -const ordersRoutes = require('./routes/orders'); - -const order_itemsRoutes = require('./routes/order_items'); - -const paymentsRoutes = require('./routes/payments'); - -const shipmentsRoutes = require('./routes/shipments'); - - -const getBaseUrl = (url) => { - if (!url) return ''; - return url.endsWith('/api') ? url.slice(0, -4) : url; -}; - -const options = { - definition: { - openapi: "3.0.0", - info: { - version: "1.0.0", - title: "Store Operations Hub", - description: "Store Operations Hub Online REST API for Testing and Prototyping application. You can perform all major operations with your entities - create, delete and etc.", - }, - servers: [ - { - url: getBaseUrl(process.env.NEXT_PUBLIC_BACK_API) || config.swaggerUrl, - description: "Development server", - } - ], - components: { - securitySchemes: { - bearerAuth: { - type: 'http', - scheme: 'bearer', - bearerFormat: 'JWT', - } - }, - responses: { - UnauthorizedError: { - description: "Access token is missing or invalid" - } - } - }, - security: [{ - bearerAuth: [] - }] - }, - apis: ["./src/routes/*.js"], -}; - -const specs = swaggerJsDoc(options); -app.use('/api-docs', function (req, res, next) { - swaggerUI.host = getBaseUrl(process.env.NEXT_PUBLIC_BACK_API) || req.get('host'); - next() - }, swaggerUI.serve, swaggerUI.setup(specs)) - -app.use(cors({origin: true})); -require('./auth/auth'); - -app.use(bodyParser.json()); - -app.use('/api/auth', authRoutes); -app.use('/api/file', fileRoutes); -app.use('/api/pexels', pexelsRoutes); -app.enable('trust proxy'); - - -app.use('/api/users', passport.authenticate('jwt', {session: false}), usersRoutes); - -app.use('/api/roles', passport.authenticate('jwt', {session: false}), rolesRoutes); - -app.use('/api/permissions', passport.authenticate('jwt', {session: false}), permissionsRoutes); - -app.use('/api/customers', passport.authenticate('jwt', {session: false}), customersRoutes); - -app.use('/api/product_categories', passport.authenticate('jwt', {session: false}), product_categoriesRoutes); - -app.use('/api/products', passport.authenticate('jwt', {session: false}), productsRoutes); - -app.use('/api/orders', passport.authenticate('jwt', {session: false}), ordersRoutes); - -app.use('/api/order_items', passport.authenticate('jwt', {session: false}), order_itemsRoutes); - -app.use('/api/payments', passport.authenticate('jwt', {session: false}), paymentsRoutes); - -app.use('/api/shipments', passport.authenticate('jwt', {session: false}), shipmentsRoutes); - -app.use( - '/api/openai', - passport.authenticate('jwt', { session: false }), - openaiRoutes, -); -app.use( - '/api/ai', - passport.authenticate('jwt', { session: false }), - openaiRoutes, -); - -app.use( - '/api/search', - passport.authenticate('jwt', { session: false }), - searchRoutes); -app.use( - '/api/sql', - passport.authenticate('jwt', { session: false }), - sqlRoutes); - - -const publicDir = path.join( - __dirname, - '../public', -); - -if (fs.existsSync(publicDir)) { - app.use('/', express.static(publicDir)); - - app.get('*', function(request, response) { - response.sendFile( - path.resolve(publicDir, 'index.html'), - ); - }); -} - -const PORT = process.env.NODE_ENV === 'dev_stage' ? 3000 : 8080; - - app.listen(PORT, () => { - console.log(`Listening on port ${PORT}`); - }); - -module.exports = app; diff --git a/backend/src/middlewares/check-permissions.js b/backend/src/middlewares/check-permissions.js deleted file mode 100644 index 77740c7..0000000 --- a/backend/src/middlewares/check-permissions.js +++ /dev/null @@ -1,149 +0,0 @@ - -const ValidationError = require('../services/notifications/errors/validation'); -const RolesDBApi = require('../db/api/roles'); - -// Cache for the 'Public' role object -let publicRoleCache = null; - -// Function to asynchronously fetch and cache the 'Public' role -async function fetchAndCachePublicRole() { - try { - // Use RolesDBApi to find the role by name 'Public' - publicRoleCache = await RolesDBApi.findBy({ name: 'Public' }); - - if (!publicRoleCache) { - console.error("WARNING: Role 'Public' not found in database during middleware startup. Check your migrations."); - // The system might not function correctly without this role. May need to throw an error or use a fallback stub. - } else { - console.log("'Public' role successfully loaded and cached."); - } - } catch (error) { - console.error("Error fetching 'Public' role during middleware startup:", error); - // Handle the error during startup fetch - throw error; // Important to know if the app can proceed without the Public role - } -} - -// Trigger the role fetching when the check-permissions.js module is imported/loaded -// This should happen during application startup when routes are being configured. -fetchAndCachePublicRole().catch(error => { - // Handle the case where the fetchAndCachePublicRole promise is rejected - console.error("Critical error during permissions middleware initialization:", error); - // Decide here if the process should exit if the Public role is essential. - // process.exit(1); -}); - -/** - * Middleware creator to check if the current user (or Public role) has a specific permission. - * @param {string} permission - The name of the required permission. - * @return {import("express").RequestHandler} Express middleware function. - */ -function checkPermissions(permission) { - return async (req, res, next) => { - const { currentUser } = req; - - // 1. Check self-access bypass (only if the user is authenticated) - if (currentUser && (currentUser.id === req.params.id || currentUser.id === req.body.id)) { - return next(); // User has access to their own resource - } - - // 2. Check Custom Permissions (only if the user is authenticated) - if (currentUser) { - // Ensure custom_permissions is an array before using find - const customPermissions = Array.isArray(currentUser.custom_permissions) - ? currentUser.custom_permissions - : []; - const userPermission = customPermissions.find( - (cp) => cp.name === permission, - ); - if (userPermission) { - return next(); // User has a custom permission - } - } - - // 3. Determine the "effective" role for permission check - let effectiveRole = null; - try { - if (currentUser && currentUser.app_role) { - // User is authenticated and has an assigned role - effectiveRole = currentUser.app_role; - } else { - // User is NOT authenticated OR is authenticated but has no role - // Use the cached 'Public' role - if (!publicRoleCache) { - // If the cache is unexpectedly empty (e.g., startup error caught), - // we can try fetching the role again synchronously (less ideal) or just deny access. - console.error("Public role cache is empty. Attempting synchronous fetch..."); - // Less efficient fallback option: - effectiveRole = await RolesDBApi.findBy({ name: 'Public' }); // Could be slow - if (!effectiveRole) { - // If even the synchronous attempt failed - return next(new Error("Internal Server Error: Public role missing and cannot be fetched.")); - } - } else { - effectiveRole = publicRoleCache; // Use the cached object - } - } - - // Check if we got a valid role object - if (!effectiveRole) { - return next(new Error("Internal Server Error: Could not determine effective role.")); - } - - // 4. Check Permissions on the "effective" role - // Assume the effectiveRole object (from app_role or RolesDBApi) has a getPermissions() method - // or a 'permissions' property (if permissions are eagerly loaded). - let rolePermissions = []; - if (typeof effectiveRole.getPermissions === 'function') { - rolePermissions = await effectiveRole.getPermissions(); // Get permissions asynchronously if the method exists - } else if (Array.isArray(effectiveRole.permissions)) { - rolePermissions = effectiveRole.permissions; // Or take from property if permissions are pre-loaded - } else { - console.error("Role object lacks getPermissions() method or permissions property:", effectiveRole); - return next(new Error("Internal Server Error: Invalid role object format.")); - } - - - if (rolePermissions.find((p) => p.name === permission)) { - next(); // The "effective" role has the required permission - } else { - // The "effective" role does not have the required permission - const roleName = effectiveRole.name || 'unknown role'; - next(new ValidationError('auth.forbidden', `Role '${roleName}' denied access to '${permission}'.`)); - } - - } catch (e) { - // Handle errors during role or permission fetching - console.error("Error during permission check:", e); - next(e); // Pass the error to the next middleware - } - }; -} - -const METHOD_MAP = { - POST: 'CREATE', - GET: 'READ', - PUT: 'UPDATE', - PATCH: 'UPDATE', - DELETE: 'DELETE', -}; - -/** - * Middleware creator to check standard CRUD permissions based on HTTP method and entity name. - * @param {string} name - The name of the entity. - * @return {import("express").RequestHandler} Express middleware function. - */ -function checkCrudPermissions(name) { - return (req, res, next) => { - // Dynamically determine the permission name (e.g., 'READ_USERS') - const permissionName = `${METHOD_MAP[req.method]}_${name.toUpperCase()}`; - // Call the checkPermissions middleware with the determined permission - checkPermissions(permissionName)(req, res, next); - }; -} - -module.exports = { - checkPermissions, - checkCrudPermissions, -}; - diff --git a/backend/src/middlewares/upload.js b/backend/src/middlewares/upload.js deleted file mode 100644 index ea3e835..0000000 --- a/backend/src/middlewares/upload.js +++ /dev/null @@ -1,11 +0,0 @@ -const util = require('util'); -const Multer = require('multer'); -const maxSize = 10 * 1024 * 1024; - -let processFile = Multer({ - storage: Multer.memoryStorage(), - limits: { fileSize: maxSize }, -}).single("file"); - -let processFileMiddleware = util.promisify(processFile); -module.exports = processFileMiddleware; diff --git a/backend/src/routes/auth.js b/backend/src/routes/auth.js deleted file mode 100644 index d6f29e8..0000000 --- a/backend/src/routes/auth.js +++ /dev/null @@ -1,207 +0,0 @@ -const express = require('express'); -const passport = require('passport'); - -const config = require('../config'); -const AuthService = require('../services/auth'); -const ForbiddenError = require('../services/notifications/errors/forbidden'); -const EmailSender = require('../services/email'); -const wrapAsync = require('../helpers').wrapAsync; - -const router = express.Router(); - -/** - * @swagger - * components: - * schemas: - * Auth: - * type: object - * required: - * - email - * - password - * properties: - * email: - * type: string - * default: admin@flatlogic.com - * description: User email - * password: - * type: string - * default: password - * description: User password - */ - -/** - * @swagger - * tags: - * name: Auth - * description: Authorization operations - */ - -/** - * @swagger - * /api/auth/signin/local: - * post: - * tags: [Auth] - * summary: Logs user into the system - * description: Logs user into the system - * requestBody: - * description: Set valid user email and password - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Auth" - * responses: - * 200: - * description: Successful login - * 400: - * description: Invalid username/password supplied - * x-codegen-request-body-name: body - */ - -router.post('/signin/local', wrapAsync(async (req, res) => { - const payload = await AuthService.signin(req.body.email, req.body.password, req,); - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/auth/me: - * get: - * security: - * - bearerAuth: [] - * tags: [Auth] - * summary: Get current authorized user info - * description: Get current authorized user info - * responses: - * 200: - * description: Successful retrieval of current authorized user data - * 400: - * description: Invalid username/password supplied - * x-codegen-request-body-name: body - */ - -router.get('/me', passport.authenticate('jwt', {session: false}), (req, res) => { - if (!req.currentUser || !req.currentUser.id) { - throw new ForbiddenError(); - } - - const payload = req.currentUser; - delete payload.password; - res.status(200).send(payload); -}); - -router.put('/password-reset', wrapAsync(async (req, res) => { - const payload = await AuthService.passwordReset(req.body.token, req.body.password, req,); - res.status(200).send(payload); -})); - -router.put('/password-update', passport.authenticate('jwt', {session: false}), wrapAsync(async (req, res) => { - const payload = await AuthService.passwordUpdate(req.body.currentPassword, req.body.newPassword, req); - res.status(200).send(payload); -})); - -router.post('/send-email-address-verification-email', passport.authenticate('jwt', {session: false}), wrapAsync(async (req, res) => { - if (!req.currentUser) { - throw new ForbiddenError(); - } - - await AuthService.sendEmailAddressVerificationEmail(req.currentUser.email); - const payload = true; - res.status(200).send(payload); -})); - -router.post('/send-password-reset-email', wrapAsync(async (req, res) => { - const link = new URL(req.headers.referer); - await AuthService.sendPasswordResetEmail(req.body.email, 'register', link.host,); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/auth/signup: - * post: - * tags: [Auth] - * summary: Register new user into the system - * description: Register new user into the system - * requestBody: - * description: Set valid user email and password - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Auth" - * responses: - * 200: - * description: New user successfully signed up - * 400: - * description: Invalid username/password supplied - * 500: - * description: Some server error - * x-codegen-request-body-name: body - */ - -router.post('/signup', wrapAsync(async (req, res) => { - const link = new URL(req.headers.referer); - const payload = await AuthService.signup( - req.body.email, - req.body.password, - - req, - link.host, - ) - res.status(200).send(payload); -})); - -router.put('/profile', passport.authenticate('jwt', {session: false}), wrapAsync(async (req, res) => { - if (!req.currentUser || !req.currentUser.id) { - throw new ForbiddenError(); - } - - await AuthService.updateProfile(req.body.profile, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -router.put('/verify-email', wrapAsync(async (req, res) => { - const payload = await AuthService.verifyEmail(req.body.token, req, req.headers.referer) - res.status(200).send(payload); -})); - -router.get('/email-configured', (req, res) => { - const payload = EmailSender.isConfigured; - res.status(200).send(payload); -}); - -router.get('/signin/google', (req, res, next) => { - passport.authenticate("google", {scope: ["profile", "email"], state: req.query.app})(req, res, next); -}); - -router.get('/signin/google/callback', passport.authenticate("google", {failureRedirect: "/login", session: false}), - - function (req, res) { - socialRedirect(res, req.query.state, req.user.token, config); - } -); - -router.get('/signin/microsoft', (req, res, next) => { - passport.authenticate("microsoft", { - scope: ["https://graph.microsoft.com/user.read openid"], - state: req.query.app - })(req, res, next); -}); - -router.get('/signin/microsoft/callback', passport.authenticate("microsoft", { - failureRedirect: "/login", - session: false - }), - function (req, res) { - socialRedirect(res, req.query.state, req.user.token, config); - } -); - -router.use('/', require('../helpers').commonErrorHandler); - -function socialRedirect(res, state, token, config) { - res.redirect(config.uiUrl + "/login?token=" + token); -} - -module.exports = router; diff --git a/backend/src/routes/contactForm.js b/backend/src/routes/contactForm.js deleted file mode 100644 index e69de29..0000000 diff --git a/backend/src/routes/customers.js b/backend/src/routes/customers.js deleted file mode 100644 index 22f4ae3..0000000 --- a/backend/src/routes/customers.js +++ /dev/null @@ -1,448 +0,0 @@ - -const express = require('express'); - -const CustomersService = require('../services/customers'); -const CustomersDBApi = require('../db/api/customers'); -const wrapAsync = require('../helpers').wrapAsync; - - -const router = express.Router(); - -const { parse } = require('json2csv'); - - -const { - checkCrudPermissions, -} = require('../middlewares/check-permissions'); - -router.use(checkCrudPermissions('customers')); - - -/** - * @swagger - * components: - * schemas: - * Customers: - * type: object - * properties: - - * customer_code: - * type: string - * default: customer_code - * full_name: - * type: string - * default: full_name - * email: - * type: string - * default: email - * phone: - * type: string - * default: phone - * billing_address: - * type: string - * default: billing_address - * shipping_address: - * type: string - * default: shipping_address - * notes: - * type: string - * default: notes - - - - * - */ - -/** - * @swagger - * tags: - * name: Customers - * description: The Customers managing API - */ - -/** -* @swagger -* /api/customers: -* post: -* security: -* - bearerAuth: [] -* tags: [Customers] -* summary: Add new item -* description: Add new item -* requestBody: -* required: true -* content: -* application/json: -* schema: -* properties: -* data: -* description: Data of the updated item -* type: object -* $ref: "#/components/schemas/Customers" -* responses: -* 200: -* description: The item was successfully added -* content: -* application/json: -* schema: -* $ref: "#/components/schemas/Customers" -* 401: -* $ref: "#/components/responses/UnauthorizedError" -* 405: -* description: Invalid input data -* 500: -* description: Some server error -*/ -router.post('/', wrapAsync(async (req, res) => { - const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`; - const link = new URL(referer); - await CustomersService.create(req.body.data, req.currentUser, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/budgets/bulk-import: - * post: - * security: - * - bearerAuth: [] - * tags: [Customers] - * summary: Bulk import items - * description: Bulk import items - * requestBody: - * required: true - * content: - * application/json: - * schema: - * properties: - * data: - * description: Data of the updated items - * type: array - * items: - * $ref: "#/components/schemas/Customers" - * responses: - * 200: - * description: The items were successfully imported - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Customers" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 405: - * description: Invalid input data - * 500: - * description: Some server error - * - */ -router.post('/bulk-import', wrapAsync(async (req, res) => { - const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`; - const link = new URL(referer); - await CustomersService.bulkImport(req, res, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/customers/{id}: - * put: - * security: - * - bearerAuth: [] - * tags: [Customers] - * summary: Update the data of the selected item - * description: Update the data of the selected item - * parameters: - * - in: path - * name: id - * description: Item ID to update - * required: true - * schema: - * type: string - * requestBody: - * description: Set new item data - * required: true - * content: - * application/json: - * schema: - * properties: - * id: - * description: ID of the updated item - * type: string - * data: - * description: Data of the updated item - * type: object - * $ref: "#/components/schemas/Customers" - * required: - * - id - * responses: - * 200: - * description: The item data was successfully updated - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Customers" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.put('/:id', wrapAsync(async (req, res) => { - await CustomersService.update(req.body.data, req.body.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/customers/{id}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Customers] - * summary: Delete the selected item - * description: Delete the selected item - * parameters: - * - in: path - * name: id - * description: Item ID to delete - * required: true - * schema: - * type: string - * responses: - * 200: - * description: The item was successfully deleted - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Customers" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.delete('/:id', wrapAsync(async (req, res) => { - await CustomersService.remove(req.params.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/customers/deleteByIds: - * post: - * security: - * - bearerAuth: [] - * tags: [Customers] - * summary: Delete the selected item list - * description: Delete the selected item list - * requestBody: - * required: true - * content: - * application/json: - * schema: - * properties: - * ids: - * description: IDs of the updated items - * type: array - * responses: - * 200: - * description: The items was successfully deleted - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Customers" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Items not found - * 500: - * description: Some server error - */ -router.post('/deleteByIds', wrapAsync(async (req, res) => { - await CustomersService.deleteByIds(req.body.data, req.currentUser); - const payload = true; - res.status(200).send(payload); - })); - -/** - * @swagger - * /api/customers: - * get: - * security: - * - bearerAuth: [] - * tags: [Customers] - * summary: Get all customers - * description: Get all customers - * responses: - * 200: - * description: Customers list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Customers" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error -*/ -router.get('/', wrapAsync(async (req, res) => { - const filetype = req.query.filetype - - const currentUser = req.currentUser; - const payload = await CustomersDBApi.findAll( - req.query, { currentUser } - ); - if (filetype && filetype === 'csv') { - const fields = ['id','customer_code','full_name','email','phone','billing_address','shipping_address','notes', - - - 'registered_at', - ]; - const opts = { fields }; - try { - const csv = parse(payload.rows, opts); - res.status(200).attachment(csv); - res.send(csv) - - } catch (err) { - console.error(err); - } - } else { - res.status(200).send(payload); - } - -})); - -/** - * @swagger - * /api/customers/count: - * get: - * security: - * - bearerAuth: [] - * tags: [Customers] - * summary: Count all customers - * description: Count all customers - * responses: - * 200: - * description: Customers count successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Customers" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/count', wrapAsync(async (req, res) => { - - const currentUser = req.currentUser; - const payload = await CustomersDBApi.findAll( - req.query, - null, - { countOnly: true, currentUser } - ); - - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/customers/autocomplete: - * get: - * security: - * - bearerAuth: [] - * tags: [Customers] - * summary: Find all customers that match search criteria - * description: Find all customers that match search criteria - * responses: - * 200: - * description: Customers list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Customers" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/autocomplete', async (req, res) => { - - const payload = await CustomersDBApi.findAllAutocomplete( - req.query.query, - req.query.limit, - req.query.offset, - - ); - - res.status(200).send(payload); -}); - -/** - * @swagger - * /api/customers/{id}: - * get: - * security: - * - bearerAuth: [] - * tags: [Customers] - * summary: Get selected item - * description: Get selected item - * parameters: - * - in: path - * name: id - * description: ID of item to get - * required: true - * schema: - * type: string - * responses: - * 200: - * description: Selected item successfully received - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Customers" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.get('/:id', wrapAsync(async (req, res) => { - const payload = await CustomersDBApi.findBy( - { id: req.params.id }, - ); - - - - res.status(200).send(payload); -})); - -router.use('/', require('../helpers').commonErrorHandler); - -module.exports = router; diff --git a/backend/src/routes/file.js b/backend/src/routes/file.js deleted file mode 100644 index ddd2bc0..0000000 --- a/backend/src/routes/file.js +++ /dev/null @@ -1,32 +0,0 @@ -const express = require('express'); -const config = require('../config'); -const path = require('path'); -const passport = require('passport'); -const services = require('../services/file'); -const router = express.Router(); - -router.get('/download', (req, res) => { - if (process.env.NODE_ENV == "production" || process.env.NEXT_PUBLIC_BACK_API) { - services.downloadGCloud(req, res); - } - else { - services.downloadLocal(req, res); - } -}); - -router.post('/upload/:table/:field', passport.authenticate('jwt', {session: false}), (req, res) => { - const fileName = `${req.params.table}/${req.params.field}`; - - if (process.env.NODE_ENV == "production" || process.env.NEXT_PUBLIC_BACK_API) { - services.uploadGCloud(fileName, req, res); - } - else { - services.uploadLocal(fileName, { - entity: null, - maxFileSize: 10 * 1024 * 1024, - folderIncludesAuthenticationUid: false, - })(req, res); - } -}); - -module.exports = router; diff --git a/backend/src/routes/openai.js b/backend/src/routes/openai.js deleted file mode 100644 index 2d47d9f..0000000 --- a/backend/src/routes/openai.js +++ /dev/null @@ -1,328 +0,0 @@ -const express = require('express'); -const db = require('../db/models'); -const wrapAsync = require('../helpers').wrapAsync; -const router = express.Router(); -const sjs = require('sequelize-json-schema'); -const { getWidget, askGpt } = require('../services/openai'); -const { LocalAIApi } = require('../ai/LocalAIApi'); - -const loadRolesModules = () => { - try { - return { - RolesService: require('../services/roles'), - RolesDBApi: require('../db/api/roles'), - }; - } catch (error) { - console.error('Roles modules are missing. Advanced roles are required for this endpoint.', error); - const err = new Error('Roles modules are missing. Advanced roles are required for this endpoint.'); - err.originalError = error; - throw err; - } -}; - -/** - * @swagger - * /api/roles/roles-info/{infoId}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Roles] - * summary: Remove role information by ID - * description: Remove specific role information by ID - * parameters: - * - in: path - * name: infoId - * description: ID of role information to remove - * required: true - * schema: - * type: string - * - in: query - * name: userId - * description: ID of the user - * required: true - * schema: - * type: string - * - in: query - * name: key - * description: Key of the role information to remove - * required: true - * schema: - * type: string - * responses: - * 200: - * description: Role information successfully removed - * content: - * application/json: - * schema: - * type: object - * properties: - * user: - * type: string - * description: The user information - * 400: - * description: Invalid ID or key supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Role not found - * 500: - * description: Some server error - */ - -router.delete( - '/roles-info/:infoId', - wrapAsync(async (req, res) => { - const { RolesService } = loadRolesModules(); - const role = await RolesService.removeRoleInfoById( - req.query.infoId, - req.query.roleId, - req.query.key, - req.currentUser, - ); - - res.status(200).send(role); - }), -); - -/** - * @swagger - * /api/roles/role-info/{roleId}: - * get: - * security: - * - bearerAuth: [] - * tags: [Roles] - * summary: Get role information by key - * description: Get specific role information by key - * parameters: - * - in: path - * name: roleId - * description: ID of role to get information for - * required: true - * schema: - * type: string - * - in: query - * name: key - * description: Key of the role information to retrieve - * required: true - * schema: - * type: string - * responses: - * 200: - * description: Role information successfully received - * content: - * application/json: - * schema: - * type: object - * properties: - * info: - * type: string - * description: The role information - * 400: - * description: Invalid ID or key supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Role not found - * 500: - * description: Some server error - */ - -router.get( - '/info-by-key', - wrapAsync(async (req, res) => { - const { RolesService, RolesDBApi } = loadRolesModules(); - const roleId = req.query.roleId; - const key = req.query.key; - const currentUser = req.currentUser; - let info = await RolesService.getRoleInfoByKey( - key, - roleId, - currentUser, - ); - const role = await RolesDBApi.findBy({ id: roleId }); - if (!role?.role_customization) { - await Promise.all(["pie", "bar"].map(async (e) => { - const schema = await sjs.getSequelizeSchema(db.sequelize, {}); - const payload = { - description: `Create some cool ${e} chart`, - modelDefinition: schema.definitions, - }; - const widgetId = await getWidget(payload, currentUser?.id, roleId); - if (widgetId) { - await RolesService.addRoleInfo( - roleId, - currentUser?.id, - 'widgets', - widgetId, - req.currentUser, - ); - } - })) - info = await RolesService.getRoleInfoByKey( - key, - roleId, - currentUser, - ); - } - res.status(200).send(info); - }), -); - -router.post( - '/create_widget', - wrapAsync(async (req, res) => { - const { RolesService } = loadRolesModules(); - const { description, userId, roleId } = req.body; - - const currentUser = req.currentUser; - const schema = await sjs.getSequelizeSchema(db.sequelize, {}); - const payload = { - description, - modelDefinition: schema.definitions, - }; - - const widgetId = await getWidget(payload, userId, roleId); - - if (widgetId) { - await RolesService.addRoleInfo( - roleId, - userId, - 'widgets', - widgetId, - currentUser, - ); - - return res.status(200).send(widgetId); - } else { - return res.status(400).send(widgetId); - } - }), -); - -/** - * @swagger - * /api/openai/response: - * post: - * security: - * - bearerAuth: [] - * tags: [OpenAI] - * summary: Proxy a Responses API request - * description: Sends the payload to the Flatlogic AI proxy and returns the response. - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * input: - * type: array - * description: List of messages with roles and content. - * items: - * type: object - * properties: - * role: - * type: string - * content: - * type: string - * options: - * type: object - * description: Optional polling controls. - * properties: - * poll_interval: - * type: number - * poll_timeout: - * type: number - * responses: - * 200: - * description: AI response received - * 400: - * description: Invalid request - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 502: - * description: Proxy error - */ -router.post( - '/response', - wrapAsync(async (req, res) => { - const body = req.body || {}; - const options = body.options || {}; - const payload = { ...body }; - delete payload.options; - - const response = await LocalAIApi.createResponse(payload, options); - - if (response.success) { - return res.status(200).send(response); - } - - console.error('AI proxy error:', response); - const status = response.error === 'input_missing' ? 400 : 502; - return res.status(status).send(response); - }), -); - -/** - * @swagger - * /api/openai/ask: - * post: - * security: - * - bearerAuth: [] - * tags: [OpenAI] - * summary: Ask a question to ChatGPT - * description: Send a question through the Flatlogic AI proxy and get a response - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * prompt: - * type: string - * description: The question to ask ChatGPT - * responses: - * 200: - * description: Question successfully answered - * content: - * application/json: - * schema: - * type: object - * properties: - * success: - * type: boolean - * description: Whether the request was successful - * data: - * type: string - * description: The answer from ChatGPT - * 400: - * description: Invalid request - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 500: - * description: Some server error - */ -router.post( - '/ask-gpt', - wrapAsync(async (req, res) => { - const { prompt } = req.body; - if (!prompt) { - return res.status(400).send({ - success: false, - error: 'Prompt is required', - }); - } - - const response = await askGpt(prompt); - - if (response.success) { - return res.status(200).send(response); - } else { - return res.status(500).send(response); - } - }), -); - - -module.exports = router; diff --git a/backend/src/routes/order_items.js b/backend/src/routes/order_items.js deleted file mode 100644 index c0db2f7..0000000 --- a/backend/src/routes/order_items.js +++ /dev/null @@ -1,448 +0,0 @@ - -const express = require('express'); - -const Order_itemsService = require('../services/order_items'); -const Order_itemsDBApi = require('../db/api/order_items'); -const wrapAsync = require('../helpers').wrapAsync; - - -const router = express.Router(); - -const { parse } = require('json2csv'); - - -const { - checkCrudPermissions, -} = require('../middlewares/check-permissions'); - -router.use(checkCrudPermissions('order_items')); - - -/** - * @swagger - * components: - * schemas: - * Order_items: - * type: object - * properties: - - * product_name_snapshot: - * type: string - * default: product_name_snapshot - * sku_snapshot: - * type: string - * default: sku_snapshot - - * quantity: - * type: integer - * format: int64 - - * unit_price: - * type: integer - * format: int64 - * line_discount_amount: - * type: integer - * format: int64 - * line_tax_amount: - * type: integer - * format: int64 - * line_total_amount: - * type: integer - * format: int64 - - * - */ - -/** - * @swagger - * tags: - * name: Order_items - * description: The Order_items managing API - */ - -/** -* @swagger -* /api/order_items: -* post: -* security: -* - bearerAuth: [] -* tags: [Order_items] -* summary: Add new item -* description: Add new item -* requestBody: -* required: true -* content: -* application/json: -* schema: -* properties: -* data: -* description: Data of the updated item -* type: object -* $ref: "#/components/schemas/Order_items" -* responses: -* 200: -* description: The item was successfully added -* content: -* application/json: -* schema: -* $ref: "#/components/schemas/Order_items" -* 401: -* $ref: "#/components/responses/UnauthorizedError" -* 405: -* description: Invalid input data -* 500: -* description: Some server error -*/ -router.post('/', wrapAsync(async (req, res) => { - const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`; - const link = new URL(referer); - await Order_itemsService.create(req.body.data, req.currentUser, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/budgets/bulk-import: - * post: - * security: - * - bearerAuth: [] - * tags: [Order_items] - * summary: Bulk import items - * description: Bulk import items - * requestBody: - * required: true - * content: - * application/json: - * schema: - * properties: - * data: - * description: Data of the updated items - * type: array - * items: - * $ref: "#/components/schemas/Order_items" - * responses: - * 200: - * description: The items were successfully imported - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Order_items" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 405: - * description: Invalid input data - * 500: - * description: Some server error - * - */ -router.post('/bulk-import', wrapAsync(async (req, res) => { - const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`; - const link = new URL(referer); - await Order_itemsService.bulkImport(req, res, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/order_items/{id}: - * put: - * security: - * - bearerAuth: [] - * tags: [Order_items] - * summary: Update the data of the selected item - * description: Update the data of the selected item - * parameters: - * - in: path - * name: id - * description: Item ID to update - * required: true - * schema: - * type: string - * requestBody: - * description: Set new item data - * required: true - * content: - * application/json: - * schema: - * properties: - * id: - * description: ID of the updated item - * type: string - * data: - * description: Data of the updated item - * type: object - * $ref: "#/components/schemas/Order_items" - * required: - * - id - * responses: - * 200: - * description: The item data was successfully updated - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Order_items" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.put('/:id', wrapAsync(async (req, res) => { - await Order_itemsService.update(req.body.data, req.body.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/order_items/{id}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Order_items] - * summary: Delete the selected item - * description: Delete the selected item - * parameters: - * - in: path - * name: id - * description: Item ID to delete - * required: true - * schema: - * type: string - * responses: - * 200: - * description: The item was successfully deleted - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Order_items" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.delete('/:id', wrapAsync(async (req, res) => { - await Order_itemsService.remove(req.params.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/order_items/deleteByIds: - * post: - * security: - * - bearerAuth: [] - * tags: [Order_items] - * summary: Delete the selected item list - * description: Delete the selected item list - * requestBody: - * required: true - * content: - * application/json: - * schema: - * properties: - * ids: - * description: IDs of the updated items - * type: array - * responses: - * 200: - * description: The items was successfully deleted - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Order_items" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Items not found - * 500: - * description: Some server error - */ -router.post('/deleteByIds', wrapAsync(async (req, res) => { - await Order_itemsService.deleteByIds(req.body.data, req.currentUser); - const payload = true; - res.status(200).send(payload); - })); - -/** - * @swagger - * /api/order_items: - * get: - * security: - * - bearerAuth: [] - * tags: [Order_items] - * summary: Get all order_items - * description: Get all order_items - * responses: - * 200: - * description: Order_items list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Order_items" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error -*/ -router.get('/', wrapAsync(async (req, res) => { - const filetype = req.query.filetype - - const currentUser = req.currentUser; - const payload = await Order_itemsDBApi.findAll( - req.query, { currentUser } - ); - if (filetype && filetype === 'csv') { - const fields = ['id','product_name_snapshot','sku_snapshot', - 'quantity', - 'unit_price','line_discount_amount','line_tax_amount','line_total_amount', - - ]; - const opts = { fields }; - try { - const csv = parse(payload.rows, opts); - res.status(200).attachment(csv); - res.send(csv) - - } catch (err) { - console.error(err); - } - } else { - res.status(200).send(payload); - } - -})); - -/** - * @swagger - * /api/order_items/count: - * get: - * security: - * - bearerAuth: [] - * tags: [Order_items] - * summary: Count all order_items - * description: Count all order_items - * responses: - * 200: - * description: Order_items count successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Order_items" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/count', wrapAsync(async (req, res) => { - - const currentUser = req.currentUser; - const payload = await Order_itemsDBApi.findAll( - req.query, - null, - { countOnly: true, currentUser } - ); - - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/order_items/autocomplete: - * get: - * security: - * - bearerAuth: [] - * tags: [Order_items] - * summary: Find all order_items that match search criteria - * description: Find all order_items that match search criteria - * responses: - * 200: - * description: Order_items list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Order_items" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/autocomplete', async (req, res) => { - - const payload = await Order_itemsDBApi.findAllAutocomplete( - req.query.query, - req.query.limit, - req.query.offset, - - ); - - res.status(200).send(payload); -}); - -/** - * @swagger - * /api/order_items/{id}: - * get: - * security: - * - bearerAuth: [] - * tags: [Order_items] - * summary: Get selected item - * description: Get selected item - * parameters: - * - in: path - * name: id - * description: ID of item to get - * required: true - * schema: - * type: string - * responses: - * 200: - * description: Selected item successfully received - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Order_items" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.get('/:id', wrapAsync(async (req, res) => { - const payload = await Order_itemsDBApi.findBy( - { id: req.params.id }, - ); - - - - res.status(200).send(payload); -})); - -router.use('/', require('../helpers').commonErrorHandler); - -module.exports = router; diff --git a/backend/src/routes/orders.js b/backend/src/routes/orders.js deleted file mode 100644 index 542751f..0000000 --- a/backend/src/routes/orders.js +++ /dev/null @@ -1,474 +0,0 @@ - -const express = require('express'); - -const OrdersService = require('../services/orders'); -const OrdersDBApi = require('../db/api/orders'); -const wrapAsync = require('../helpers').wrapAsync; - - -const router = express.Router(); - -const { parse } = require('json2csv'); - - -const { - checkCrudPermissions, -} = require('../middlewares/check-permissions'); - -router.use(checkCrudPermissions('orders')); - - -/** - * @swagger - * components: - * schemas: - * Orders: - * type: object - * properties: - - * order_number: - * type: string - * default: order_number - * currency: - * type: string - * default: currency - * shipping_name: - * type: string - * default: shipping_name - * shipping_address: - * type: string - * default: shipping_address - * billing_name: - * type: string - * default: billing_name - * billing_address: - * type: string - * default: billing_address - * notes_internal: - * type: string - * default: notes_internal - * customer_note: - * type: string - * default: customer_note - * tracking_number: - * type: string - * default: tracking_number - * carrier: - * type: string - * default: carrier - - - * subtotal_amount: - * type: integer - * format: int64 - * discount_amount: - * type: integer - * format: int64 - * tax_amount: - * type: integer - * format: int64 - * shipping_amount: - * type: integer - * format: int64 - * total_amount: - * type: integer - * format: int64 - - * - * - * - */ - -/** - * @swagger - * tags: - * name: Orders - * description: The Orders managing API - */ - -/** -* @swagger -* /api/orders: -* post: -* security: -* - bearerAuth: [] -* tags: [Orders] -* summary: Add new item -* description: Add new item -* requestBody: -* required: true -* content: -* application/json: -* schema: -* properties: -* data: -* description: Data of the updated item -* type: object -* $ref: "#/components/schemas/Orders" -* responses: -* 200: -* description: The item was successfully added -* content: -* application/json: -* schema: -* $ref: "#/components/schemas/Orders" -* 401: -* $ref: "#/components/responses/UnauthorizedError" -* 405: -* description: Invalid input data -* 500: -* description: Some server error -*/ -router.post('/', wrapAsync(async (req, res) => { - const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`; - const link = new URL(referer); - await OrdersService.create(req.body.data, req.currentUser, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/budgets/bulk-import: - * post: - * security: - * - bearerAuth: [] - * tags: [Orders] - * summary: Bulk import items - * description: Bulk import items - * requestBody: - * required: true - * content: - * application/json: - * schema: - * properties: - * data: - * description: Data of the updated items - * type: array - * items: - * $ref: "#/components/schemas/Orders" - * responses: - * 200: - * description: The items were successfully imported - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Orders" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 405: - * description: Invalid input data - * 500: - * description: Some server error - * - */ -router.post('/bulk-import', wrapAsync(async (req, res) => { - const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`; - const link = new URL(referer); - await OrdersService.bulkImport(req, res, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/orders/{id}: - * put: - * security: - * - bearerAuth: [] - * tags: [Orders] - * summary: Update the data of the selected item - * description: Update the data of the selected item - * parameters: - * - in: path - * name: id - * description: Item ID to update - * required: true - * schema: - * type: string - * requestBody: - * description: Set new item data - * required: true - * content: - * application/json: - * schema: - * properties: - * id: - * description: ID of the updated item - * type: string - * data: - * description: Data of the updated item - * type: object - * $ref: "#/components/schemas/Orders" - * required: - * - id - * responses: - * 200: - * description: The item data was successfully updated - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Orders" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.put('/:id', wrapAsync(async (req, res) => { - await OrdersService.update(req.body.data, req.body.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/orders/{id}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Orders] - * summary: Delete the selected item - * description: Delete the selected item - * parameters: - * - in: path - * name: id - * description: Item ID to delete - * required: true - * schema: - * type: string - * responses: - * 200: - * description: The item was successfully deleted - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Orders" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.delete('/:id', wrapAsync(async (req, res) => { - await OrdersService.remove(req.params.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/orders/deleteByIds: - * post: - * security: - * - bearerAuth: [] - * tags: [Orders] - * summary: Delete the selected item list - * description: Delete the selected item list - * requestBody: - * required: true - * content: - * application/json: - * schema: - * properties: - * ids: - * description: IDs of the updated items - * type: array - * responses: - * 200: - * description: The items was successfully deleted - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Orders" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Items not found - * 500: - * description: Some server error - */ -router.post('/deleteByIds', wrapAsync(async (req, res) => { - await OrdersService.deleteByIds(req.body.data, req.currentUser); - const payload = true; - res.status(200).send(payload); - })); - -/** - * @swagger - * /api/orders: - * get: - * security: - * - bearerAuth: [] - * tags: [Orders] - * summary: Get all orders - * description: Get all orders - * responses: - * 200: - * description: Orders list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Orders" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error -*/ -router.get('/', wrapAsync(async (req, res) => { - const filetype = req.query.filetype - - const currentUser = req.currentUser; - const payload = await OrdersDBApi.findAll( - req.query, { currentUser } - ); - if (filetype && filetype === 'csv') { - const fields = ['id','order_number','currency','shipping_name','shipping_address','billing_name','billing_address','notes_internal','customer_note','tracking_number','carrier', - - 'subtotal_amount','discount_amount','tax_amount','shipping_amount','total_amount', - 'placed_at','packed_at','shipped_at','delivered_at', - ]; - const opts = { fields }; - try { - const csv = parse(payload.rows, opts); - res.status(200).attachment(csv); - res.send(csv) - - } catch (err) { - console.error(err); - } - } else { - res.status(200).send(payload); - } - -})); - -/** - * @swagger - * /api/orders/count: - * get: - * security: - * - bearerAuth: [] - * tags: [Orders] - * summary: Count all orders - * description: Count all orders - * responses: - * 200: - * description: Orders count successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Orders" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/count', wrapAsync(async (req, res) => { - - const currentUser = req.currentUser; - const payload = await OrdersDBApi.findAll( - req.query, - null, - { countOnly: true, currentUser } - ); - - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/orders/autocomplete: - * get: - * security: - * - bearerAuth: [] - * tags: [Orders] - * summary: Find all orders that match search criteria - * description: Find all orders that match search criteria - * responses: - * 200: - * description: Orders list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Orders" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/autocomplete', async (req, res) => { - - const payload = await OrdersDBApi.findAllAutocomplete( - req.query.query, - req.query.limit, - req.query.offset, - - ); - - res.status(200).send(payload); -}); - -/** - * @swagger - * /api/orders/{id}: - * get: - * security: - * - bearerAuth: [] - * tags: [Orders] - * summary: Get selected item - * description: Get selected item - * parameters: - * - in: path - * name: id - * description: ID of item to get - * required: true - * schema: - * type: string - * responses: - * 200: - * description: Selected item successfully received - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Orders" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.get('/:id', wrapAsync(async (req, res) => { - const payload = await OrdersDBApi.findBy( - { id: req.params.id }, - ); - - - - res.status(200).send(payload); -})); - -router.use('/', require('../helpers').commonErrorHandler); - -module.exports = router; diff --git a/backend/src/routes/organizationLogin.js b/backend/src/routes/organizationLogin.js deleted file mode 100644 index 139597f..0000000 --- a/backend/src/routes/organizationLogin.js +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/backend/src/routes/payments.js b/backend/src/routes/payments.js deleted file mode 100644 index ee2356f..0000000 --- a/backend/src/routes/payments.js +++ /dev/null @@ -1,444 +0,0 @@ - -const express = require('express'); - -const PaymentsService = require('../services/payments'); -const PaymentsDBApi = require('../db/api/payments'); -const wrapAsync = require('../helpers').wrapAsync; - - -const router = express.Router(); - -const { parse } = require('json2csv'); - - -const { - checkCrudPermissions, -} = require('../middlewares/check-permissions'); - -router.use(checkCrudPermissions('payments')); - - -/** - * @swagger - * components: - * schemas: - * Payments: - * type: object - * properties: - - * payment_reference: - * type: string - * default: payment_reference - * currency: - * type: string - * default: currency - * provider_transaction_id: - * type: string - * default: provider_transaction_id - * failure_reason: - * type: string - * default: failure_reason - - - * amount: - * type: integer - * format: int64 - - * - * - * - */ - -/** - * @swagger - * tags: - * name: Payments - * description: The Payments managing API - */ - -/** -* @swagger -* /api/payments: -* post: -* security: -* - bearerAuth: [] -* tags: [Payments] -* summary: Add new item -* description: Add new item -* requestBody: -* required: true -* content: -* application/json: -* schema: -* properties: -* data: -* description: Data of the updated item -* type: object -* $ref: "#/components/schemas/Payments" -* responses: -* 200: -* description: The item was successfully added -* content: -* application/json: -* schema: -* $ref: "#/components/schemas/Payments" -* 401: -* $ref: "#/components/responses/UnauthorizedError" -* 405: -* description: Invalid input data -* 500: -* description: Some server error -*/ -router.post('/', wrapAsync(async (req, res) => { - const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`; - const link = new URL(referer); - await PaymentsService.create(req.body.data, req.currentUser, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/budgets/bulk-import: - * post: - * security: - * - bearerAuth: [] - * tags: [Payments] - * summary: Bulk import items - * description: Bulk import items - * requestBody: - * required: true - * content: - * application/json: - * schema: - * properties: - * data: - * description: Data of the updated items - * type: array - * items: - * $ref: "#/components/schemas/Payments" - * responses: - * 200: - * description: The items were successfully imported - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Payments" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 405: - * description: Invalid input data - * 500: - * description: Some server error - * - */ -router.post('/bulk-import', wrapAsync(async (req, res) => { - const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`; - const link = new URL(referer); - await PaymentsService.bulkImport(req, res, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/payments/{id}: - * put: - * security: - * - bearerAuth: [] - * tags: [Payments] - * summary: Update the data of the selected item - * description: Update the data of the selected item - * parameters: - * - in: path - * name: id - * description: Item ID to update - * required: true - * schema: - * type: string - * requestBody: - * description: Set new item data - * required: true - * content: - * application/json: - * schema: - * properties: - * id: - * description: ID of the updated item - * type: string - * data: - * description: Data of the updated item - * type: object - * $ref: "#/components/schemas/Payments" - * required: - * - id - * responses: - * 200: - * description: The item data was successfully updated - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Payments" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.put('/:id', wrapAsync(async (req, res) => { - await PaymentsService.update(req.body.data, req.body.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/payments/{id}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Payments] - * summary: Delete the selected item - * description: Delete the selected item - * parameters: - * - in: path - * name: id - * description: Item ID to delete - * required: true - * schema: - * type: string - * responses: - * 200: - * description: The item was successfully deleted - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Payments" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.delete('/:id', wrapAsync(async (req, res) => { - await PaymentsService.remove(req.params.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/payments/deleteByIds: - * post: - * security: - * - bearerAuth: [] - * tags: [Payments] - * summary: Delete the selected item list - * description: Delete the selected item list - * requestBody: - * required: true - * content: - * application/json: - * schema: - * properties: - * ids: - * description: IDs of the updated items - * type: array - * responses: - * 200: - * description: The items was successfully deleted - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Payments" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Items not found - * 500: - * description: Some server error - */ -router.post('/deleteByIds', wrapAsync(async (req, res) => { - await PaymentsService.deleteByIds(req.body.data, req.currentUser); - const payload = true; - res.status(200).send(payload); - })); - -/** - * @swagger - * /api/payments: - * get: - * security: - * - bearerAuth: [] - * tags: [Payments] - * summary: Get all payments - * description: Get all payments - * responses: - * 200: - * description: Payments list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Payments" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error -*/ -router.get('/', wrapAsync(async (req, res) => { - const filetype = req.query.filetype - - const currentUser = req.currentUser; - const payload = await PaymentsDBApi.findAll( - req.query, { currentUser } - ); - if (filetype && filetype === 'csv') { - const fields = ['id','payment_reference','currency','provider_transaction_id','failure_reason', - - 'amount', - 'initiated_at','captured_at','refunded_at', - ]; - const opts = { fields }; - try { - const csv = parse(payload.rows, opts); - res.status(200).attachment(csv); - res.send(csv) - - } catch (err) { - console.error(err); - } - } else { - res.status(200).send(payload); - } - -})); - -/** - * @swagger - * /api/payments/count: - * get: - * security: - * - bearerAuth: [] - * tags: [Payments] - * summary: Count all payments - * description: Count all payments - * responses: - * 200: - * description: Payments count successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Payments" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/count', wrapAsync(async (req, res) => { - - const currentUser = req.currentUser; - const payload = await PaymentsDBApi.findAll( - req.query, - null, - { countOnly: true, currentUser } - ); - - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/payments/autocomplete: - * get: - * security: - * - bearerAuth: [] - * tags: [Payments] - * summary: Find all payments that match search criteria - * description: Find all payments that match search criteria - * responses: - * 200: - * description: Payments list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Payments" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/autocomplete', async (req, res) => { - - const payload = await PaymentsDBApi.findAllAutocomplete( - req.query.query, - req.query.limit, - req.query.offset, - - ); - - res.status(200).send(payload); -}); - -/** - * @swagger - * /api/payments/{id}: - * get: - * security: - * - bearerAuth: [] - * tags: [Payments] - * summary: Get selected item - * description: Get selected item - * parameters: - * - in: path - * name: id - * description: ID of item to get - * required: true - * schema: - * type: string - * responses: - * 200: - * description: Selected item successfully received - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Payments" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.get('/:id', wrapAsync(async (req, res) => { - const payload = await PaymentsDBApi.findBy( - { id: req.params.id }, - ); - - - - res.status(200).send(payload); -})); - -router.use('/', require('../helpers').commonErrorHandler); - -module.exports = router; diff --git a/backend/src/routes/permissions.js b/backend/src/routes/permissions.js deleted file mode 100644 index b569a78..0000000 --- a/backend/src/routes/permissions.js +++ /dev/null @@ -1,429 +0,0 @@ - -const express = require('express'); - -const PermissionsService = require('../services/permissions'); -const PermissionsDBApi = require('../db/api/permissions'); -const wrapAsync = require('../helpers').wrapAsync; - - -const router = express.Router(); - -const { parse } = require('json2csv'); - - -const { - checkCrudPermissions, -} = require('../middlewares/check-permissions'); - -router.use(checkCrudPermissions('permissions')); - - -/** - * @swagger - * components: - * schemas: - * Permissions: - * type: object - * properties: - - * name: - * type: string - * default: name - - - - */ - -/** - * @swagger - * tags: - * name: Permissions - * description: The Permissions managing API - */ - -/** -* @swagger -* /api/permissions: -* post: -* security: -* - bearerAuth: [] -* tags: [Permissions] -* summary: Add new item -* description: Add new item -* requestBody: -* required: true -* content: -* application/json: -* schema: -* properties: -* data: -* description: Data of the updated item -* type: object -* $ref: "#/components/schemas/Permissions" -* responses: -* 200: -* description: The item was successfully added -* content: -* application/json: -* schema: -* $ref: "#/components/schemas/Permissions" -* 401: -* $ref: "#/components/responses/UnauthorizedError" -* 405: -* description: Invalid input data -* 500: -* description: Some server error -*/ -router.post('/', wrapAsync(async (req, res) => { - const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`; - const link = new URL(referer); - await PermissionsService.create(req.body.data, req.currentUser, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/budgets/bulk-import: - * post: - * security: - * - bearerAuth: [] - * tags: [Permissions] - * summary: Bulk import items - * description: Bulk import items - * requestBody: - * required: true - * content: - * application/json: - * schema: - * properties: - * data: - * description: Data of the updated items - * type: array - * items: - * $ref: "#/components/schemas/Permissions" - * responses: - * 200: - * description: The items were successfully imported - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Permissions" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 405: - * description: Invalid input data - * 500: - * description: Some server error - * - */ -router.post('/bulk-import', wrapAsync(async (req, res) => { - const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`; - const link = new URL(referer); - await PermissionsService.bulkImport(req, res, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/permissions/{id}: - * put: - * security: - * - bearerAuth: [] - * tags: [Permissions] - * summary: Update the data of the selected item - * description: Update the data of the selected item - * parameters: - * - in: path - * name: id - * description: Item ID to update - * required: true - * schema: - * type: string - * requestBody: - * description: Set new item data - * required: true - * content: - * application/json: - * schema: - * properties: - * id: - * description: ID of the updated item - * type: string - * data: - * description: Data of the updated item - * type: object - * $ref: "#/components/schemas/Permissions" - * required: - * - id - * responses: - * 200: - * description: The item data was successfully updated - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Permissions" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.put('/:id', wrapAsync(async (req, res) => { - await PermissionsService.update(req.body.data, req.body.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/permissions/{id}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Permissions] - * summary: Delete the selected item - * description: Delete the selected item - * parameters: - * - in: path - * name: id - * description: Item ID to delete - * required: true - * schema: - * type: string - * responses: - * 200: - * description: The item was successfully deleted - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Permissions" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.delete('/:id', wrapAsync(async (req, res) => { - await PermissionsService.remove(req.params.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/permissions/deleteByIds: - * post: - * security: - * - bearerAuth: [] - * tags: [Permissions] - * summary: Delete the selected item list - * description: Delete the selected item list - * requestBody: - * required: true - * content: - * application/json: - * schema: - * properties: - * ids: - * description: IDs of the updated items - * type: array - * responses: - * 200: - * description: The items was successfully deleted - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Permissions" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Items not found - * 500: - * description: Some server error - */ -router.post('/deleteByIds', wrapAsync(async (req, res) => { - await PermissionsService.deleteByIds(req.body.data, req.currentUser); - const payload = true; - res.status(200).send(payload); - })); - -/** - * @swagger - * /api/permissions: - * get: - * security: - * - bearerAuth: [] - * tags: [Permissions] - * summary: Get all permissions - * description: Get all permissions - * responses: - * 200: - * description: Permissions list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Permissions" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error -*/ -router.get('/', wrapAsync(async (req, res) => { - const filetype = req.query.filetype - - const currentUser = req.currentUser; - const payload = await PermissionsDBApi.findAll( - req.query, { currentUser } - ); - if (filetype && filetype === 'csv') { - const fields = ['id','name', - - - - ]; - const opts = { fields }; - try { - const csv = parse(payload.rows, opts); - res.status(200).attachment(csv); - res.send(csv) - - } catch (err) { - console.error(err); - } - } else { - res.status(200).send(payload); - } - -})); - -/** - * @swagger - * /api/permissions/count: - * get: - * security: - * - bearerAuth: [] - * tags: [Permissions] - * summary: Count all permissions - * description: Count all permissions - * responses: - * 200: - * description: Permissions count successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Permissions" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/count', wrapAsync(async (req, res) => { - - const currentUser = req.currentUser; - const payload = await PermissionsDBApi.findAll( - req.query, - null, - { countOnly: true, currentUser } - ); - - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/permissions/autocomplete: - * get: - * security: - * - bearerAuth: [] - * tags: [Permissions] - * summary: Find all permissions that match search criteria - * description: Find all permissions that match search criteria - * responses: - * 200: - * description: Permissions list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Permissions" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/autocomplete', async (req, res) => { - - const payload = await PermissionsDBApi.findAllAutocomplete( - req.query.query, - req.query.limit, - req.query.offset, - - ); - - res.status(200).send(payload); -}); - -/** - * @swagger - * /api/permissions/{id}: - * get: - * security: - * - bearerAuth: [] - * tags: [Permissions] - * summary: Get selected item - * description: Get selected item - * parameters: - * - in: path - * name: id - * description: ID of item to get - * required: true - * schema: - * type: string - * responses: - * 200: - * description: Selected item successfully received - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Permissions" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.get('/:id', wrapAsync(async (req, res) => { - const payload = await PermissionsDBApi.findBy( - { id: req.params.id }, - ); - - - - res.status(200).send(payload); -})); - -router.use('/', require('../helpers').commonErrorHandler); - -module.exports = router; diff --git a/backend/src/routes/pexels.js b/backend/src/routes/pexels.js deleted file mode 100644 index 8298595..0000000 --- a/backend/src/routes/pexels.js +++ /dev/null @@ -1,104 +0,0 @@ -const express = require('express'); -const router = express.Router(); -const { pexelsKey, pexelsQuery } = require('../config'); -const fetch = require('node-fetch'); - -const KEY = pexelsKey; - -router.get('/image', async (req, res) => { - const headers = { - Authorization: `${KEY}`, - }; - const query = pexelsQuery || 'nature'; - const orientation = 'portrait'; - const perPage = 1; - const url = `https://api.pexels.com/v1/search?query=${query}&orientation=${orientation}&per_page=${perPage}&page=1`; - - try { - const response = await fetch(url, { headers }); - const data = await response.json(); - res.status(200).json(data.photos[0]); - } catch (error) { - res.status(200).json({ error: 'Failed to fetch image' }); - } -}); - -router.get('/video', async (req, res) => { - const headers = { - Authorization: `${KEY}`, - }; - const query = pexelsQuery || 'nature'; - const orientation = 'portrait'; - const perPage = 1; - const url = `https://api.pexels.com/videos/search?query=${query}&orientation=${orientation}&per_page=${perPage}&page=1`; - - try { - const response = await fetch(url, { headers }); - const data = await response.json(); - res.status(200).json(data.videos[0]); - } catch (error) { - res.status(200).json({ error: 'Failed to fetch video' }); - } -}); - -router.get('/multiple-images', async (req, res) => { - const headers = { - Authorization: `${KEY}`, - }; - - const queries = req.query.queries - ? req.query.queries.split(',') - : ['home', 'apple', 'pizza', 'mountains', 'cat']; - const orientation = 'square'; - const perPage = 1; - - const fallbackImage = { - src: 'https://images.pexels.com/photos/8199252/pexels-photo-8199252.jpeg', - photographer: 'Yan Krukau', - photographer_url: 'https://www.pexels.com/@yankrukov', - }; - const fetchFallbackImage = async () => { - try { - const response = await fetch('https://picsum.photos/600'); - return { - src: response.url, - photographer: 'Random Picsum', - photographer_url: 'https://picsum.photos/', - }; - } catch (error) { - return fallbackImage; - } - }; - const fetchImage = async (query) => { - const url = `https://api.pexels.com/v1/search?query=${query}&orientation=${orientation}&per_page=${perPage}&page=1`; - const response = await fetch(url, { headers }); - const data = await response.json(); - return data.photos[0] || null; - }; - - const imagePromises = queries.map((query) => fetchImage(query)); - const imagesResults = await Promise.allSettled(imagePromises); - - const formattedImages = await Promise.all(imagesResults.map(async (result) => { - if (result.status === 'fulfilled' && result.value) { - const image = result.value; - return { - src: image.src?.original || fallbackImage.src, - photographer: image.photographer || fallbackImage.photographer, - photographer_url: image.photographer_url || fallbackImage.photographer_url, - }; - } else { - const fallback = await fetchFallbackImage(); - return { - src: fallback.src || '', - photographer: fallback.photographer || 'Unknown', - photographer_url: fallback.photographer_url || '', - }; - } - })); - - - res.json(formattedImages); -}); - -module.exports = router; diff --git a/backend/src/routes/product_categories.js b/backend/src/routes/product_categories.js deleted file mode 100644 index ed24049..0000000 --- a/backend/src/routes/product_categories.js +++ /dev/null @@ -1,435 +0,0 @@ - -const express = require('express'); - -const Product_categoriesService = require('../services/product_categories'); -const Product_categoriesDBApi = require('../db/api/product_categories'); -const wrapAsync = require('../helpers').wrapAsync; - - -const router = express.Router(); - -const { parse } = require('json2csv'); - - -const { - checkCrudPermissions, -} = require('../middlewares/check-permissions'); - -router.use(checkCrudPermissions('product_categories')); - - -/** - * @swagger - * components: - * schemas: - * Product_categories: - * type: object - * properties: - - * name: - * type: string - * default: name - * slug: - * type: string - * default: slug - * description: - * type: string - * default: description - - - - */ - -/** - * @swagger - * tags: - * name: Product_categories - * description: The Product_categories managing API - */ - -/** -* @swagger -* /api/product_categories: -* post: -* security: -* - bearerAuth: [] -* tags: [Product_categories] -* summary: Add new item -* description: Add new item -* requestBody: -* required: true -* content: -* application/json: -* schema: -* properties: -* data: -* description: Data of the updated item -* type: object -* $ref: "#/components/schemas/Product_categories" -* responses: -* 200: -* description: The item was successfully added -* content: -* application/json: -* schema: -* $ref: "#/components/schemas/Product_categories" -* 401: -* $ref: "#/components/responses/UnauthorizedError" -* 405: -* description: Invalid input data -* 500: -* description: Some server error -*/ -router.post('/', wrapAsync(async (req, res) => { - const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`; - const link = new URL(referer); - await Product_categoriesService.create(req.body.data, req.currentUser, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/budgets/bulk-import: - * post: - * security: - * - bearerAuth: [] - * tags: [Product_categories] - * summary: Bulk import items - * description: Bulk import items - * requestBody: - * required: true - * content: - * application/json: - * schema: - * properties: - * data: - * description: Data of the updated items - * type: array - * items: - * $ref: "#/components/schemas/Product_categories" - * responses: - * 200: - * description: The items were successfully imported - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Product_categories" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 405: - * description: Invalid input data - * 500: - * description: Some server error - * - */ -router.post('/bulk-import', wrapAsync(async (req, res) => { - const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`; - const link = new URL(referer); - await Product_categoriesService.bulkImport(req, res, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/product_categories/{id}: - * put: - * security: - * - bearerAuth: [] - * tags: [Product_categories] - * summary: Update the data of the selected item - * description: Update the data of the selected item - * parameters: - * - in: path - * name: id - * description: Item ID to update - * required: true - * schema: - * type: string - * requestBody: - * description: Set new item data - * required: true - * content: - * application/json: - * schema: - * properties: - * id: - * description: ID of the updated item - * type: string - * data: - * description: Data of the updated item - * type: object - * $ref: "#/components/schemas/Product_categories" - * required: - * - id - * responses: - * 200: - * description: The item data was successfully updated - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Product_categories" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.put('/:id', wrapAsync(async (req, res) => { - await Product_categoriesService.update(req.body.data, req.body.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/product_categories/{id}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Product_categories] - * summary: Delete the selected item - * description: Delete the selected item - * parameters: - * - in: path - * name: id - * description: Item ID to delete - * required: true - * schema: - * type: string - * responses: - * 200: - * description: The item was successfully deleted - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Product_categories" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.delete('/:id', wrapAsync(async (req, res) => { - await Product_categoriesService.remove(req.params.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/product_categories/deleteByIds: - * post: - * security: - * - bearerAuth: [] - * tags: [Product_categories] - * summary: Delete the selected item list - * description: Delete the selected item list - * requestBody: - * required: true - * content: - * application/json: - * schema: - * properties: - * ids: - * description: IDs of the updated items - * type: array - * responses: - * 200: - * description: The items was successfully deleted - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Product_categories" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Items not found - * 500: - * description: Some server error - */ -router.post('/deleteByIds', wrapAsync(async (req, res) => { - await Product_categoriesService.deleteByIds(req.body.data, req.currentUser); - const payload = true; - res.status(200).send(payload); - })); - -/** - * @swagger - * /api/product_categories: - * get: - * security: - * - bearerAuth: [] - * tags: [Product_categories] - * summary: Get all product_categories - * description: Get all product_categories - * responses: - * 200: - * description: Product_categories list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Product_categories" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error -*/ -router.get('/', wrapAsync(async (req, res) => { - const filetype = req.query.filetype - - const currentUser = req.currentUser; - const payload = await Product_categoriesDBApi.findAll( - req.query, { currentUser } - ); - if (filetype && filetype === 'csv') { - const fields = ['id','name','slug','description', - - - - ]; - const opts = { fields }; - try { - const csv = parse(payload.rows, opts); - res.status(200).attachment(csv); - res.send(csv) - - } catch (err) { - console.error(err); - } - } else { - res.status(200).send(payload); - } - -})); - -/** - * @swagger - * /api/product_categories/count: - * get: - * security: - * - bearerAuth: [] - * tags: [Product_categories] - * summary: Count all product_categories - * description: Count all product_categories - * responses: - * 200: - * description: Product_categories count successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Product_categories" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/count', wrapAsync(async (req, res) => { - - const currentUser = req.currentUser; - const payload = await Product_categoriesDBApi.findAll( - req.query, - null, - { countOnly: true, currentUser } - ); - - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/product_categories/autocomplete: - * get: - * security: - * - bearerAuth: [] - * tags: [Product_categories] - * summary: Find all product_categories that match search criteria - * description: Find all product_categories that match search criteria - * responses: - * 200: - * description: Product_categories list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Product_categories" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/autocomplete', async (req, res) => { - - const payload = await Product_categoriesDBApi.findAllAutocomplete( - req.query.query, - req.query.limit, - req.query.offset, - - ); - - res.status(200).send(payload); -}); - -/** - * @swagger - * /api/product_categories/{id}: - * get: - * security: - * - bearerAuth: [] - * tags: [Product_categories] - * summary: Get selected item - * description: Get selected item - * parameters: - * - in: path - * name: id - * description: ID of item to get - * required: true - * schema: - * type: string - * responses: - * 200: - * description: Selected item successfully received - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Product_categories" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.get('/:id', wrapAsync(async (req, res) => { - const payload = await Product_categoriesDBApi.findBy( - { id: req.params.id }, - ); - - - - res.status(200).send(payload); -})); - -router.use('/', require('../helpers').commonErrorHandler); - -module.exports = router; diff --git a/backend/src/routes/products.js b/backend/src/routes/products.js deleted file mode 100644 index b39fba5..0000000 --- a/backend/src/routes/products.js +++ /dev/null @@ -1,460 +0,0 @@ - -const express = require('express'); - -const ProductsService = require('../services/products'); -const ProductsDBApi = require('../db/api/products'); -const wrapAsync = require('../helpers').wrapAsync; - - -const router = express.Router(); - -const { parse } = require('json2csv'); - - -const { - checkCrudPermissions, -} = require('../middlewares/check-permissions'); - -router.use(checkCrudPermissions('products')); - - -/** - * @swagger - * components: - * schemas: - * Products: - * type: object - * properties: - - * name: - * type: string - * default: name - * sku: - * type: string - * default: sku - * barcode: - * type: string - * default: barcode - * short_description: - * type: string - * default: short_description - * description: - * type: string - * default: description - - * stock_on_hand: - * type: integer - * format: int64 - * reorder_point: - * type: integer - * format: int64 - - * price: - * type: integer - * format: int64 - * compare_at_price: - * type: integer - * format: int64 - * cost: - * type: integer - * format: int64 - * weight: - * type: integer - * format: int64 - - * - */ - -/** - * @swagger - * tags: - * name: Products - * description: The Products managing API - */ - -/** -* @swagger -* /api/products: -* post: -* security: -* - bearerAuth: [] -* tags: [Products] -* summary: Add new item -* description: Add new item -* requestBody: -* required: true -* content: -* application/json: -* schema: -* properties: -* data: -* description: Data of the updated item -* type: object -* $ref: "#/components/schemas/Products" -* responses: -* 200: -* description: The item was successfully added -* content: -* application/json: -* schema: -* $ref: "#/components/schemas/Products" -* 401: -* $ref: "#/components/responses/UnauthorizedError" -* 405: -* description: Invalid input data -* 500: -* description: Some server error -*/ -router.post('/', wrapAsync(async (req, res) => { - const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`; - const link = new URL(referer); - await ProductsService.create(req.body.data, req.currentUser, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/budgets/bulk-import: - * post: - * security: - * - bearerAuth: [] - * tags: [Products] - * summary: Bulk import items - * description: Bulk import items - * requestBody: - * required: true - * content: - * application/json: - * schema: - * properties: - * data: - * description: Data of the updated items - * type: array - * items: - * $ref: "#/components/schemas/Products" - * responses: - * 200: - * description: The items were successfully imported - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Products" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 405: - * description: Invalid input data - * 500: - * description: Some server error - * - */ -router.post('/bulk-import', wrapAsync(async (req, res) => { - const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`; - const link = new URL(referer); - await ProductsService.bulkImport(req, res, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/products/{id}: - * put: - * security: - * - bearerAuth: [] - * tags: [Products] - * summary: Update the data of the selected item - * description: Update the data of the selected item - * parameters: - * - in: path - * name: id - * description: Item ID to update - * required: true - * schema: - * type: string - * requestBody: - * description: Set new item data - * required: true - * content: - * application/json: - * schema: - * properties: - * id: - * description: ID of the updated item - * type: string - * data: - * description: Data of the updated item - * type: object - * $ref: "#/components/schemas/Products" - * required: - * - id - * responses: - * 200: - * description: The item data was successfully updated - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Products" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.put('/:id', wrapAsync(async (req, res) => { - await ProductsService.update(req.body.data, req.body.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/products/{id}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Products] - * summary: Delete the selected item - * description: Delete the selected item - * parameters: - * - in: path - * name: id - * description: Item ID to delete - * required: true - * schema: - * type: string - * responses: - * 200: - * description: The item was successfully deleted - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Products" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.delete('/:id', wrapAsync(async (req, res) => { - await ProductsService.remove(req.params.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/products/deleteByIds: - * post: - * security: - * - bearerAuth: [] - * tags: [Products] - * summary: Delete the selected item list - * description: Delete the selected item list - * requestBody: - * required: true - * content: - * application/json: - * schema: - * properties: - * ids: - * description: IDs of the updated items - * type: array - * responses: - * 200: - * description: The items was successfully deleted - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Products" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Items not found - * 500: - * description: Some server error - */ -router.post('/deleteByIds', wrapAsync(async (req, res) => { - await ProductsService.deleteByIds(req.body.data, req.currentUser); - const payload = true; - res.status(200).send(payload); - })); - -/** - * @swagger - * /api/products: - * get: - * security: - * - bearerAuth: [] - * tags: [Products] - * summary: Get all products - * description: Get all products - * responses: - * 200: - * description: Products list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Products" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error -*/ -router.get('/', wrapAsync(async (req, res) => { - const filetype = req.query.filetype - - const currentUser = req.currentUser; - const payload = await ProductsDBApi.findAll( - req.query, { currentUser } - ); - if (filetype && filetype === 'csv') { - const fields = ['id','name','sku','barcode','short_description','description', - 'stock_on_hand','reorder_point', - 'price','compare_at_price','cost','weight', - - ]; - const opts = { fields }; - try { - const csv = parse(payload.rows, opts); - res.status(200).attachment(csv); - res.send(csv) - - } catch (err) { - console.error(err); - } - } else { - res.status(200).send(payload); - } - -})); - -/** - * @swagger - * /api/products/count: - * get: - * security: - * - bearerAuth: [] - * tags: [Products] - * summary: Count all products - * description: Count all products - * responses: - * 200: - * description: Products count successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Products" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/count', wrapAsync(async (req, res) => { - - const currentUser = req.currentUser; - const payload = await ProductsDBApi.findAll( - req.query, - null, - { countOnly: true, currentUser } - ); - - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/products/autocomplete: - * get: - * security: - * - bearerAuth: [] - * tags: [Products] - * summary: Find all products that match search criteria - * description: Find all products that match search criteria - * responses: - * 200: - * description: Products list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Products" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/autocomplete', async (req, res) => { - - const payload = await ProductsDBApi.findAllAutocomplete( - req.query.query, - req.query.limit, - req.query.offset, - - ); - - res.status(200).send(payload); -}); - -/** - * @swagger - * /api/products/{id}: - * get: - * security: - * - bearerAuth: [] - * tags: [Products] - * summary: Get selected item - * description: Get selected item - * parameters: - * - in: path - * name: id - * description: ID of item to get - * required: true - * schema: - * type: string - * responses: - * 200: - * description: Selected item successfully received - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Products" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.get('/:id', wrapAsync(async (req, res) => { - const payload = await ProductsDBApi.findBy( - { id: req.params.id }, - ); - - - - res.status(200).send(payload); -})); - -router.use('/', require('../helpers').commonErrorHandler); - -module.exports = router; diff --git a/backend/src/routes/roles.js b/backend/src/routes/roles.js deleted file mode 100644 index 42f1121..0000000 --- a/backend/src/routes/roles.js +++ /dev/null @@ -1,429 +0,0 @@ - -const express = require('express'); - -const RolesService = require('../services/roles'); -const RolesDBApi = require('../db/api/roles'); -const wrapAsync = require('../helpers').wrapAsync; - - -const router = express.Router(); - -const { parse } = require('json2csv'); - - -const { - checkCrudPermissions, -} = require('../middlewares/check-permissions'); - -router.use(checkCrudPermissions('roles')); - - -/** - * @swagger - * components: - * schemas: - * Roles: - * type: object - * properties: - - * name: - * type: string - * default: name - - - - */ - -/** - * @swagger - * tags: - * name: Roles - * description: The Roles managing API - */ - -/** -* @swagger -* /api/roles: -* post: -* security: -* - bearerAuth: [] -* tags: [Roles] -* summary: Add new item -* description: Add new item -* requestBody: -* required: true -* content: -* application/json: -* schema: -* properties: -* data: -* description: Data of the updated item -* type: object -* $ref: "#/components/schemas/Roles" -* responses: -* 200: -* description: The item was successfully added -* content: -* application/json: -* schema: -* $ref: "#/components/schemas/Roles" -* 401: -* $ref: "#/components/responses/UnauthorizedError" -* 405: -* description: Invalid input data -* 500: -* description: Some server error -*/ -router.post('/', wrapAsync(async (req, res) => { - const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`; - const link = new URL(referer); - await RolesService.create(req.body.data, req.currentUser, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/budgets/bulk-import: - * post: - * security: - * - bearerAuth: [] - * tags: [Roles] - * summary: Bulk import items - * description: Bulk import items - * requestBody: - * required: true - * content: - * application/json: - * schema: - * properties: - * data: - * description: Data of the updated items - * type: array - * items: - * $ref: "#/components/schemas/Roles" - * responses: - * 200: - * description: The items were successfully imported - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Roles" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 405: - * description: Invalid input data - * 500: - * description: Some server error - * - */ -router.post('/bulk-import', wrapAsync(async (req, res) => { - const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`; - const link = new URL(referer); - await RolesService.bulkImport(req, res, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/roles/{id}: - * put: - * security: - * - bearerAuth: [] - * tags: [Roles] - * summary: Update the data of the selected item - * description: Update the data of the selected item - * parameters: - * - in: path - * name: id - * description: Item ID to update - * required: true - * schema: - * type: string - * requestBody: - * description: Set new item data - * required: true - * content: - * application/json: - * schema: - * properties: - * id: - * description: ID of the updated item - * type: string - * data: - * description: Data of the updated item - * type: object - * $ref: "#/components/schemas/Roles" - * required: - * - id - * responses: - * 200: - * description: The item data was successfully updated - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Roles" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.put('/:id', wrapAsync(async (req, res) => { - await RolesService.update(req.body.data, req.body.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/roles/{id}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Roles] - * summary: Delete the selected item - * description: Delete the selected item - * parameters: - * - in: path - * name: id - * description: Item ID to delete - * required: true - * schema: - * type: string - * responses: - * 200: - * description: The item was successfully deleted - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Roles" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.delete('/:id', wrapAsync(async (req, res) => { - await RolesService.remove(req.params.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/roles/deleteByIds: - * post: - * security: - * - bearerAuth: [] - * tags: [Roles] - * summary: Delete the selected item list - * description: Delete the selected item list - * requestBody: - * required: true - * content: - * application/json: - * schema: - * properties: - * ids: - * description: IDs of the updated items - * type: array - * responses: - * 200: - * description: The items was successfully deleted - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Roles" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Items not found - * 500: - * description: Some server error - */ -router.post('/deleteByIds', wrapAsync(async (req, res) => { - await RolesService.deleteByIds(req.body.data, req.currentUser); - const payload = true; - res.status(200).send(payload); - })); - -/** - * @swagger - * /api/roles: - * get: - * security: - * - bearerAuth: [] - * tags: [Roles] - * summary: Get all roles - * description: Get all roles - * responses: - * 200: - * description: Roles list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Roles" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error -*/ -router.get('/', wrapAsync(async (req, res) => { - const filetype = req.query.filetype - - const currentUser = req.currentUser; - const payload = await RolesDBApi.findAll( - req.query, { currentUser } - ); - if (filetype && filetype === 'csv') { - const fields = ['id','name', - - - - ]; - const opts = { fields }; - try { - const csv = parse(payload.rows, opts); - res.status(200).attachment(csv); - res.send(csv) - - } catch (err) { - console.error(err); - } - } else { - res.status(200).send(payload); - } - -})); - -/** - * @swagger - * /api/roles/count: - * get: - * security: - * - bearerAuth: [] - * tags: [Roles] - * summary: Count all roles - * description: Count all roles - * responses: - * 200: - * description: Roles count successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Roles" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/count', wrapAsync(async (req, res) => { - - const currentUser = req.currentUser; - const payload = await RolesDBApi.findAll( - req.query, - null, - { countOnly: true, currentUser } - ); - - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/roles/autocomplete: - * get: - * security: - * - bearerAuth: [] - * tags: [Roles] - * summary: Find all roles that match search criteria - * description: Find all roles that match search criteria - * responses: - * 200: - * description: Roles list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Roles" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/autocomplete', async (req, res) => { - - const payload = await RolesDBApi.findAllAutocomplete( - req.query.query, - req.query.limit, - req.query.offset, - - ); - - res.status(200).send(payload); -}); - -/** - * @swagger - * /api/roles/{id}: - * get: - * security: - * - bearerAuth: [] - * tags: [Roles] - * summary: Get selected item - * description: Get selected item - * parameters: - * - in: path - * name: id - * description: ID of item to get - * required: true - * schema: - * type: string - * responses: - * 200: - * description: Selected item successfully received - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Roles" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.get('/:id', wrapAsync(async (req, res) => { - const payload = await RolesDBApi.findBy( - { id: req.params.id }, - ); - - - - res.status(200).send(payload); -})); - -router.use('/', require('../helpers').commonErrorHandler); - -module.exports = router; diff --git a/backend/src/routes/search.js b/backend/src/routes/search.js deleted file mode 100644 index 164b376..0000000 --- a/backend/src/routes/search.js +++ /dev/null @@ -1,52 +0,0 @@ -const express = require('express'); -const SearchService = require('../services/search'); - - -const router = express.Router(); - -const { checkCrudPermissions } = require('../middlewares/check-permissions'); -router.use(checkCrudPermissions('search')); - -/** - * @swagger - * path: - * /api/search: - * post: - * summary: Search - * description: Search results across multiple tables - * requestBody: - * content: - * application/json: - * schema: - * type: object - * properties: - * searchQuery: - * type: string - * required: - * - searchQuery - * responses: - * 200: - * description: Successful request - * 400: - * description: Invalid request - * 500: - * description: Internal server error - */ - -router.post('/', async (req, res) => { - const { searchQuery } = req.body; - - if (!searchQuery) { - return res.status(400).json({ error: 'Please enter a search query' }); - } - - try { - const foundMatches = await SearchService.search(searchQuery, req.currentUser ); - res.json(foundMatches); - } catch (error) { - console.error('Internal Server Error', error); - res.status(500).json({ error: 'Internal Server Error' }); - } - }); - -module.exports = router; \ No newline at end of file diff --git a/backend/src/routes/shipments.js b/backend/src/routes/shipments.js deleted file mode 100644 index 3c456b0..0000000 --- a/backend/src/routes/shipments.js +++ /dev/null @@ -1,448 +0,0 @@ - -const express = require('express'); - -const ShipmentsService = require('../services/shipments'); -const ShipmentsDBApi = require('../db/api/shipments'); -const wrapAsync = require('../helpers').wrapAsync; - - -const router = express.Router(); - -const { parse } = require('json2csv'); - - -const { - checkCrudPermissions, -} = require('../middlewares/check-permissions'); - -router.use(checkCrudPermissions('shipments')); - - -/** - * @swagger - * components: - * schemas: - * Shipments: - * type: object - * properties: - - * shipment_number: - * type: string - * default: shipment_number - * carrier: - * type: string - * default: carrier - * service_level: - * type: string - * default: service_level - * tracking_number: - * type: string - * default: tracking_number - * label_url: - * type: string - * default: label_url - * notes: - * type: string - * default: notes - - - * shipping_cost: - * type: integer - * format: int64 - - * - */ - -/** - * @swagger - * tags: - * name: Shipments - * description: The Shipments managing API - */ - -/** -* @swagger -* /api/shipments: -* post: -* security: -* - bearerAuth: [] -* tags: [Shipments] -* summary: Add new item -* description: Add new item -* requestBody: -* required: true -* content: -* application/json: -* schema: -* properties: -* data: -* description: Data of the updated item -* type: object -* $ref: "#/components/schemas/Shipments" -* responses: -* 200: -* description: The item was successfully added -* content: -* application/json: -* schema: -* $ref: "#/components/schemas/Shipments" -* 401: -* $ref: "#/components/responses/UnauthorizedError" -* 405: -* description: Invalid input data -* 500: -* description: Some server error -*/ -router.post('/', wrapAsync(async (req, res) => { - const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`; - const link = new URL(referer); - await ShipmentsService.create(req.body.data, req.currentUser, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/budgets/bulk-import: - * post: - * security: - * - bearerAuth: [] - * tags: [Shipments] - * summary: Bulk import items - * description: Bulk import items - * requestBody: - * required: true - * content: - * application/json: - * schema: - * properties: - * data: - * description: Data of the updated items - * type: array - * items: - * $ref: "#/components/schemas/Shipments" - * responses: - * 200: - * description: The items were successfully imported - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Shipments" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 405: - * description: Invalid input data - * 500: - * description: Some server error - * - */ -router.post('/bulk-import', wrapAsync(async (req, res) => { - const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`; - const link = new URL(referer); - await ShipmentsService.bulkImport(req, res, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/shipments/{id}: - * put: - * security: - * - bearerAuth: [] - * tags: [Shipments] - * summary: Update the data of the selected item - * description: Update the data of the selected item - * parameters: - * - in: path - * name: id - * description: Item ID to update - * required: true - * schema: - * type: string - * requestBody: - * description: Set new item data - * required: true - * content: - * application/json: - * schema: - * properties: - * id: - * description: ID of the updated item - * type: string - * data: - * description: Data of the updated item - * type: object - * $ref: "#/components/schemas/Shipments" - * required: - * - id - * responses: - * 200: - * description: The item data was successfully updated - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Shipments" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.put('/:id', wrapAsync(async (req, res) => { - await ShipmentsService.update(req.body.data, req.body.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/shipments/{id}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Shipments] - * summary: Delete the selected item - * description: Delete the selected item - * parameters: - * - in: path - * name: id - * description: Item ID to delete - * required: true - * schema: - * type: string - * responses: - * 200: - * description: The item was successfully deleted - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Shipments" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.delete('/:id', wrapAsync(async (req, res) => { - await ShipmentsService.remove(req.params.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/shipments/deleteByIds: - * post: - * security: - * - bearerAuth: [] - * tags: [Shipments] - * summary: Delete the selected item list - * description: Delete the selected item list - * requestBody: - * required: true - * content: - * application/json: - * schema: - * properties: - * ids: - * description: IDs of the updated items - * type: array - * responses: - * 200: - * description: The items was successfully deleted - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Shipments" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Items not found - * 500: - * description: Some server error - */ -router.post('/deleteByIds', wrapAsync(async (req, res) => { - await ShipmentsService.deleteByIds(req.body.data, req.currentUser); - const payload = true; - res.status(200).send(payload); - })); - -/** - * @swagger - * /api/shipments: - * get: - * security: - * - bearerAuth: [] - * tags: [Shipments] - * summary: Get all shipments - * description: Get all shipments - * responses: - * 200: - * description: Shipments list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Shipments" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error -*/ -router.get('/', wrapAsync(async (req, res) => { - const filetype = req.query.filetype - - const currentUser = req.currentUser; - const payload = await ShipmentsDBApi.findAll( - req.query, { currentUser } - ); - if (filetype && filetype === 'csv') { - const fields = ['id','shipment_number','carrier','service_level','tracking_number','label_url','notes', - - 'shipping_cost', - 'packed_at','shipped_at','delivered_at', - ]; - const opts = { fields }; - try { - const csv = parse(payload.rows, opts); - res.status(200).attachment(csv); - res.send(csv) - - } catch (err) { - console.error(err); - } - } else { - res.status(200).send(payload); - } - -})); - -/** - * @swagger - * /api/shipments/count: - * get: - * security: - * - bearerAuth: [] - * tags: [Shipments] - * summary: Count all shipments - * description: Count all shipments - * responses: - * 200: - * description: Shipments count successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Shipments" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/count', wrapAsync(async (req, res) => { - - const currentUser = req.currentUser; - const payload = await ShipmentsDBApi.findAll( - req.query, - null, - { countOnly: true, currentUser } - ); - - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/shipments/autocomplete: - * get: - * security: - * - bearerAuth: [] - * tags: [Shipments] - * summary: Find all shipments that match search criteria - * description: Find all shipments that match search criteria - * responses: - * 200: - * description: Shipments list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Shipments" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/autocomplete', async (req, res) => { - - const payload = await ShipmentsDBApi.findAllAutocomplete( - req.query.query, - req.query.limit, - req.query.offset, - - ); - - res.status(200).send(payload); -}); - -/** - * @swagger - * /api/shipments/{id}: - * get: - * security: - * - bearerAuth: [] - * tags: [Shipments] - * summary: Get selected item - * description: Get selected item - * parameters: - * - in: path - * name: id - * description: ID of item to get - * required: true - * schema: - * type: string - * responses: - * 200: - * description: Selected item successfully received - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Shipments" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.get('/:id', wrapAsync(async (req, res) => { - const payload = await ShipmentsDBApi.findBy( - { id: req.params.id }, - ); - - - - res.status(200).send(payload); -})); - -router.use('/', require('../helpers').commonErrorHandler); - -module.exports = router; diff --git a/backend/src/routes/sql.js b/backend/src/routes/sql.js deleted file mode 100644 index b844f07..0000000 --- a/backend/src/routes/sql.js +++ /dev/null @@ -1,61 +0,0 @@ -const express = require('express'); -const db = require('../db/models'); -const wrapAsync = require('../helpers').wrapAsync; - -const router = express.Router(); - -/** - * @swagger - * /api/sql: - * post: - * security: - * - bearerAuth: [] - * summary: Execute a SELECT-only SQL query - * description: Executes a read-only SQL query and returns rows. - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * sql: - * type: string - * required: - * - sql - * responses: - * 200: - * description: Query result - * 400: - * description: Invalid SQL - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 500: - * description: Internal server error - */ -router.post( - '/', - wrapAsync(async (req, res) => { - const { sql } = req.body; - if (typeof sql !== 'string' || !sql.trim()) { - return res.status(400).json({ error: 'SQL is required' }); - } - - const normalized = sql.trim().replace(/;+\s*$/, ''); - if (!/^select\b/i.test(normalized)) { - return res.status(400).json({ error: 'Only SELECT statements are allowed' }); - } - - if (normalized.includes(';')) { - return res.status(400).json({ error: 'Only a single SELECT statement is allowed' }); - } - - const rows = await db.sequelize.query(normalized, { - type: db.Sequelize.QueryTypes.SELECT, - }); - - return res.status(200).json({ rows }); - }), -); - -module.exports = router; diff --git a/backend/src/routes/users.js b/backend/src/routes/users.js deleted file mode 100644 index 19df9ae..0000000 --- a/backend/src/routes/users.js +++ /dev/null @@ -1,440 +0,0 @@ - -const express = require('express'); - -const UsersService = require('../services/users'); -const UsersDBApi = require('../db/api/users'); -const wrapAsync = require('../helpers').wrapAsync; - - -const router = express.Router(); - -const { parse } = require('json2csv'); - - -const { - checkCrudPermissions, -} = require('../middlewares/check-permissions'); - -router.use(checkCrudPermissions('users')); - - -/** - * @swagger - * components: - * schemas: - * Users: - * type: object - * properties: - - * firstName: - * type: string - * default: firstName - * lastName: - * type: string - * default: lastName - * phoneNumber: - * type: string - * default: phoneNumber - * email: - * type: string - * default: email - - - - */ - -/** - * @swagger - * tags: - * name: Users - * description: The Users managing API - */ - -/** -* @swagger -* /api/users: -* post: -* security: -* - bearerAuth: [] -* tags: [Users] -* summary: Add new item -* description: Add new item -* requestBody: -* required: true -* content: -* application/json: -* schema: -* properties: -* data: -* description: Data of the updated item -* type: object -* $ref: "#/components/schemas/Users" -* responses: -* 200: -* description: The item was successfully added -* content: -* application/json: -* schema: -* $ref: "#/components/schemas/Users" -* 401: -* $ref: "#/components/responses/UnauthorizedError" -* 405: -* description: Invalid input data -* 500: -* description: Some server error -*/ -router.post('/', wrapAsync(async (req, res) => { - const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`; - const link = new URL(referer); - await UsersService.create(req.body.data, req.currentUser, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/budgets/bulk-import: - * post: - * security: - * - bearerAuth: [] - * tags: [Users] - * summary: Bulk import items - * description: Bulk import items - * requestBody: - * required: true - * content: - * application/json: - * schema: - * properties: - * data: - * description: Data of the updated items - * type: array - * items: - * $ref: "#/components/schemas/Users" - * responses: - * 200: - * description: The items were successfully imported - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Users" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 405: - * description: Invalid input data - * 500: - * description: Some server error - * - */ -router.post('/bulk-import', wrapAsync(async (req, res) => { - const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`; - const link = new URL(referer); - await UsersService.bulkImport(req, res, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/users/{id}: - * put: - * security: - * - bearerAuth: [] - * tags: [Users] - * summary: Update the data of the selected item - * description: Update the data of the selected item - * parameters: - * - in: path - * name: id - * description: Item ID to update - * required: true - * schema: - * type: string - * requestBody: - * description: Set new item data - * required: true - * content: - * application/json: - * schema: - * properties: - * id: - * description: ID of the updated item - * type: string - * data: - * description: Data of the updated item - * type: object - * $ref: "#/components/schemas/Users" - * required: - * - id - * responses: - * 200: - * description: The item data was successfully updated - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Users" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.put('/:id', wrapAsync(async (req, res) => { - await UsersService.update(req.body.data, req.body.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/users/{id}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Users] - * summary: Delete the selected item - * description: Delete the selected item - * parameters: - * - in: path - * name: id - * description: Item ID to delete - * required: true - * schema: - * type: string - * responses: - * 200: - * description: The item was successfully deleted - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Users" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.delete('/:id', wrapAsync(async (req, res) => { - await UsersService.remove(req.params.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/users/deleteByIds: - * post: - * security: - * - bearerAuth: [] - * tags: [Users] - * summary: Delete the selected item list - * description: Delete the selected item list - * requestBody: - * required: true - * content: - * application/json: - * schema: - * properties: - * ids: - * description: IDs of the updated items - * type: array - * responses: - * 200: - * description: The items was successfully deleted - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Users" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Items not found - * 500: - * description: Some server error - */ -router.post('/deleteByIds', wrapAsync(async (req, res) => { - await UsersService.deleteByIds(req.body.data, req.currentUser); - const payload = true; - res.status(200).send(payload); - })); - -/** - * @swagger - * /api/users: - * get: - * security: - * - bearerAuth: [] - * tags: [Users] - * summary: Get all users - * description: Get all users - * responses: - * 200: - * description: Users list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Users" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error -*/ -router.get('/', wrapAsync(async (req, res) => { - const filetype = req.query.filetype - - const currentUser = req.currentUser; - const payload = await UsersDBApi.findAll( - req.query, { currentUser } - ); - if (filetype && filetype === 'csv') { - const fields = ['id','firstName','lastName','phoneNumber','email', - - - - ]; - const opts = { fields }; - try { - const csv = parse(payload.rows, opts); - res.status(200).attachment(csv); - res.send(csv) - - } catch (err) { - console.error(err); - } - } else { - res.status(200).send(payload); - } - -})); - -/** - * @swagger - * /api/users/count: - * get: - * security: - * - bearerAuth: [] - * tags: [Users] - * summary: Count all users - * description: Count all users - * responses: - * 200: - * description: Users count successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Users" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/count', wrapAsync(async (req, res) => { - - const currentUser = req.currentUser; - const payload = await UsersDBApi.findAll( - req.query, - null, - { countOnly: true, currentUser } - ); - - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/users/autocomplete: - * get: - * security: - * - bearerAuth: [] - * tags: [Users] - * summary: Find all users that match search criteria - * description: Find all users that match search criteria - * responses: - * 200: - * description: Users list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Users" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/autocomplete', async (req, res) => { - - const payload = await UsersDBApi.findAllAutocomplete( - req.query.query, - req.query.limit, - req.query.offset, - - ); - - res.status(200).send(payload); -}); - -/** - * @swagger - * /api/users/{id}: - * get: - * security: - * - bearerAuth: [] - * tags: [Users] - * summary: Get selected item - * description: Get selected item - * parameters: - * - in: path - * name: id - * description: ID of item to get - * required: true - * schema: - * type: string - * responses: - * 200: - * description: Selected item successfully received - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Users" - * 400: - * description: Invalid ID supplied - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Item not found - * 500: - * description: Some server error - */ -router.get('/:id', wrapAsync(async (req, res) => { - const payload = await UsersDBApi.findBy( - { id: req.params.id }, - ); - - - delete payload.password; - - - res.status(200).send(payload); -})); - -router.use('/', require('../helpers').commonErrorHandler); - -module.exports = router; diff --git a/backend/src/services/auth.js b/backend/src/services/auth.js deleted file mode 100644 index 2862da4..0000000 --- a/backend/src/services/auth.js +++ /dev/null @@ -1,312 +0,0 @@ -const UsersDBApi = require('../db/api/users'); -const ValidationError = require('./notifications/errors/validation'); -const ForbiddenError = require('./notifications/errors/forbidden'); -const bcrypt = require('bcrypt'); -const EmailAddressVerificationEmail = require('./email/list/addressVerification'); -const InvitationEmail = require("./email/list/invitation"); -const PasswordResetEmail = require('./email/list/passwordReset'); -const EmailSender = require('./email'); -const config = require('../config'); -const helpers = require('../helpers'); - -class Auth { - static async signup(email, password, options = {}, host) { - const user = await UsersDBApi.findBy({email}); - - const hashedPassword = await bcrypt.hash( - password, - config.bcrypt.saltRounds, - ); - - if (user) { - if (user.authenticationUid) { - throw new ValidationError( - 'auth.emailAlreadyInUse', - ); - } - - if (user.disabled) { - throw new ValidationError( - 'auth.userDisabled', - ); - } - - await UsersDBApi.updatePassword( - user.id, - hashedPassword, - options, - ); - - if (EmailSender.isConfigured) { - await this.sendEmailAddressVerificationEmail( - user.email, - host, - ); - } - - const data = { - user: { - id: user.id, - email: user.email - } - }; - - return helpers.jwtSign(data); - } - - const newUser = await UsersDBApi.createFromAuth( - { - firstName: email.split('@')[0], - password: hashedPassword, - email: email, - - }, - options, - ); - - if (EmailSender.isConfigured) { - await this.sendEmailAddressVerificationEmail( - newUser.email, - host, - ); - } - - const data = { - user: { - id: newUser.id, - email: newUser.email - } - }; - - return helpers.jwtSign(data); - } - - static async signin(email, password, options = {}) { - const user = await UsersDBApi.findBy({email}); - - if (!user) { - throw new ValidationError( - 'auth.userNotFound', - ); - } - - if (user.disabled) { - throw new ValidationError( - 'auth.userDisabled', - ); - } - - if (!user.password) { - throw new ValidationError( - 'auth.wrongPassword', - ); - } - - if (!EmailSender.isConfigured) { - user.emailVerified = true; - } - - if (!user.emailVerified) { - throw new ValidationError( - 'auth.userNotVerified', - ); - } - - const passwordsMatch = await bcrypt.compare( - password, - user.password, - ); - - if (!passwordsMatch) { - throw new ValidationError( - 'auth.wrongPassword', - ); - } - - const data = { - user: { - id: user.id, - email: user.email - } - }; - - return helpers.jwtSign(data); - } - - static async sendEmailAddressVerificationEmail( - email, - host, - ) { - - - let link; - try { - const token = await UsersDBApi.generateEmailVerificationToken( - email, - ); - link = `${host}/verify-email?token=${token}`; - } catch (error) { - console.error(error); - throw new ValidationError( - 'auth.emailAddressVerificationEmail.error', - ); - } - - const emailAddressVerificationEmail = new EmailAddressVerificationEmail( - email, - link, - ); - - return new EmailSender( - emailAddressVerificationEmail, - ).send(); - } - - static async sendPasswordResetEmail(email, type = 'register', host) { - - - let link; - - try { - const token = await UsersDBApi.generatePasswordResetToken( - email, - ); - link = `${host}/password-reset?token=${token}`; - } catch (error) { - console.error(error); - throw new ValidationError( - 'auth.passwordReset.error', - ); - } - - let passwordResetEmail; - if (type === 'register') { - passwordResetEmail = new PasswordResetEmail( - email, - link, - ); - } - if (type === 'invitation') { - passwordResetEmail = new InvitationEmail( - email, - link, - ); - } - - return new EmailSender(passwordResetEmail).send(); - } - - static async verifyEmail(token, options = {}) { - const user = await UsersDBApi.findByEmailVerificationToken( - token, - options, - ); - - if (!user) { - throw new ValidationError( - 'auth.emailAddressVerificationEmail.invalidToken', - ); - } - - return UsersDBApi.markEmailVerified( - user.id, - options, - ); - } - - static async passwordUpdate(currentPassword, newPassword, options) { - const currentUser = options.currentUser || null; - if (!currentUser) { - throw new ForbiddenError(); - } - - const currentPasswordMatch = await bcrypt.compare( - currentPassword, - currentUser.password, - ); - - if (!currentPasswordMatch) { - throw new ValidationError( - 'auth.wrongPassword' - ) - } - - const newPasswordMatch = await bcrypt.compare( - newPassword, - currentUser.password, - ); - - if (newPasswordMatch) { - throw new ValidationError( - 'auth.passwordUpdate.samePassword' - ) - } - - const hashedPassword = await bcrypt.hash( - newPassword, - config.bcrypt.saltRounds, - ); - - return UsersDBApi.updatePassword( - currentUser.id, - hashedPassword, - options, - ); - } - - static async passwordReset( - token, - password, - options = {}, - ) { - const user = await UsersDBApi.findByPasswordResetToken( - token, - options, - ); - - if (!user) { - throw new ValidationError( - 'auth.passwordReset.invalidToken', - ); - } - - const hashedPassword = await bcrypt.hash( - password, - config.bcrypt.saltRounds, - ); - - return UsersDBApi.updatePassword( - user.id, - hashedPassword, - options, - ); - } - - static async updateProfile(data, currentUser) { - let transaction = await db.sequelize.transaction(); - - try { - await UsersDBApi.findBy( - {id: currentUser.id}, - {transaction}, - ); - - await UsersDBApi.update( - currentUser.id, - data, - { - currentUser, - transaction - }, - ); - - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } -} - -module.exports = Auth; diff --git a/backend/src/services/customers.js b/backend/src/services/customers.js deleted file mode 100644 index 4232e6d..0000000 --- a/backend/src/services/customers.js +++ /dev/null @@ -1,138 +0,0 @@ -const db = require('../db/models'); -const CustomersDBApi = require('../db/api/customers'); -const processFile = require("../middlewares/upload"); -const ValidationError = require('./notifications/errors/validation'); -const csv = require('csv-parser'); -const axios = require('axios'); -const config = require('../config'); -const stream = require('stream'); - - - - - -module.exports = class CustomersService { - static async create(data, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - await CustomersDBApi.create( - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async bulkImport(req, res, sendInvitationEmails = true, host) { - const transaction = await db.sequelize.transaction(); - - try { - await processFile(req, res); - const bufferStream = new stream.PassThrough(); - const results = []; - - await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream - - await new Promise((resolve, reject) => { - bufferStream - .pipe(csv()) - .on('data', (data) => results.push(data)) - .on('end', async () => { - console.log('CSV results', results); - resolve(); - }) - .on('error', (error) => reject(error)); - }) - - await CustomersDBApi.bulkImport(results, { - transaction, - ignoreDuplicates: true, - validate: true, - currentUser: req.currentUser - }); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - static async update(data, id, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - let customers = await CustomersDBApi.findBy( - {id}, - {transaction}, - ); - - if (!customers) { - throw new ValidationError( - 'customersNotFound', - ); - } - - const updatedCustomers = await CustomersDBApi.update( - id, - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - return updatedCustomers; - - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async deleteByIds(ids, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await CustomersDBApi.deleteByIds(ids, { - currentUser, - transaction, - }); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - static async remove(id, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await CustomersDBApi.remove( - id, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - -}; - - diff --git a/backend/src/services/email/htmlTemplates/addressVerification/emailAddressVerification.html b/backend/src/services/email/htmlTemplates/addressVerification/emailAddressVerification.html deleted file mode 100644 index 32bfa2c..0000000 --- a/backend/src/services/email/htmlTemplates/addressVerification/emailAddressVerification.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/backend/src/services/email/htmlTemplates/invitation/invitationTemplate.html b/backend/src/services/email/htmlTemplates/invitation/invitationTemplate.html deleted file mode 100644 index 064c88d..0000000 --- a/backend/src/services/email/htmlTemplates/invitation/invitationTemplate.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/backend/src/services/email/htmlTemplates/passwordReset/passwordResetEmail.html b/backend/src/services/email/htmlTemplates/passwordReset/passwordResetEmail.html deleted file mode 100644 index 94f0586..0000000 --- a/backend/src/services/email/htmlTemplates/passwordReset/passwordResetEmail.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/backend/src/services/email/index.js b/backend/src/services/email/index.js deleted file mode 100644 index bc97a3d..0000000 --- a/backend/src/services/email/index.js +++ /dev/null @@ -1,44 +0,0 @@ -const config = require('../../config'); -const assert = require('assert'); -const nodemailer = require('nodemailer'); - -module.exports = class EmailSender { - constructor(email) { - this.email = email; - } - - async send() { - assert(this.email, 'email is required'); - assert(this.email.to, 'email.to is required'); - assert(this.email.subject, 'email.subject is required'); - assert(this.email.html, 'email.html is required'); - - const htmlContent = await this.email.html(); - - const transporter = nodemailer.createTransport(this.transportConfig); - - const mailOptions = { - from: this.from, - to: this.email.to, - subject: this.email.subject, - html: htmlContent, - headers: { - 'X-SES-CONFIGURATION-SET': 'flatlogic-app', - }, - }; - - return transporter.sendMail(mailOptions); - } - - static get isConfigured() { - return !!config.email?.auth?.pass && !!config.email?.auth?.user; - } - - get transportConfig() { - return config.email; - } - - get from() { - return config.email.from; - } -}; diff --git a/backend/src/services/email/list/addressVerification.js b/backend/src/services/email/list/addressVerification.js deleted file mode 100644 index 695e199..0000000 --- a/backend/src/services/email/list/addressVerification.js +++ /dev/null @@ -1,38 +0,0 @@ -const { getNotification } = require('../../notifications/helpers'); -const fs = require('fs').promises; -const path = require('path'); - -module.exports = class EmailAddressVerificationEmail { - constructor(to, link) { - this.to = to; - this.link = link; - } - - get subject() { - return getNotification( - 'emails.emailAddressVerification.subject', - getNotification('app.title'), - ); - } - - async html() { - try { - const templatePath = path.join(__dirname, '../../email/htmlTemplates/addressVerification/emailAddressVerification.html'); - - const template = await fs.readFile(templatePath, 'utf8'); - - const appTitle = getNotification('app.title'); - const signupUrl = this.link; - - let html = template.replace(/{appTitle}/g, appTitle) - .replace(/{signupUrl}/g, signupUrl) - .replace(/{to}/g, this.to); - - return html; - } catch (error) { - console.error('Error generating invitation email HTML:', error); - throw error; - } - } - -}; diff --git a/backend/src/services/email/list/invitation.js b/backend/src/services/email/list/invitation.js deleted file mode 100644 index 928c537..0000000 --- a/backend/src/services/email/list/invitation.js +++ /dev/null @@ -1,37 +0,0 @@ -const fs = require('fs').promises; -const path = require('path'); -const { getNotification } = require('../../notifications/helpers'); - -module.exports = class InvitationEmail { - constructor(to, host) { - this.to = to; - this.host = host; - } - - get subject() { - return getNotification( - 'emails.invitation.subject', - getNotification('app.title'), - ); - } - - async html() { - try { - const templatePath = path.join(__dirname, '../../email/htmlTemplates/invitation/invitationTemplate.html'); - - const template = await fs.readFile(templatePath, 'utf8'); - - const appTitle = getNotification('app.title'); - const signupUrl = `${this.host}&invitation=true`; - - let html = template.replace(/{appTitle}/g, appTitle) - .replace(/{signupUrl}/g, signupUrl) - .replace(/{to}/g, this.to); - - return html; - } catch (error) { - console.error('Error generating invitation email HTML:', error); - throw error; - } - } -}; \ No newline at end of file diff --git a/backend/src/services/email/list/passwordReset.js b/backend/src/services/email/list/passwordReset.js deleted file mode 100644 index c1fd105..0000000 --- a/backend/src/services/email/list/passwordReset.js +++ /dev/null @@ -1,38 +0,0 @@ -const { getNotification } = require('../../notifications/helpers'); -const path = require("path"); -const {promises: fs} = require("fs"); - -module.exports = class PasswordResetEmail { - constructor(to, link) { - this.to = to; - this.link = link; - } - - get subject() { - return getNotification( - 'emails.passwordReset.subject', - getNotification('app.title'), - ); - } - - async html() { - try { - const templatePath = path.join(__dirname, '../../email/htmlTemplates/passwordReset/passwordResetEmail.html'); - - const template = await fs.readFile(templatePath, 'utf8'); - - const appTitle = getNotification('app.title'); - const resetUrl = this.link; - const accountName = this.to; - - let html = template.replace(/{appTitle}/g, appTitle) - .replace(/{resetUrl}/g, resetUrl) - .replace(/{accountName}/g, accountName); - - return html; - } catch (error) { - console.error('Error generating invitation email HTML:', error); - throw error; - } - } -}; diff --git a/backend/src/services/file.js b/backend/src/services/file.js deleted file mode 100644 index 597be30..0000000 --- a/backend/src/services/file.js +++ /dev/null @@ -1,213 +0,0 @@ -const formidable = require('formidable'); -const fs = require('fs'); -const config = require('../config'); -const path = require('path'); -const { format } = require("util"); - -const ensureDirectoryExistence = (filePath) => { - const dirname = path.dirname(filePath); - - if (fs.existsSync(dirname)) { - return true; - } - - ensureDirectoryExistence(dirname); - fs.mkdirSync(dirname); -} - -const uploadLocal = ( - folder, - validations = { - entity: null, - maxFileSize: null, - folderIncludesAuthenticationUid: false, - }, -) => { - return (req, res) => { - if (!req.currentUser) { - res.sendStatus(403); - return; - } - - if ( - validations.entity - ) { - res.sendStatus(403); - return; - } - - if (validations.folderIncludesAuthenticationUid) { - folder = folder.replace( - ':userId', - req.currentUser.authenticationUid, - ); - if ( - !req.currentUser.authenticationUid || - !folder.includes(req.currentUser.authenticationUid) - ) { - res.sendStatus(403); - return; - } - } - - const form = new formidable.IncomingForm(); - form.uploadDir = config.uploadDir; - - if (validations && validations.maxFileSize) { - form.maxFileSize = validations.maxFileSize; - } - - form.parse(req, function (err, fields, files) { - const filename = String(fields.filename); - const fileTempUrl = files.file.path; - - if (!filename) { - fs.unlinkSync(fileTempUrl); - res.sendStatus(500); - return; - } - - const privateUrl = path.join( - form.uploadDir, - folder, - filename, - ); - ensureDirectoryExistence(privateUrl); - fs.renameSync(fileTempUrl, privateUrl); - res.sendStatus(200); - }); - - form.on('error', function (err) { - res.status(500).send(err); - }); - } -} - -const downloadLocal = async (req, res) => { - const privateUrl = req.query.privateUrl; - if (!privateUrl) { - return res.sendStatus(404); - } - res.download(path.join(config.uploadDir, privateUrl)); -} - -const initGCloud = () => { - const processFile = require("../middlewares/upload"); - const { Storage } = require("@google-cloud/storage"); - - const crypto = require('crypto') - const hash = config.gcloud.hash - - const privateKey = process.env.GC_PRIVATE_KEY.replace(/\\\n/g, "\n"); - - const storage = new Storage({ - projectId: process.env.GC_PROJECT_ID, - credentials: { - client_email: process.env.GC_CLIENT_EMAIL, - private_key: privateKey - } - }); - - const bucket = storage.bucket(config.gcloud.bucket); - return {hash, bucket, processFile}; -} - -const uploadGCloud = async (folder, req, res) => { - try { - const {hash, bucket, processFile} = initGCloud(); - await processFile(req, res); - let buffer = await req.file.buffer; - let filename = await req.body.filename; - - if (!req.file) { - return res.status(400).send({ message: "Please upload a file!" }); - } - - let path = `${hash}/${folder}/${filename}`; - let blob = bucket.file(path); - - console.log(path); - - const blobStream = blob.createWriteStream({ - resumable: false, - }); - - blobStream.on("error", (err) => { - console.log('Upload error'); - console.log(err.message); - res.status(500).send({ message: err.message }); - }); - - console.log(`https://storage.googleapis.com/${bucket.name}/${blob.name}`); - - blobStream.on("finish", async (data) => { - const publicUrl = format( - `https://storage.googleapis.com/${bucket.name}/${blob.name}` - ); - - res.status(200).send({ - message: "Uploaded the file successfully: " + path, - url: publicUrl, - }); - }); - - blobStream.end(buffer) - } catch (err) { - console.log(err); - - res.status(500).send({ - message: `Could not upload the file. ${err}` - }); - } -} - -const downloadGCloud = async (req, res) => { - try { - const {hash, bucket, processFile} = initGCloud(); - - const privateUrl = await req.query.privateUrl; - const filePath = `${hash}/${privateUrl}`; - const file = bucket.file(filePath) - const fileExists = await file.exists(); - - if (fileExists[0]) { - const stream = file.createReadStream(); - stream.pipe(res); - } - else { - res.status(404).send({ - message: "Could not download the file. " + err, - }); - } - } catch (err) { - res.status(404).send({ - message: "Could not download the file. " + err, - }); - } -} - -const deleteGCloud = async (privateUrl) => { - try { - const {hash, bucket, processFile} = initGCloud(); - const filePath = `${hash}/${privateUrl}`; - - const file = bucket.file(filePath) - const fileExists = await file.exists(); - - if (fileExists[0]) { - file.delete(); - } - } catch (err) { - console.log(`Cannot find the file ${privateUrl}`); - } -} - -module.exports = { - initGCloud, - uploadLocal, - downloadLocal, - deleteGCloud, - uploadGCloud, - downloadGCloud -} - diff --git a/backend/src/services/notifications/errors/forbidden.js b/backend/src/services/notifications/errors/forbidden.js deleted file mode 100644 index 33e5dc2..0000000 --- a/backend/src/services/notifications/errors/forbidden.js +++ /dev/null @@ -1,17 +0,0 @@ -const { getNotification, isNotification } = require('../helpers'); - -module.exports = class ForbiddenError extends Error { - constructor(messageCode) { - let message; - - if (messageCode && isNotification(messageCode)) { - message = getNotification(messageCode); - } - - message = - message || getNotification('errors.forbidden.message'); - - super(message); - this.code = 403; - } -}; diff --git a/backend/src/services/notifications/errors/validation.js b/backend/src/services/notifications/errors/validation.js deleted file mode 100644 index cf3130c..0000000 --- a/backend/src/services/notifications/errors/validation.js +++ /dev/null @@ -1,18 +0,0 @@ -const { getNotification, isNotification } = require('../helpers'); - -module.exports = class ValidationError extends Error { - constructor(messageCode) { - let message; - - if (messageCode && isNotification(messageCode)) { - message = getNotification(messageCode); - } - - message = - message || - getNotification('errors.validation.message'); - - super(message); - this.code = 400; - } -}; diff --git a/backend/src/services/notifications/helpers.js b/backend/src/services/notifications/helpers.js deleted file mode 100644 index b2f31fd..0000000 --- a/backend/src/services/notifications/helpers.js +++ /dev/null @@ -1,35 +0,0 @@ -const _get = require('lodash/get'); -const errors = require('./list'); - -function format(message, args) { - if (!message) { - return null; - } - - return message.replace(/{(\d+)}/g, function ( - match, - number, - ) { - return typeof args[number] != 'undefined' - ? args[number] - : match; - }); -} - -const isNotification = (key) => { - const message = _get(errors, key); - return !!message; -}; - -const getNotification = (key, ...args) => { - const message = _get(errors, key); - - if (!message) { - return key; - } - - return format(message, args); -}; - -exports.getNotification = getNotification; -exports.isNotification = isNotification; diff --git a/backend/src/services/notifications/list.js b/backend/src/services/notifications/list.js deleted file mode 100644 index d0d014a..0000000 --- a/backend/src/services/notifications/list.js +++ /dev/null @@ -1,104 +0,0 @@ -const errors = { - app: { - title: 'Store Operations Hub', - }, - - auth: { - userDisabled: 'Your account is disabled', - forbidden: 'Forbidden', - unauthorized: 'Unauthorized', - userNotFound: `Sorry, we don't recognize your credentials`, - wrongPassword: `Sorry, we don't recognize your credentials`, - weakPassword: 'This password is too weak', - emailAlreadyInUse: 'Email is already in use', - invalidEmail: 'Please provide a valid email', - passwordReset: { - invalidToken: - 'Password reset link is invalid or has expired', - error: `Email not recognized`, - }, - passwordUpdate: { - samePassword: `You can't use the same password. Please create new password` - }, - userNotVerified: `Sorry, your email has not been verified yet`, - emailAddressVerificationEmail: { - invalidToken: - 'Email verification link is invalid or has expired', - error: `Email not recognized`, - }, - }, - - iam: { - errors: { - userAlreadyExists: - 'User with this email already exists', - userNotFound: 'User not found', - disablingHimself: `You can't disable yourself`, - revokingOwnPermission: `You can't revoke your own owner permission`, - deletingHimself: `You can't delete yourself`, - emailRequired: 'Email is required', - }, - }, - - importer: { - errors: { - invalidFileEmpty: 'The file is empty', - invalidFileExcel: - 'Only excel (.xlsx) files are allowed', - invalidFileUpload: - 'Invalid file. Make sure you are using the last version of the template.', - importHashRequired: 'Import hash is required', - importHashExistent: 'Data has already been imported', - userEmailMissing: 'Some items in the CSV do not have an email', - }, - }, - - errors: { - forbidden: { - message: 'Forbidden', - }, - validation: { - message: 'An error occurred', - }, - searchQueryRequired: { - message: 'Search query is required', - }, - }, - - emails: { - invitation: { - subject: `You've been invited to {0}`, - body: ` -

Hello,

-

You've been invited to {0} set password for your {1} account.

-

{2}

-

Thanks,

-

Your {0} team

- `, - }, - emailAddressVerification: { - subject: `Verify your email for {0}`, - body: ` -

Hello,

-

Follow this link to verify your email address.

-

{0}

-

If you didn't ask to verify this address, you can ignore this email.

-

Thanks,

-

Your {1} team

- `, - }, - passwordReset: { - subject: `Reset your password for {0}`, - body: ` -

Hello,

-

Follow this link to reset your {0} password for your {1} account.

-

{2}

-

If you didn't ask to reset your password, you can ignore this email.

-

Thanks,

-

Your {0} team

- `, - }, - }, -}; - -module.exports = errors; diff --git a/backend/src/services/openai.js b/backend/src/services/openai.js deleted file mode 100644 index 3793398..0000000 --- a/backend/src/services/openai.js +++ /dev/null @@ -1,80 +0,0 @@ -const axios = require('axios'); -const config = require('../config'); -const { LocalAIApi } = require('../ai/LocalAIApi'); - -const loadRoleService = () => { - try { - return require('./roles'); - } catch (error) { - console.error('Role service is missing. Advanced roles are required for this operation.', error); - const err = new Error('Role service is missing. Advanced roles are required for this operation.'); - err.originalError = error; - throw err; - } -}; - -module.exports = class OpenAiService { - static async getWidget(payload, userId, roleId) { - const RoleService = loadRoleService(); - const response = await axios.post( - `${config.flHost}/${config.project_uuid}/project_customization_widgets.json`, - payload, - ); - - if (response.status >= 200 && response.status < 300) { - const { widget_id } = await response.data; - await RoleService.addRoleInfo(roleId, userId, 'widgets', widget_id); - return widget_id; - } else { - console.error('=======error=======', response.data); - return { value: null, error: response.data }; - } - } - - static async askGpt(prompt) { - if (!prompt) { - return { - success: false, - error: 'Prompt is required' - }; - } - - const response = await LocalAIApi.createResponse( - { - input: [{ role: 'user', content: prompt }], - }, - { - poll_interval: 5, - poll_timeout: 300, - }, - ); - - if (response.success) { - let text = LocalAIApi.extractText(response); - if (!text) { - try { - const decoded = LocalAIApi.decodeJsonFromResponse(response); - text = JSON.stringify(decoded); - } catch (error) { - console.error('AI JSON decode failed:', error); - return { - success: false, - error: 'AI response parsing failed', - details: error.message || String(error), - }; - } - } - return { - success: true, - data: text, - }; - } - - console.error('AI proxy error:', response); - return { - success: false, - error: response.error || response.message || 'AI proxy error', - response, - }; - } -}; diff --git a/backend/src/services/order_items.js b/backend/src/services/order_items.js deleted file mode 100644 index 9532731..0000000 --- a/backend/src/services/order_items.js +++ /dev/null @@ -1,138 +0,0 @@ -const db = require('../db/models'); -const Order_itemsDBApi = require('../db/api/order_items'); -const processFile = require("../middlewares/upload"); -const ValidationError = require('./notifications/errors/validation'); -const csv = require('csv-parser'); -const axios = require('axios'); -const config = require('../config'); -const stream = require('stream'); - - - - - -module.exports = class Order_itemsService { - static async create(data, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - await Order_itemsDBApi.create( - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async bulkImport(req, res, sendInvitationEmails = true, host) { - const transaction = await db.sequelize.transaction(); - - try { - await processFile(req, res); - const bufferStream = new stream.PassThrough(); - const results = []; - - await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream - - await new Promise((resolve, reject) => { - bufferStream - .pipe(csv()) - .on('data', (data) => results.push(data)) - .on('end', async () => { - console.log('CSV results', results); - resolve(); - }) - .on('error', (error) => reject(error)); - }) - - await Order_itemsDBApi.bulkImport(results, { - transaction, - ignoreDuplicates: true, - validate: true, - currentUser: req.currentUser - }); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - static async update(data, id, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - let order_items = await Order_itemsDBApi.findBy( - {id}, - {transaction}, - ); - - if (!order_items) { - throw new ValidationError( - 'order_itemsNotFound', - ); - } - - const updatedOrder_items = await Order_itemsDBApi.update( - id, - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - return updatedOrder_items; - - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async deleteByIds(ids, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await Order_itemsDBApi.deleteByIds(ids, { - currentUser, - transaction, - }); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - static async remove(id, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await Order_itemsDBApi.remove( - id, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - -}; - - diff --git a/backend/src/services/orders.js b/backend/src/services/orders.js deleted file mode 100644 index 2cac58d..0000000 --- a/backend/src/services/orders.js +++ /dev/null @@ -1,138 +0,0 @@ -const db = require('../db/models'); -const OrdersDBApi = require('../db/api/orders'); -const processFile = require("../middlewares/upload"); -const ValidationError = require('./notifications/errors/validation'); -const csv = require('csv-parser'); -const axios = require('axios'); -const config = require('../config'); -const stream = require('stream'); - - - - - -module.exports = class OrdersService { - static async create(data, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - await OrdersDBApi.create( - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async bulkImport(req, res, sendInvitationEmails = true, host) { - const transaction = await db.sequelize.transaction(); - - try { - await processFile(req, res); - const bufferStream = new stream.PassThrough(); - const results = []; - - await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream - - await new Promise((resolve, reject) => { - bufferStream - .pipe(csv()) - .on('data', (data) => results.push(data)) - .on('end', async () => { - console.log('CSV results', results); - resolve(); - }) - .on('error', (error) => reject(error)); - }) - - await OrdersDBApi.bulkImport(results, { - transaction, - ignoreDuplicates: true, - validate: true, - currentUser: req.currentUser - }); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - static async update(data, id, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - let orders = await OrdersDBApi.findBy( - {id}, - {transaction}, - ); - - if (!orders) { - throw new ValidationError( - 'ordersNotFound', - ); - } - - const updatedOrders = await OrdersDBApi.update( - id, - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - return updatedOrders; - - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async deleteByIds(ids, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await OrdersDBApi.deleteByIds(ids, { - currentUser, - transaction, - }); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - static async remove(id, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await OrdersDBApi.remove( - id, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - -}; - - diff --git a/backend/src/services/payments.js b/backend/src/services/payments.js deleted file mode 100644 index ef655fe..0000000 --- a/backend/src/services/payments.js +++ /dev/null @@ -1,138 +0,0 @@ -const db = require('../db/models'); -const PaymentsDBApi = require('../db/api/payments'); -const processFile = require("../middlewares/upload"); -const ValidationError = require('./notifications/errors/validation'); -const csv = require('csv-parser'); -const axios = require('axios'); -const config = require('../config'); -const stream = require('stream'); - - - - - -module.exports = class PaymentsService { - static async create(data, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - await PaymentsDBApi.create( - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async bulkImport(req, res, sendInvitationEmails = true, host) { - const transaction = await db.sequelize.transaction(); - - try { - await processFile(req, res); - const bufferStream = new stream.PassThrough(); - const results = []; - - await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream - - await new Promise((resolve, reject) => { - bufferStream - .pipe(csv()) - .on('data', (data) => results.push(data)) - .on('end', async () => { - console.log('CSV results', results); - resolve(); - }) - .on('error', (error) => reject(error)); - }) - - await PaymentsDBApi.bulkImport(results, { - transaction, - ignoreDuplicates: true, - validate: true, - currentUser: req.currentUser - }); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - static async update(data, id, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - let payments = await PaymentsDBApi.findBy( - {id}, - {transaction}, - ); - - if (!payments) { - throw new ValidationError( - 'paymentsNotFound', - ); - } - - const updatedPayments = await PaymentsDBApi.update( - id, - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - return updatedPayments; - - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async deleteByIds(ids, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await PaymentsDBApi.deleteByIds(ids, { - currentUser, - transaction, - }); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - static async remove(id, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await PaymentsDBApi.remove( - id, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - -}; - - diff --git a/backend/src/services/permissions.js b/backend/src/services/permissions.js deleted file mode 100644 index e505d0c..0000000 --- a/backend/src/services/permissions.js +++ /dev/null @@ -1,138 +0,0 @@ -const db = require('../db/models'); -const PermissionsDBApi = require('../db/api/permissions'); -const processFile = require("../middlewares/upload"); -const ValidationError = require('./notifications/errors/validation'); -const csv = require('csv-parser'); -const axios = require('axios'); -const config = require('../config'); -const stream = require('stream'); - - - - - -module.exports = class PermissionsService { - static async create(data, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - await PermissionsDBApi.create( - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async bulkImport(req, res, sendInvitationEmails = true, host) { - const transaction = await db.sequelize.transaction(); - - try { - await processFile(req, res); - const bufferStream = new stream.PassThrough(); - const results = []; - - await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream - - await new Promise((resolve, reject) => { - bufferStream - .pipe(csv()) - .on('data', (data) => results.push(data)) - .on('end', async () => { - console.log('CSV results', results); - resolve(); - }) - .on('error', (error) => reject(error)); - }) - - await PermissionsDBApi.bulkImport(results, { - transaction, - ignoreDuplicates: true, - validate: true, - currentUser: req.currentUser - }); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - static async update(data, id, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - let permissions = await PermissionsDBApi.findBy( - {id}, - {transaction}, - ); - - if (!permissions) { - throw new ValidationError( - 'permissionsNotFound', - ); - } - - const updatedPermissions = await PermissionsDBApi.update( - id, - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - return updatedPermissions; - - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async deleteByIds(ids, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await PermissionsDBApi.deleteByIds(ids, { - currentUser, - transaction, - }); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - static async remove(id, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await PermissionsDBApi.remove( - id, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - -}; - - diff --git a/backend/src/services/product_categories.js b/backend/src/services/product_categories.js deleted file mode 100644 index 8fe1612..0000000 --- a/backend/src/services/product_categories.js +++ /dev/null @@ -1,138 +0,0 @@ -const db = require('../db/models'); -const Product_categoriesDBApi = require('../db/api/product_categories'); -const processFile = require("../middlewares/upload"); -const ValidationError = require('./notifications/errors/validation'); -const csv = require('csv-parser'); -const axios = require('axios'); -const config = require('../config'); -const stream = require('stream'); - - - - - -module.exports = class Product_categoriesService { - static async create(data, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - await Product_categoriesDBApi.create( - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async bulkImport(req, res, sendInvitationEmails = true, host) { - const transaction = await db.sequelize.transaction(); - - try { - await processFile(req, res); - const bufferStream = new stream.PassThrough(); - const results = []; - - await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream - - await new Promise((resolve, reject) => { - bufferStream - .pipe(csv()) - .on('data', (data) => results.push(data)) - .on('end', async () => { - console.log('CSV results', results); - resolve(); - }) - .on('error', (error) => reject(error)); - }) - - await Product_categoriesDBApi.bulkImport(results, { - transaction, - ignoreDuplicates: true, - validate: true, - currentUser: req.currentUser - }); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - static async update(data, id, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - let product_categories = await Product_categoriesDBApi.findBy( - {id}, - {transaction}, - ); - - if (!product_categories) { - throw new ValidationError( - 'product_categoriesNotFound', - ); - } - - const updatedProduct_categories = await Product_categoriesDBApi.update( - id, - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - return updatedProduct_categories; - - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async deleteByIds(ids, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await Product_categoriesDBApi.deleteByIds(ids, { - currentUser, - transaction, - }); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - static async remove(id, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await Product_categoriesDBApi.remove( - id, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - -}; - - diff --git a/backend/src/services/products.js b/backend/src/services/products.js deleted file mode 100644 index 458d58f..0000000 --- a/backend/src/services/products.js +++ /dev/null @@ -1,138 +0,0 @@ -const db = require('../db/models'); -const ProductsDBApi = require('../db/api/products'); -const processFile = require("../middlewares/upload"); -const ValidationError = require('./notifications/errors/validation'); -const csv = require('csv-parser'); -const axios = require('axios'); -const config = require('../config'); -const stream = require('stream'); - - - - - -module.exports = class ProductsService { - static async create(data, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - await ProductsDBApi.create( - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async bulkImport(req, res, sendInvitationEmails = true, host) { - const transaction = await db.sequelize.transaction(); - - try { - await processFile(req, res); - const bufferStream = new stream.PassThrough(); - const results = []; - - await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream - - await new Promise((resolve, reject) => { - bufferStream - .pipe(csv()) - .on('data', (data) => results.push(data)) - .on('end', async () => { - console.log('CSV results', results); - resolve(); - }) - .on('error', (error) => reject(error)); - }) - - await ProductsDBApi.bulkImport(results, { - transaction, - ignoreDuplicates: true, - validate: true, - currentUser: req.currentUser - }); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - static async update(data, id, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - let products = await ProductsDBApi.findBy( - {id}, - {transaction}, - ); - - if (!products) { - throw new ValidationError( - 'productsNotFound', - ); - } - - const updatedProducts = await ProductsDBApi.update( - id, - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - return updatedProducts; - - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async deleteByIds(ids, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await ProductsDBApi.deleteByIds(ids, { - currentUser, - transaction, - }); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - static async remove(id, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await ProductsDBApi.remove( - id, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - -}; - - diff --git a/backend/src/services/roles.js b/backend/src/services/roles.js deleted file mode 100644 index d2d8595..0000000 --- a/backend/src/services/roles.js +++ /dev/null @@ -1,437 +0,0 @@ -const db = require('../db/models'); -const RolesDBApi = require('../db/api/roles'); -const processFile = require("../middlewares/upload"); -const ValidationError = require('./notifications/errors/validation'); -const csv = require('csv-parser'); -const axios = require('axios'); -const config = require('../config'); -const stream = require('stream'); - - - - -function buildWidgetResult(widget, queryResult, queryString) { - if (queryResult[0] && queryResult[0].length) { - const key = Object.keys(queryResult[0][0])[0]; - const value = widget.widget_type === 'scalar' ? queryResult[0][0][key] : queryResult[0]; - const widgetData = JSON.parse(widget.data); - return { ...widget, ...widgetData, value, query: queryString }; - } else { - return { ...widget, value: [], query: queryString }; - } -} - -async function executeQuery(queryString, currentUser) { - try { - return await db.sequelize.query(queryString, { - replacements: { organizationId: currentUser.organizationId }, - }); - } catch (e) { - console.log(e); - return []; - } -} - -function insertWhereConditions(queryString, whereConditions) { - if (!whereConditions) return queryString; - - const whereIndex = queryString.toLowerCase().indexOf('where'); - const groupByIndex = queryString.toLowerCase().indexOf('group by'); - const insertIndex = whereIndex === -1 - ? (groupByIndex !== -1 ? groupByIndex : queryString.length) - : whereIndex + 5; - - const prefix = queryString.substring(0, insertIndex); - const suffix = queryString.substring(insertIndex); - const conditionString = whereIndex === -1 ? ` WHERE ${whereConditions} ` : ` ${whereConditions} AND `; - - return `${prefix}${conditionString}${suffix}`; -} - -function constructWhereConditions(mainTable, currentUser, replacements) { - const { organizationId, app_role: { globalAccess } } = currentUser; - const tablesWithoutOrgId = ['permissions', 'roles']; - let whereConditions = ''; - - if (!globalAccess && !tablesWithoutOrgId.includes(mainTable)) { - whereConditions += `"${mainTable}"."organizationId" = :organizationId`; - replacements.organizationId = organizationId; - } - - whereConditions += whereConditions ? ' AND ' : ''; - whereConditions += `"${mainTable}"."deletedAt" IS NULL`; - - return whereConditions; -} - -function extractTableName(queryString) { - const tableNameRegex = /FROM\s+("?)([^"\s]+)\1\s*/i; - const match = tableNameRegex.exec(queryString); - return match ? match[2] : null; -} - -function buildQueryString(widget, currentUser) { - let queryString = widget?.query || ''; - const tableName = extractTableName(queryString); - const mainTable = JSON.parse(widget?.data)?.main_table || tableName; - const replacements = {}; - const whereConditions = constructWhereConditions(mainTable, currentUser, replacements); - queryString = insertWhereConditions(queryString, whereConditions); - console.log(queryString, 'queryString'); - return queryString; -} - -async function constructWidgetsResults(widgets, currentUser) { - const widgetsResults = []; - for (const widget of widgets) { - if (!widget) continue; - const queryString = buildQueryString(widget, currentUser); - const queryResult = await executeQuery(queryString, currentUser); - widgetsResults.push(buildWidgetResult(widget, queryResult, queryString)); - } - return widgetsResults; -} - -async function fetchWidgetsData(widgets) { - const widgetPromises = (widgets || []).map(widgetId => - axios.get(`${config.flHost}/${config.project_uuid}/project_customization_widgets/${widgetId}.json`) - ); - const widgetResults = widgetPromises ? await Promise.allSettled(widgetPromises) : []; - return widgetResults - .filter(result => result.status === 'fulfilled') - .map(result => result.value.data); -} - -async function processWidgets(widgets, currentUser) { - const widgetData = await fetchWidgetsData(widgets); - return constructWidgetsResults(widgetData, currentUser); -} - -function parseCustomization(role) { - try { - return JSON.parse(role.role_customization || '{}'); - } catch (e) { - console.log(e); - return {}; - } -} - -async function findRole(roleId, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - const role = roleId - ? await RolesDBApi.findBy({ id: roleId }, { transaction }) - : await RolesDBApi.findBy({ name: 'User' }, { transaction }); - await transaction.commit(); - return role; - } catch (error) { - await transaction.rollback(); - throw error; - } -} - - -module.exports = class RolesService { - static async create(data, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - await RolesDBApi.create( - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async bulkImport(req, res, sendInvitationEmails = true, host) { - const transaction = await db.sequelize.transaction(); - - try { - await processFile(req, res); - const bufferStream = new stream.PassThrough(); - const results = []; - - await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream - - await new Promise((resolve, reject) => { - bufferStream - .pipe(csv()) - .on('data', (data) => results.push(data)) - .on('end', async () => { - console.log('CSV results', results); - resolve(); - }) - .on('error', (error) => reject(error)); - }) - - await RolesDBApi.bulkImport(results, { - transaction, - ignoreDuplicates: true, - validate: true, - currentUser: req.currentUser - }); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - static async update(data, id, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - let roles = await RolesDBApi.findBy( - {id}, - {transaction}, - ); - - if (!roles) { - throw new ValidationError( - 'rolesNotFound', - ); - } - - const updatedRoles = await RolesDBApi.update( - id, - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - return updatedRoles; - - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async deleteByIds(ids, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await RolesDBApi.deleteByIds(ids, { - currentUser, - transaction, - }); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - static async remove(id, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await RolesDBApi.remove( - id, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - - static async addRoleInfo(roleId, userId, key, widgetId, currentUser) { - const regexExpForUuid = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/gi; - const widgetIdIsUUID = regexExpForUuid.test(widgetId); - - const transaction = await db.sequelize.transaction(); - let role; - if (roleId) { - role = await RolesDBApi.findBy({ id: roleId }, { transaction }); - } else { - role = await RolesDBApi.findBy({ name: 'User' }, { transaction }); - } - - if (!role) { - throw new ValidationError('rolesNotFound'); - } - - try { - let customization = {}; - try { - customization = JSON.parse(role.role_customization || '{}'); - } catch (e) { - console.log(e); - } - - if (widgetIdIsUUID && Array.isArray(customization[key])) { - const el = customization[key].find((e) => e === widgetId); - !el ? customization[key].unshift(widgetId) : null; - } - - if (widgetIdIsUUID && !customization[key]) { - customization[key] = [widgetId]; - } - - const newRole = await RolesDBApi.update( - role.id, - { - role_customization: JSON.stringify(customization), - name: role.name, - permissions: role.permissions, - - }, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - - return newRole; - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - static async removeRoleInfoById(infoId, roleId, key, currentUser) { - const transaction = await db.sequelize.transaction(); - - let role; - if (roleId) { - role = await RolesDBApi.findBy({ id: roleId }, { transaction }); - } else { - role = await RolesDBApi.findBy({ name: 'User' }, { transaction }); - } - if (!role) { - await transaction.rollback(); - throw new ValidationError('rolesNotFound'); - } - - let customization = {}; - try { - customization = JSON.parse(role.role_customization || '{}'); - } catch (e) { - console.log(e); - } - - customization[key] = customization[key].filter( - (item) => item !== infoId, - ); - - const response = await axios.delete(`${config.flHost}/${config.project_uuid}/project_customization_widgets/${infoId}.json`); - const { status } = await response; - try { - const result = await RolesDBApi.update( - role.id, - { - role_customization: JSON.stringify(customization), - name: role.name, - permissions: role.permissions, - - }, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - return result; - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - static async getRoleInfoByKey(key, roleId, currentUser) { - const transaction = await db.sequelize.transaction(); - - const organizationId = currentUser.organizationId; - let globalAccess = currentUser.app_role?.globalAccess; - let queryString = ''; - - - let role; - try { - if (roleId) { - role = await RolesDBApi.findBy({ id: roleId }, { transaction }); - } else { - role = await RolesDBApi.findBy({ name: 'User' }, { transaction }); - } - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - - let customization = '{}'; - - try { - customization = JSON.parse(role.role_customization || '{}'); - } catch (e) { - console.log(e); - } - - if (key === 'widgets') { - const widgets = (customization[key] || []); - const widgetArray = widgets.map(widget => { - return axios.get(`${config.flHost}/${config.project_uuid}/project_customization_widgets/${widget}.json`) - }) - const widgetResults = await Promise.allSettled(widgetArray); - - const fulfilledWidgets = widgetResults.map(result => { - if (result.status === 'fulfilled') { - return result.value.data; - } - }); - - const widgetsResults = []; - - if (Array.isArray(fulfilledWidgets)) { - for (const widget of fulfilledWidgets) { - let result = []; - try { - result = await db.sequelize.query(widget.query); - } catch (e) { - console.log(e); - } - - if (result[0] && result[0].length) { - const key = Object.keys(result[0][0])[0]; - const value = - widget.widget_type === 'scalar' ? result[0][0][key] : result[0]; - const widgetData = JSON.parse(widget.data); - widgetsResults.push({ ...widget, ...widgetData, value }); - } else { - widgetsResults.push({ ...widget, value: null }); - } - } - } - return widgetsResults; - } - return customization[key]; - - - } - - -}; - - diff --git a/backend/src/services/search.js b/backend/src/services/search.js deleted file mode 100644 index 50cb77e..0000000 --- a/backend/src/services/search.js +++ /dev/null @@ -1,363 +0,0 @@ -const db = require('../db/models'); -const ValidationError = require('./notifications/errors/validation'); - -const Sequelize = db.Sequelize; -const Op = Sequelize.Op; - -/** - * @param {string} permission - * @param {object} currentUser - */ -async function checkPermissions(permission, currentUser) { - - if (!currentUser) { - throw new ValidationError('auth.unauthorized'); - } - - const userPermission = currentUser.custom_permissions.find( - (cp) => cp.name === permission, - ); - - if (userPermission) { - return true; - } - - try { - if (!currentUser.app_role) { - throw new ValidationError('auth.forbidden'); - } - - const permissions = await currentUser.app_role.getPermissions(); - - return !!permissions.find((p) => p.name === permission); - } catch (e) { - throw e; - } -} - -module.exports = class SearchService { - static async search(searchQuery, currentUser ) { - try { - if (!searchQuery) { - throw new ValidationError('iam.errors.searchQueryRequired'); - } - const tableColumns = { - - - - - - "users": [ - - "firstName", - - "lastName", - - "phoneNumber", - - "email", - - ], - - - - - - - - - "customers": [ - - "customer_code", - - "full_name", - - "email", - - "phone", - - "billing_address", - - "shipping_address", - - "notes", - - ], - - - - - - - "product_categories": [ - - "name", - - "slug", - - "description", - - ], - - - - - - - "products": [ - - "name", - - "sku", - - "barcode", - - "short_description", - - "description", - - ], - - - - - - - "orders": [ - - "order_number", - - "currency", - - "shipping_name", - - "shipping_address", - - "billing_name", - - "billing_address", - - "notes_internal", - - "customer_note", - - "tracking_number", - - "carrier", - - ], - - - - - - - "order_items": [ - - "product_name_snapshot", - - "sku_snapshot", - - ], - - - - - - - "payments": [ - - "payment_reference", - - "currency", - - "provider_transaction_id", - - "failure_reason", - - ], - - - - - - - "shipments": [ - - "shipment_number", - - "carrier", - - "service_level", - - "tracking_number", - - "label_url", - - "notes", - - ], - - - }; - const columnsInt = { - - - - - - - - - - - - - - - - - - - "products": [ - - "price", - - "compare_at_price", - - "cost", - - "stock_on_hand", - - "reorder_point", - - "weight", - - ], - - - - - - "orders": [ - - "subtotal_amount", - - "discount_amount", - - "tax_amount", - - "shipping_amount", - - "total_amount", - - ], - - - - - - "order_items": [ - - "unit_price", - - "quantity", - - "line_discount_amount", - - "line_tax_amount", - - "line_total_amount", - - ], - - - - - - "payments": [ - - "amount", - - ], - - - - - - "shipments": [ - - "shipping_cost", - - ], - - - }; - - let allFoundRecords = []; - - for (const tableName in tableColumns) { - if (tableColumns.hasOwnProperty(tableName)) { - const attributesToSearch = tableColumns[tableName]; - const attributesIntToSearch = columnsInt[tableName] || []; - const whereCondition = { - [Op.or]: [ - ...attributesToSearch.map(attribute => ({ - [attribute]: { - [Op.iLike] : `%${searchQuery}%`, - }, - })), - ...attributesIntToSearch.map(attribute => ( - Sequelize.where( - Sequelize.cast(Sequelize.col(`${tableName}.${attribute}`), 'varchar'), - { [Op.iLike]: `%${searchQuery}%` } - ) - )), - ], - }; - - - - const hasPermission = await checkPermissions(`READ_${tableName.toUpperCase()}`, currentUser); - if (!hasPermission) { - continue; - } - - const foundRecords = await db[tableName].findAll({ - where: whereCondition, - attributes: [...tableColumns[tableName], 'id', ...attributesIntToSearch], - }); - - const modifiedRecords = foundRecords.map((record) => { - const matchAttribute = []; - - for (const attribute of attributesToSearch) { - if (record[attribute]?.toLowerCase()?.includes(searchQuery.toLowerCase())) { - matchAttribute.push(attribute); - } - } - - for (const attribute of attributesIntToSearch) { - const castedValue = String(record[attribute]); - if (castedValue && castedValue.toLowerCase().includes(searchQuery.toLowerCase())) { - matchAttribute.push(attribute); - } - } - - return { - ...record.get(), - matchAttribute, - tableName, - }; - }); - - allFoundRecords = allFoundRecords.concat(modifiedRecords); - } - } - - return allFoundRecords; - } catch (error) { - throw error; - } - } -} \ No newline at end of file diff --git a/backend/src/services/shipments.js b/backend/src/services/shipments.js deleted file mode 100644 index 48ba951..0000000 --- a/backend/src/services/shipments.js +++ /dev/null @@ -1,138 +0,0 @@ -const db = require('../db/models'); -const ShipmentsDBApi = require('../db/api/shipments'); -const processFile = require("../middlewares/upload"); -const ValidationError = require('./notifications/errors/validation'); -const csv = require('csv-parser'); -const axios = require('axios'); -const config = require('../config'); -const stream = require('stream'); - - - - - -module.exports = class ShipmentsService { - static async create(data, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - await ShipmentsDBApi.create( - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async bulkImport(req, res, sendInvitationEmails = true, host) { - const transaction = await db.sequelize.transaction(); - - try { - await processFile(req, res); - const bufferStream = new stream.PassThrough(); - const results = []; - - await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream - - await new Promise((resolve, reject) => { - bufferStream - .pipe(csv()) - .on('data', (data) => results.push(data)) - .on('end', async () => { - console.log('CSV results', results); - resolve(); - }) - .on('error', (error) => reject(error)); - }) - - await ShipmentsDBApi.bulkImport(results, { - transaction, - ignoreDuplicates: true, - validate: true, - currentUser: req.currentUser - }); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - static async update(data, id, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - let shipments = await ShipmentsDBApi.findBy( - {id}, - {transaction}, - ); - - if (!shipments) { - throw new ValidationError( - 'shipmentsNotFound', - ); - } - - const updatedShipments = await ShipmentsDBApi.update( - id, - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - return updatedShipments; - - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async deleteByIds(ids, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await ShipmentsDBApi.deleteByIds(ids, { - currentUser, - transaction, - }); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - static async remove(id, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await ShipmentsDBApi.remove( - id, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - -}; - - diff --git a/backend/src/services/users.js b/backend/src/services/users.js deleted file mode 100644 index 555d193..0000000 --- a/backend/src/services/users.js +++ /dev/null @@ -1,171 +0,0 @@ -const db = require('../db/models'); -const UsersDBApi = require('../db/api/users'); -const processFile = require("../middlewares/upload"); -const ValidationError = require('./notifications/errors/validation'); -const csv = require('csv-parser'); -const axios = require('axios'); -const config = require('../config'); -const stream = require('stream'); - - -const InvitationEmail = require('./email/list/invitation'); -const EmailSender = require('./email'); -const AuthService = require('./auth'); - -module.exports = class UsersService { - static async create(data, currentUser, sendInvitationEmails = true, host) { - let transaction = await db.sequelize.transaction(); - - let email = data.email; - let emailsToInvite = []; - try { - if (email) { - let user = await UsersDBApi.findBy({email}, {transaction}); - if (user) { - throw new ValidationError( - 'iam.errors.userAlreadyExists', - ); - } else { - await UsersDBApi.create( - {data}, - - { - currentUser, - transaction, - }, - ); - emailsToInvite.push(email); - } - } else { - throw new ValidationError('iam.errors.emailRequired') - } - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - if (emailsToInvite && emailsToInvite.length) { - if (!sendInvitationEmails) return; - - AuthService.sendPasswordResetEmail(email, 'invitation', host); - } - } - - static async bulkImport(req, res, sendInvitationEmails = true, host) { - const transaction = await db.sequelize.transaction(); - let emailsToInvite = []; - - try { - await processFile(req, res); - const bufferStream = new stream.PassThrough(); - const results = []; - - await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream - - await new Promise((resolve, reject) => { - bufferStream - .pipe(csv()) - .on('data', (data) => results.push(data)) - .on('end', () => { - console.log('results csv', results); - resolve(); - }) - .on('error', (error) => reject(error)); - }); - - const hasAllEmails = results.every((result) => result.email); - - if (!hasAllEmails) { - throw new ValidationError('importer.errors.userEmailMissing'); - } - - await UsersDBApi.bulkImport(results, { - transaction, - ignoreDuplicates: true, - validate: true, - currentUser: req.currentUser - }); - - emailsToInvite = results.map((result) => result.email); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - - if (emailsToInvite && emailsToInvite.length && !sendInvitationEmails) { - - emailsToInvite.forEach((email) => { - AuthService.sendPasswordResetEmail(email, 'invitation', host); - }); - } - } - - static async update(data, id, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - let users = await UsersDBApi.findBy( - {id}, - {transaction}, - ); - - if (!users) { - throw new ValidationError( - 'iam.errors.userNotFound', - ); - } - - const updatedUser = await UsersDBApi.update( - id, - data, - - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - return updatedUser; - - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async remove(id, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - if (currentUser.id === id) { - throw new ValidationError( - 'iam.errors.deletingHimself', - ); - } - - if (currentUser.app_role?.name !== config.roles.admin ) { - throw new ValidationError( - 'errors.forbidden.message', - ); - } - - await UsersDBApi.remove( - id, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } -}; - - diff --git a/backend/watcher.js b/backend/watcher.js deleted file mode 100644 index 9e5e5bc..0000000 --- a/backend/watcher.js +++ /dev/null @@ -1,49 +0,0 @@ -const chokidar = require('chokidar'); -const { exec } = require('child_process'); -const nodemon = require('nodemon'); - -const nodeEnv = process.env.NODE_ENV || 'dev_stage'; -const childEnv = { ...process.env, NODE_ENV: nodeEnv }; - -const migrationsWatcher = chokidar.watch('./src/db/migrations', { - persistent: true, - ignoreInitial: true -}); -migrationsWatcher.on('add', (filePath) => { - console.log(`[DEBUG] New migration file: ${filePath}`); - exec('npm run db:migrate', { env: childEnv }, (error, stdout, stderr) => { - console.log(stdout); - if (error) { - console.error(stderr); - } - }); -}); - -const seedersWatcher = chokidar.watch('./src/db/seeders', { - persistent: true, - ignoreInitial: true -}); -seedersWatcher.on('add', (filePath) => { - console.log(`[DEBUG] New seed file: ${filePath}`); - exec('npm run db:seed', { env: childEnv }, (error, stdout, stderr) => { - console.log(stdout); - if (error) { - console.error(stderr); - } - }); -}); - -nodemon({ - script: './src/index.js', - env: childEnv, - ignore: ['./src/db/migrations', './src/db/seeders'], - delay: '500' -}); - -nodemon.on('start', () => { - console.log('Nodemon started'); -}); - -nodemon.on('restart', (files) => { - console.log('Nodemon restarted due changes in:', files); -}); diff --git a/backend/yarn.lock b/backend/yarn.lock deleted file mode 100644 index 222a4f9..0000000 --- a/backend/yarn.lock +++ /dev/null @@ -1,4470 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@apidevtools/json-schema-ref-parser@^9.0.6": - version "9.1.2" - resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz#8ff5386b365d4c9faa7c8b566ff16a46a577d9b8" - integrity sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg== - dependencies: - "@jsdevtools/ono" "^7.1.3" - "@types/json-schema" "^7.0.6" - call-me-maybe "^1.0.1" - js-yaml "^4.1.0" - -"@apidevtools/openapi-schemas@^2.0.4": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz#9fa08017fb59d80538812f03fc7cac5992caaa17" - integrity sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ== - -"@apidevtools/swagger-methods@^3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz#b789a362e055b0340d04712eafe7027ddc1ac267" - integrity sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg== - -"@apidevtools/swagger-parser@10.0.3": - version "10.0.3" - resolved "https://registry.yarnpkg.com/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz#32057ae99487872c4dd96b314a1ab4b95d89eaf5" - integrity sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g== - dependencies: - "@apidevtools/json-schema-ref-parser" "^9.0.6" - "@apidevtools/openapi-schemas" "^2.0.4" - "@apidevtools/swagger-methods" "^3.0.2" - "@jsdevtools/ono" "^7.1.3" - call-me-maybe "^1.0.1" - z-schema "^5.0.1" - -"@azure/abort-controller@^1.0.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-1.1.0.tgz#788ee78457a55af8a1ad342acb182383d2119249" - integrity sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw== - dependencies: - tslib "^2.2.0" - -"@azure/abort-controller@^2.0.0": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-2.1.2.tgz#42fe0ccab23841d9905812c58f1082d27784566d" - integrity sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA== - dependencies: - tslib "^2.6.2" - -"@azure/core-auth@^1.3.0", "@azure/core-auth@^1.4.0", "@azure/core-auth@^1.5.0": - version "1.7.2" - resolved "https://registry.yarnpkg.com/@azure/core-auth/-/core-auth-1.7.2.tgz#558b7cb7dd12b00beec07ae5df5907d74df1ebd9" - integrity sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g== - dependencies: - "@azure/abort-controller" "^2.0.0" - "@azure/core-util" "^1.1.0" - tslib "^2.6.2" - -"@azure/core-client@^1.3.0", "@azure/core-client@^1.5.0", "@azure/core-client@^1.9.2": - version "1.9.2" - resolved "https://registry.yarnpkg.com/@azure/core-client/-/core-client-1.9.2.tgz#6fc69cee2816883ab6c5cdd653ee4f2ff9774f74" - integrity sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w== - dependencies: - "@azure/abort-controller" "^2.0.0" - "@azure/core-auth" "^1.4.0" - "@azure/core-rest-pipeline" "^1.9.1" - "@azure/core-tracing" "^1.0.0" - "@azure/core-util" "^1.6.1" - "@azure/logger" "^1.0.0" - tslib "^2.6.2" - -"@azure/core-http-compat@^2.0.1": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@azure/core-http-compat/-/core-http-compat-2.1.2.tgz#d1585ada24ba750dc161d816169b33b35f762f0d" - integrity sha512-5MnV1yqzZwgNLLjlizsU3QqOeQChkIXw781Fwh1xdAqJR5AA32IUaq6xv1BICJvfbHoa+JYcaij2HFkhLbNTJQ== - dependencies: - "@azure/abort-controller" "^2.0.0" - "@azure/core-client" "^1.3.0" - "@azure/core-rest-pipeline" "^1.3.0" - -"@azure/core-lro@^2.2.0": - version "2.7.2" - resolved "https://registry.yarnpkg.com/@azure/core-lro/-/core-lro-2.7.2.tgz#787105027a20e45c77651a98b01a4d3b01b75a08" - integrity sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw== - dependencies: - "@azure/abort-controller" "^2.0.0" - "@azure/core-util" "^1.2.0" - "@azure/logger" "^1.0.0" - tslib "^2.6.2" - -"@azure/core-paging@^1.1.1": - version "1.6.2" - resolved "https://registry.yarnpkg.com/@azure/core-paging/-/core-paging-1.6.2.tgz#40d3860dc2df7f291d66350b2cfd9171526433e7" - integrity sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA== - dependencies: - tslib "^2.6.2" - -"@azure/core-rest-pipeline@^1.1.0", "@azure/core-rest-pipeline@^1.3.0", "@azure/core-rest-pipeline@^1.8.1", "@azure/core-rest-pipeline@^1.9.1": - version "1.16.2" - resolved "https://registry.yarnpkg.com/@azure/core-rest-pipeline/-/core-rest-pipeline-1.16.2.tgz#3f71b09e45a65926cc598478b4f1bcd0fe67bf4b" - integrity sha512-Hnhm/PG9/SQ07JJyLDv3l9Qr8V3xgAe1hFoBYzt6LaalMxfL/ZqFaZf/bz5VN3pMcleCPwl8ivlS2Fjxq/iC8Q== - dependencies: - "@azure/abort-controller" "^2.0.0" - "@azure/core-auth" "^1.4.0" - "@azure/core-tracing" "^1.0.1" - "@azure/core-util" "^1.9.0" - "@azure/logger" "^1.0.0" - http-proxy-agent "^7.0.0" - https-proxy-agent "^7.0.0" - tslib "^2.6.2" - -"@azure/core-tracing@^1.0.0", "@azure/core-tracing@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@azure/core-tracing/-/core-tracing-1.1.2.tgz#065dab4e093fb61899988a1cdbc827d9ad90b4ee" - integrity sha512-dawW9ifvWAWmUm9/h+/UQ2jrdvjCJ7VJEuCJ6XVNudzcOwm53BFZH4Q845vjfgoUAM8ZxokvVNxNxAITc502YA== - dependencies: - tslib "^2.6.2" - -"@azure/core-util@^1.0.0", "@azure/core-util@^1.1.0", "@azure/core-util@^1.2.0", "@azure/core-util@^1.3.0", "@azure/core-util@^1.6.1", "@azure/core-util@^1.9.0": - version "1.9.1" - resolved "https://registry.yarnpkg.com/@azure/core-util/-/core-util-1.9.1.tgz#05ea9505c5cdf29c55ccf99a648c66ddd678590b" - integrity sha512-OLsq0etbHO1MA7j6FouXFghuHrAFGk+5C1imcpQ2e+0oZhYF07WLA+NW2Vqs70R7d+zOAWiWM3tbE1sXcDN66g== - dependencies: - "@azure/abort-controller" "^2.0.0" - tslib "^2.6.2" - -"@azure/identity@^4.2.1": - version "4.4.0" - resolved "https://registry.yarnpkg.com/@azure/identity/-/identity-4.4.0.tgz#f2743e63d346000a70b0eed5a3b397dedd3984a7" - integrity sha512-oG6oFNMxUuoivYg/ElyZWVSZfw42JQyHbrp+lR7VJ1BYWsGzt34NwyDw3miPp1QI7Qm5+4KAd76wGsbHQmkpkg== - dependencies: - "@azure/abort-controller" "^1.0.0" - "@azure/core-auth" "^1.5.0" - "@azure/core-client" "^1.9.2" - "@azure/core-rest-pipeline" "^1.1.0" - "@azure/core-tracing" "^1.0.0" - "@azure/core-util" "^1.3.0" - "@azure/logger" "^1.0.0" - "@azure/msal-browser" "^3.14.0" - "@azure/msal-node" "^2.9.2" - events "^3.0.0" - jws "^4.0.0" - open "^8.0.0" - stoppable "^1.1.0" - tslib "^2.2.0" - -"@azure/keyvault-keys@^4.4.0": - version "4.8.0" - resolved "https://registry.yarnpkg.com/@azure/keyvault-keys/-/keyvault-keys-4.8.0.tgz#1513b3a187bb3a9a372b5980c593962fb793b2ad" - integrity sha512-jkuYxgkw0aaRfk40OQhFqDIupqblIOIlYESWB6DKCVDxQet1pyv86Tfk9M+5uFM0+mCs6+MUHU+Hxh3joiUn4Q== - dependencies: - "@azure/abort-controller" "^1.0.0" - "@azure/core-auth" "^1.3.0" - "@azure/core-client" "^1.5.0" - "@azure/core-http-compat" "^2.0.1" - "@azure/core-lro" "^2.2.0" - "@azure/core-paging" "^1.1.1" - "@azure/core-rest-pipeline" "^1.8.1" - "@azure/core-tracing" "^1.0.0" - "@azure/core-util" "^1.0.0" - "@azure/logger" "^1.0.0" - tslib "^2.2.0" - -"@azure/logger@^1.0.0": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@azure/logger/-/logger-1.1.3.tgz#09a8fd4850b9112865756e92d5e8b728ee457345" - integrity sha512-J8/cIKNQB1Fc9fuYqBVnrppiUtW+5WWJPCj/tAokC5LdSTwkWWttN+jsRgw9BLYD7JDBx7PceiqOBxJJ1tQz3Q== - dependencies: - tslib "^2.6.2" - -"@azure/msal-browser@^3.14.0": - version "3.19.1" - resolved "https://registry.yarnpkg.com/@azure/msal-browser/-/msal-browser-3.19.1.tgz#c5e5a7996f95cadc11920bffa2bf6321e3a24555" - integrity sha512-pqYP2gK0GCEa4OxtOqlS+EdFQqhXV6ZuESgSTYWq2ABXyxBVVdd5KNuqgR5SU0OwI2V1YWdFVvLDe1487dyQ0g== - dependencies: - "@azure/msal-common" "14.13.1" - -"@azure/msal-common@14.13.1": - version "14.13.1" - resolved "https://registry.yarnpkg.com/@azure/msal-common/-/msal-common-14.13.1.tgz#e296cf8cc556082af9c35d803496424e8a95d8b7" - integrity sha512-iUp3BYrsRZ4X3EiaZ2fDjNFjmtYMv9rEQd6c1op6ULn0HWk4ACvDmosL6NaBgWOhl1BAblIbd9vmB5/ilF8d4A== - -"@azure/msal-node@^2.9.2": - version "2.11.1" - resolved "https://registry.yarnpkg.com/@azure/msal-node/-/msal-node-2.11.1.tgz#7fea67a1c6904301eb8853fae7df86c34306a9cc" - integrity sha512-8ECtug4RL+zsgh20VL8KYHjrRO3MJOeAKEPRXT2lwtiu5U3BdyIdBb50+QZthEkIi60K6pc/pdOx/k5Jp4sLng== - dependencies: - "@azure/msal-common" "14.13.1" - jsonwebtoken "^9.0.0" - uuid "^8.3.0" - -"@google-cloud/paginator@^3.0.7": - version "3.0.7" - resolved "https://registry.yarnpkg.com/@google-cloud/paginator/-/paginator-3.0.7.tgz#fb6f8e24ec841f99defaebf62c75c2e744dd419b" - integrity sha512-jJNutk0arIQhmpUUQJPJErsojqo834KcyB6X7a1mxuic8i1tKXxde8E69IZxNZawRIlZdIK2QY4WALvlK5MzYQ== - dependencies: - arrify "^2.0.0" - extend "^3.0.2" - -"@google-cloud/projectify@^2.0.0": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@google-cloud/projectify/-/projectify-2.1.1.tgz#ae6af4fee02d78d044ae434699a630f8df0084ef" - integrity sha512-+rssMZHnlh0twl122gXY4/aCrk0G1acBqkHFfYddtsqpYXGxA29nj9V5V9SfC+GyOG00l650f6lG9KL+EpFEWQ== - -"@google-cloud/promisify@^2.0.0": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@google-cloud/promisify/-/promisify-2.0.4.tgz#9d8705ecb2baa41b6b2673f3a8e9b7b7e1abc52a" - integrity sha512-j8yRSSqswWi1QqUGKVEKOG03Q7qOoZP6/h2zN2YO+F5h2+DHU0bSrHCK9Y7lo2DI9fBd8qGAw795sf+3Jva4yA== - -"@google-cloud/storage@^5.18.2": - version "5.20.5" - resolved "https://registry.yarnpkg.com/@google-cloud/storage/-/storage-5.20.5.tgz#1de71fc88d37934a886bc815722c134b162d335d" - integrity sha512-lOs/dCyveVF8TkVFnFSF7IGd0CJrTm91qiK6JLu+Z8qiT+7Ag0RyVhxZIWkhiACqwABo7kSHDm8FdH8p2wxSSw== - dependencies: - "@google-cloud/paginator" "^3.0.7" - "@google-cloud/projectify" "^2.0.0" - "@google-cloud/promisify" "^2.0.0" - abort-controller "^3.0.0" - arrify "^2.0.0" - async-retry "^1.3.3" - compressible "^2.0.12" - configstore "^5.0.0" - duplexify "^4.0.0" - ent "^2.2.0" - extend "^3.0.2" - gaxios "^4.0.0" - google-auth-library "^7.14.1" - hash-stream-validation "^0.2.2" - mime "^3.0.0" - mime-types "^2.0.8" - p-limit "^3.0.1" - pumpify "^2.0.0" - retry-request "^4.2.2" - stream-events "^1.0.4" - teeny-request "^7.1.3" - uuid "^8.0.0" - xdg-basedir "^4.0.0" - -"@isaacs/cliui@^8.0.2": - version "8.0.2" - resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" - integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== - dependencies: - string-width "^5.1.2" - string-width-cjs "npm:string-width@^4.2.0" - strip-ansi "^7.0.1" - strip-ansi-cjs "npm:strip-ansi@^6.0.1" - wrap-ansi "^8.1.0" - wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" - -"@js-joda/core@^5.6.1": - version "5.6.3" - resolved "https://registry.yarnpkg.com/@js-joda/core/-/core-5.6.3.tgz#41ae1c07de1ebe0f6dde1abcbc9700a09b9c6056" - integrity sha512-T1rRxzdqkEXcou0ZprN1q9yDRlvzCPLqmlNt5IIsGBzoEVgLCCYrKEwc84+TvsXuAc95VAZwtWD2zVsKPY4bcA== - -"@jsdevtools/ono@^7.1.3": - version "7.1.3" - resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796" - integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg== - -"@mapbox/node-pre-gyp@^1.0.11": - version "1.0.11" - resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz#417db42b7f5323d79e93b34a6d7a2a12c0df43fa" - integrity sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ== - dependencies: - detect-libc "^2.0.0" - https-proxy-agent "^5.0.0" - make-dir "^3.1.0" - node-fetch "^2.6.7" - nopt "^5.0.0" - npmlog "^5.0.1" - rimraf "^3.0.2" - semver "^7.3.5" - tar "^6.1.11" - -"@one-ini/wasm@0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@one-ini/wasm/-/wasm-0.1.1.tgz#6013659736c9dbfccc96e8a9c2b3de317df39323" - integrity sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw== - -"@pkgjs/parseargs@^0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" - integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== - -"@sindresorhus/is@^0.14.0": - version "0.14.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" - integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== - -"@szmarczak/http-timer@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" - integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== - dependencies: - defer-to-connect "^1.0.1" - -"@tootallnate/once@2": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" - integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== - -"@types/debug@^4.1.8": - version "4.1.12" - resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917" - integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ== - dependencies: - "@types/ms" "*" - -"@types/json-schema@^7.0.6": - version "7.0.15" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" - integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== - -"@types/ms@*": - version "0.7.34" - resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433" - integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== - -"@types/node@*", "@types/node@>=18": - version "20.14.11" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.11.tgz#09b300423343460455043ddd4d0ded6ac579b74b" - integrity sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA== - dependencies: - undici-types "~5.26.4" - -"@types/readable-stream@^4.0.0": - version "4.0.15" - resolved "https://registry.yarnpkg.com/@types/readable-stream/-/readable-stream-4.0.15.tgz#e6ec26fe5b02f578c60baf1fa9452e90957d2bfb" - integrity sha512-oAZ3kw+kJFkEqyh7xORZOku1YAKvsFTogRY8kVl4vHpEKiDkfnSA/My8haRE7fvmix5Zyy+1pwzOi7yycGLBJw== - dependencies: - "@types/node" "*" - safe-buffer "~5.1.1" - -"@types/validator@^13.7.17": - version "13.12.0" - resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.12.0.tgz#1fe4c3ae9de5cf5193ce64717c99ef2fa7d8756f" - integrity sha512-nH45Lk7oPIJ1RVOF6JgFI6Dy0QpHEzq4QecZhvguxYPDwT8c93prCMqAtiIttm39voZ+DDR+qkNnMpJmMBRqag== - -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - -abbrev@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf" - integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ== - -abort-controller@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" - integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== - dependencies: - event-target-shim "^5.0.0" - -accepts@^1.3.7, accepts@~1.3.8: - version "1.3.8" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== - dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" - -agent-base@6: - version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== - dependencies: - debug "4" - -agent-base@^7.0.2, agent-base@^7.1.0: - version "7.1.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317" - integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== - dependencies: - debug "^4.3.4" - -ansi-align@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" - integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w== - dependencies: - string-width "^4.1.0" - -ansi-colors@4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - -ansi-regex@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" - integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== - -ansi-regex@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" - integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-regex@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" - integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== - -ansi-styles@^3.2.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-styles@^6.1.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" - integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== - -anymatch@~3.1.1, anymatch@~3.1.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" - integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -append-field@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56" - integrity sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw== - -"aproba@^1.0.3 || ^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" - integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== - -are-we-there-yet@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" - integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== - dependencies: - delegates "^1.0.0" - readable-stream "^3.6.0" - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -array-buffer-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" - integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== - dependencies: - call-bind "^1.0.5" - is-array-buffer "^3.0.4" - -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== - -array.prototype.map@^1.0.1: - version "1.0.7" - resolved "https://registry.yarnpkg.com/array.prototype.map/-/array.prototype.map-1.0.7.tgz#82fa4d6027272d1fca28a63bbda424d0185d78a7" - integrity sha512-XpcFfLoBEAhezrrNw1V+yLXkE7M6uR7xJEsxbG6c/V9v043qurwVJB9r9UTnoSioFDoz1i1VOydpWGmJpfVZbg== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.2" - es-array-method-boxes-properly "^1.0.0" - es-object-atoms "^1.0.0" - is-string "^1.0.7" - -arraybuffer.prototype.slice@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" - integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== - dependencies: - array-buffer-byte-length "^1.0.1" - call-bind "^1.0.5" - define-properties "^1.2.1" - es-abstract "^1.22.3" - es-errors "^1.2.1" - get-intrinsic "^1.2.3" - is-array-buffer "^3.0.4" - is-shared-array-buffer "^1.0.2" - -arrify@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" - integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== - -async-retry@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" - integrity sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw== - dependencies: - retry "0.13.1" - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== - -at-least-node@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" - integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== - -available-typed-arrays@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" - integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== - dependencies: - possible-typed-array-names "^1.0.0" - -axios@^1.6.7: - version "1.7.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.2.tgz#b625db8a7051fbea61c35a3cbb3a1daa7b9c7621" - integrity sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw== - dependencies: - follow-redirects "^1.15.6" - form-data "^4.0.0" - proxy-from-env "^1.1.0" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -base64-js@^1.3.0, base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -base64url@3.x.x: - version "3.0.1" - resolved "https://registry.yarnpkg.com/base64url/-/base64url-3.0.1.tgz#6399d572e2bc3f90a9a8b22d5dbb0a32d33f788d" - integrity sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A== - -bcrypt@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-5.1.1.tgz#0f732c6dcb4e12e5b70a25e326a72965879ba6e2" - integrity sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww== - dependencies: - "@mapbox/node-pre-gyp" "^1.0.11" - node-addon-api "^5.0.0" - -bignumber.js@^9.0.0: - version "9.1.2" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" - integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== - -binary-extensions@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" - integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== - -bl@^6.0.11: - version "6.0.14" - resolved "https://registry.yarnpkg.com/bl/-/bl-6.0.14.tgz#b9ae9862118a3d2ebec999c5318466012314f96c" - integrity sha512-TJfbvGdL7KFGxTsEbsED7avqpFdY56q9IW0/aiytyheJzxST/+Io6cx/4Qx0K2/u0BPRDs65mjaQzYvMZeNocQ== - dependencies: - "@types/readable-stream" "^4.0.0" - buffer "^6.0.3" - inherits "^2.0.4" - readable-stream "^4.2.0" - -bluebird@^3.7.2: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - -body-parser@1.20.1: - version "1.20.1" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" - integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== - dependencies: - bytes "3.1.2" - content-type "~1.0.4" - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - http-errors "2.0.0" - iconv-lite "0.4.24" - on-finished "2.4.1" - qs "6.11.0" - raw-body "2.5.1" - type-is "~1.6.18" - unpipe "1.0.0" - -boxen@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64" - integrity sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ== - dependencies: - ansi-align "^3.0.0" - camelcase "^5.3.1" - chalk "^3.0.0" - cli-boxes "^2.2.0" - string-width "^4.1.0" - term-size "^2.1.0" - type-fest "^0.8.1" - widest-line "^3.1.0" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== - dependencies: - balanced-match "^1.0.0" - -braces@~3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" - integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== - dependencies: - fill-range "^7.1.1" - -browser-stdout@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" - integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== - -buffer-equal-constant-time@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" - integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== - -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -buffer-writer@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" - integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw== - -buffer@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - -busboy@^0.2.11: - version "0.2.14" - resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453" - integrity sha512-InWFDomvlkEj+xWLBfU3AvnbVYqeTWmQopiW0tWWEy5yehYm2YkGEc59sUmw/4ty5Zj/b0WHGs1LgecuBSBGrg== - dependencies: - dicer "0.2.5" - readable-stream "1.1.x" - -bytes@3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" - integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== - -cacheable-request@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" - integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== - dependencies: - clone-response "^1.0.2" - get-stream "^5.1.0" - http-cache-semantics "^4.0.0" - keyv "^3.0.0" - lowercase-keys "^2.0.0" - normalize-url "^4.1.0" - responselike "^1.0.2" - -call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" - integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== - dependencies: - es-define-property "^1.0.0" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.4" - set-function-length "^1.2.1" - -call-me-maybe@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.2.tgz#03f964f19522ba643b1b0693acb9152fe2074baa" - integrity sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ== - -camelcase@^5.0.0, camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -chalk@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" - integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chalk@^4.0.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chokidar@3.4.2: - version "3.4.2" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.2.tgz#38dc8e658dec3809741eb3ef7bb0a47fe424232d" - integrity sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A== - dependencies: - anymatch "~3.1.1" - braces "~3.0.2" - glob-parent "~5.1.0" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.4.0" - optionalDependencies: - fsevents "~2.1.2" - -chokidar@^3.2.2: - version "3.6.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" - integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -chownr@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" - integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== - -ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" - integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== - -cli-boxes@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" - integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== - -cli-color@^2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/cli-color/-/cli-color-2.0.4.tgz#d658080290968816b322248b7306fad2346fb2c8" - integrity sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA== - dependencies: - d "^1.0.1" - es5-ext "^0.10.64" - es6-iterator "^2.0.3" - memoizee "^0.4.15" - timers-ext "^0.1.7" - -cliui@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" - integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== - dependencies: - string-width "^3.1.0" - strip-ansi "^5.2.0" - wrap-ansi "^5.1.0" - -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - -clone-response@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3" - integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA== - dependencies: - mimic-response "^1.0.0" - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -color-support@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" - integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== - -combined-stream@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -commander@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.0.tgz#b990bfb8ac030aedc6d11bc04d1488ffef56db75" - integrity sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q== - -commander@^10.0.0: - version "10.0.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" - integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== - -commander@^6.1.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" - integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== - -compressible@^2.0.12: - version "2.0.18" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" - integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== - dependencies: - mime-db ">= 1.43.0 < 2" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -concat-stream@^1.5.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -config-chain@^1.1.13: - version "1.1.13" - resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" - integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== - dependencies: - ini "^1.3.4" - proto-list "~1.2.1" - -configstore@^5.0.0, configstore@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" - integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== - dependencies: - dot-prop "^5.2.0" - graceful-fs "^4.1.2" - make-dir "^3.0.0" - unique-string "^2.0.0" - write-file-atomic "^3.0.0" - xdg-basedir "^4.0.0" - -console-control-strings@^1.0.0, console-control-strings@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== - -content-disposition@0.5.4: - version "0.5.4" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" - integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== - dependencies: - safe-buffer "5.2.1" - -content-type@~1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" - integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== - -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== - -cookie@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" - integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== - -core-util-is@~1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" - integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== - -cors@2.8.5: - version "2.8.5" - resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" - integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== - dependencies: - object-assign "^4" - vary "^1" - -cross-env@7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf" - integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw== - dependencies: - cross-spawn "^7.0.1" - -cross-spawn@^7.0.0, cross-spawn@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -crypto-random-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" - integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== - -csv-parser@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/csv-parser/-/csv-parser-3.0.0.tgz#b88a6256d79e090a97a1b56451f9327b01d710e7" - integrity sha512-s6OYSXAK3IdKqYO33y09jhypG/bSDHPuyCme/IdEHfWpLf/jKcpitVFyOC6UemgGk8v7Q5u2XE0vvwmanxhGlQ== - dependencies: - minimist "^1.2.0" - -d@1, d@^1.0.1, d@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.2.tgz#2aefd554b81981e7dccf72d6842ae725cb17e5de" - integrity sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw== - dependencies: - es5-ext "^0.10.64" - type "^2.7.2" - -data-view-buffer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" - integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - is-data-view "^1.0.1" - -data-view-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" - integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== - dependencies: - call-bind "^1.0.7" - es-errors "^1.3.0" - is-data-view "^1.0.1" - -data-view-byte-offset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" - integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - is-data-view "^1.0.1" - -debug@2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@4, debug@^4.1.1, debug@^4.3.4: - version "4.3.5" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" - integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== - dependencies: - ms "2.1.2" - -debug@4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== - dependencies: - ms "^2.1.1" - -debug@^3.2.6: - version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - -decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== - -decompress-response@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" - integrity sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA== - dependencies: - mimic-response "^1.0.0" - -deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== - -defer-to-connect@^1.0.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" - integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== - -define-data-property@^1.0.1, define-data-property@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" - integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== - dependencies: - es-define-property "^1.0.0" - es-errors "^1.3.0" - gopd "^1.0.1" - -define-lazy-prop@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" - integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== - -define-properties@^1.1.2, define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" - integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== - dependencies: - define-data-property "^1.0.1" - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== - -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== - -denque@^1.4.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" - integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== - -depd@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" - integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== - -depd@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== - -destroy@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" - integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== - -detect-libc@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" - integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== - -dicer@0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f" - integrity sha512-FDvbtnq7dzlPz0wyYlOExifDEZcu8h+rErEXgfxqmLfRfC/kJidEFh4+effJRO3P0xmfqyPbSMG0LveNRfTKVg== - dependencies: - readable-stream "1.1.x" - streamsearch "0.1.2" - -diff@4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - -doctrine@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -dot-prop@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" - integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== - dependencies: - is-obj "^2.0.0" - -dottie@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/dottie/-/dottie-2.0.6.tgz#34564ebfc6ec5e5772272d466424ad5b696484d4" - integrity sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA== - -duplexer3@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.5.tgz#0b5e4d7bad5de8901ea4440624c8e1d20099217e" - integrity sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA== - -duplexify@^4.0.0, duplexify@^4.1.1: - version "4.1.3" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-4.1.3.tgz#a07e1c0d0a2c001158563d32592ba58bddb0236f" - integrity sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA== - dependencies: - end-of-stream "^1.4.1" - inherits "^2.0.3" - readable-stream "^3.1.1" - stream-shift "^1.0.2" - -eastasianwidth@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" - integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== - -ecdsa-sig-formatter@1.0.11, ecdsa-sig-formatter@^1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" - integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== - dependencies: - safe-buffer "^5.0.1" - -editorconfig@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-1.0.4.tgz#040c9a8e9a6c5288388b87c2db07028aa89f53a3" - integrity sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q== - dependencies: - "@one-ini/wasm" "0.1.1" - commander "^10.0.0" - minimatch "9.0.1" - semver "^7.5.3" - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== - -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -emoji-regex@^9.2.2: - version "9.2.2" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" - integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== - -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== - -end-of-stream@^1.1.0, end-of-stream@^1.4.1: - version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" - -ent@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.1.tgz#68dc99a002f115792c26239baedaaea9e70c0ca2" - integrity sha512-QHuXVeZx9d+tIQAz/XztU0ZwZf2Agg9CcXcgE1rurqvdBeDBrpSwjl8/6XUqMg7tw2Y7uAdKb2sRv+bSEFqQ5A== - dependencies: - punycode "^1.4.1" - -es-abstract@^1.17.0-next.1, es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.2: - version "1.23.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" - integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== - dependencies: - array-buffer-byte-length "^1.0.1" - arraybuffer.prototype.slice "^1.0.3" - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - data-view-buffer "^1.0.1" - data-view-byte-length "^1.0.1" - data-view-byte-offset "^1.0.0" - es-define-property "^1.0.0" - es-errors "^1.3.0" - es-object-atoms "^1.0.0" - es-set-tostringtag "^2.0.3" - es-to-primitive "^1.2.1" - function.prototype.name "^1.1.6" - get-intrinsic "^1.2.4" - get-symbol-description "^1.0.2" - globalthis "^1.0.3" - gopd "^1.0.1" - has-property-descriptors "^1.0.2" - has-proto "^1.0.3" - has-symbols "^1.0.3" - hasown "^2.0.2" - internal-slot "^1.0.7" - is-array-buffer "^3.0.4" - is-callable "^1.2.7" - is-data-view "^1.0.1" - is-negative-zero "^2.0.3" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.3" - is-string "^1.0.7" - is-typed-array "^1.1.13" - is-weakref "^1.0.2" - object-inspect "^1.13.1" - object-keys "^1.1.1" - object.assign "^4.1.5" - regexp.prototype.flags "^1.5.2" - safe-array-concat "^1.1.2" - safe-regex-test "^1.0.3" - string.prototype.trim "^1.2.9" - string.prototype.trimend "^1.0.8" - string.prototype.trimstart "^1.0.8" - typed-array-buffer "^1.0.2" - typed-array-byte-length "^1.0.1" - typed-array-byte-offset "^1.0.2" - typed-array-length "^1.0.6" - unbox-primitive "^1.0.2" - which-typed-array "^1.1.15" - -es-array-method-boxes-properly@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" - integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== - -es-define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" - integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== - dependencies: - get-intrinsic "^1.2.4" - -es-errors@^1.2.1, es-errors@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" - integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== - -es-get-iterator@^1.0.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6" - integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.3" - has-symbols "^1.0.3" - is-arguments "^1.1.1" - is-map "^2.0.2" - is-set "^2.0.2" - is-string "^1.0.7" - isarray "^2.0.5" - stop-iteration-iterator "^1.0.0" - -es-object-atoms@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" - integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== - dependencies: - es-errors "^1.3.0" - -es-set-tostringtag@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" - integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== - dependencies: - get-intrinsic "^1.2.4" - has-tostringtag "^1.0.2" - hasown "^2.0.1" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.62, es5-ext@^0.10.64, es5-ext@~0.10.14, es5-ext@~0.10.2: - version "0.10.64" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.64.tgz#12e4ffb48f1ba2ea777f1fcdd1918ef73ea21714" - integrity sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg== - dependencies: - es6-iterator "^2.0.3" - es6-symbol "^3.1.3" - esniff "^2.0.1" - next-tick "^1.1.0" - -es6-iterator@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g== - dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - -es6-symbol@^3.1.1, es6-symbol@^3.1.3: - version "3.1.4" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.4.tgz#f4e7d28013770b4208ecbf3e0bf14d3bcb557b8c" - integrity sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg== - dependencies: - d "^1.0.2" - ext "^1.7.0" - -es6-weak-map@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.3.tgz#b6da1f16cc2cc0d9be43e6bdbfc5e7dfcdf31d53" - integrity sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA== - dependencies: - d "1" - es5-ext "^0.10.46" - es6-iterator "^2.0.3" - es6-symbol "^3.1.1" - -escalade@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" - integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== - -escape-goat@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" - integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q== - -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== - -escape-string-regexp@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -esniff@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/esniff/-/esniff-2.0.1.tgz#a4d4b43a5c71c7ec51c51098c1d8a29081f9b308" - integrity sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg== - dependencies: - d "^1.0.1" - es5-ext "^0.10.62" - event-emitter "^0.3.5" - type "^2.7.2" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== - -event-emitter@^0.3.5: - version "0.3.5" - resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" - integrity sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA== - dependencies: - d "1" - es5-ext "~0.10.14" - -event-target-shim@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" - integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== - -events@^3.0.0, events@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - -express@4.18.2: - version "4.18.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" - integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== - dependencies: - accepts "~1.3.8" - array-flatten "1.1.1" - body-parser "1.20.1" - content-disposition "0.5.4" - content-type "~1.0.4" - cookie "0.5.0" - cookie-signature "1.0.6" - debug "2.6.9" - depd "2.0.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "1.2.0" - fresh "0.5.2" - http-errors "2.0.0" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "2.4.1" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.7" - qs "6.11.0" - range-parser "~1.2.1" - safe-buffer "5.2.1" - send "0.18.0" - serve-static "1.15.0" - setprototypeof "1.2.0" - statuses "2.0.1" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - -ext@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f" - integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw== - dependencies: - type "^2.7.2" - -extend@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -fast-text-encoding@^1.0.0: - version "1.0.6" - resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz#0aa25f7f638222e3396d72bf936afcf1d42d6867" - integrity sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w== - -fill-range@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" - integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== - dependencies: - to-regex-range "^5.0.1" - -finalhandler@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" - integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "2.4.1" - parseurl "~1.3.3" - statuses "2.0.1" - unpipe "~1.0.0" - -find-up@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - -flat@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.1.tgz#a392059cc382881ff98642f5da4dde0a959f309b" - integrity sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA== - dependencies: - is-buffer "~2.0.3" - -follow-redirects@^1.15.6: - version "1.15.6" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" - integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== - -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== - dependencies: - is-callable "^1.1.3" - -foreground-child@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.2.1.tgz#767004ccf3a5b30df39bed90718bab43fe0a59f7" - integrity sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA== - dependencies: - cross-spawn "^7.0.0" - signal-exit "^4.0.1" - -form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -formidable@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.2.tgz#bf69aea2972982675f00865342b982986f6b8dd9" - integrity sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q== - -forwarded@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" - integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== - -fresh@0.5.2, fresh@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== - -fs-extra@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" - integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== - dependencies: - at-least-node "^1.0.0" - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs-minipass@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" - integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== - dependencies: - minipass "^3.0.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - -fsevents@~2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" - integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== - -fsevents@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - -function-bind@^1.1.1, function-bind@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" - integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== - -function.prototype.name@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" - integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - functions-have-names "^1.2.3" - -functions-have-names@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" - integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== - -gauge@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" - integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== - dependencies: - aproba "^1.0.3 || ^2.0.0" - color-support "^1.1.2" - console-control-strings "^1.0.0" - has-unicode "^2.0.1" - object-assign "^4.1.1" - signal-exit "^3.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - wide-align "^1.1.2" - -gaxios@^4.0.0: - version "4.3.3" - resolved "https://registry.yarnpkg.com/gaxios/-/gaxios-4.3.3.tgz#d44bdefe52d34b6435cc41214fdb160b64abfc22" - integrity sha512-gSaYYIO1Y3wUtdfHmjDUZ8LWaxJQpiavzbF5Kq53akSzvmVg0RfyOcFDbO1KJ/KCGRFz2qG+lS81F0nkr7cRJA== - dependencies: - abort-controller "^3.0.0" - extend "^3.0.2" - https-proxy-agent "^5.0.0" - is-stream "^2.0.0" - node-fetch "^2.6.7" - -gcp-metadata@^4.2.0: - version "4.3.1" - resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-4.3.1.tgz#fb205fe6a90fef2fd9c85e6ba06e5559ee1eefa9" - integrity sha512-x850LS5N7V1F3UcV7PoupzGsyD6iVwTVvsh3tbXfkctZnBnjW5yu5z1/3k3SehF7TyoTIe78rJs02GMMy+LF+A== - dependencies: - gaxios "^4.0.0" - json-bigint "^1.0.0" - -generate-function@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" - integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ== - dependencies: - is-property "^1.0.2" - -get-caller-file@^2.0.1, get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" - integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== - dependencies: - es-errors "^1.3.0" - function-bind "^1.1.2" - has-proto "^1.0.1" - has-symbols "^1.0.3" - hasown "^2.0.0" - -get-stream@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - -get-stream@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" - integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== - dependencies: - pump "^3.0.0" - -get-symbol-description@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" - integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== - dependencies: - call-bind "^1.0.5" - es-errors "^1.3.0" - get-intrinsic "^1.2.4" - -glob-parent@~5.1.0, glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob@7.1.6: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^10.3.3: - version "10.4.5" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" - integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== - dependencies: - foreground-child "^3.1.0" - jackspeak "^3.1.2" - minimatch "^9.0.4" - minipass "^7.1.2" - package-json-from-dist "^1.0.0" - path-scurry "^1.11.1" - -glob@^7.1.3: - version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - -global-dirs@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.1.0.tgz#e9046a49c806ff04d6c1825e196c8f0091e8df4d" - integrity sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ== - dependencies: - ini "1.3.7" - -globalthis@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" - integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== - dependencies: - define-properties "^1.2.1" - gopd "^1.0.1" - -google-auth-library@^7.14.1: - version "7.14.1" - resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-7.14.1.tgz#e3483034162f24cc71b95c8a55a210008826213c" - integrity sha512-5Rk7iLNDFhFeBYc3s8l1CqzbEBcdhwR193RlD4vSNFajIcINKI8W8P0JLmBpwymHqqWbX34pJDQu39cSy/6RsA== - dependencies: - arrify "^2.0.0" - base64-js "^1.3.0" - ecdsa-sig-formatter "^1.0.11" - fast-text-encoding "^1.0.0" - gaxios "^4.0.0" - gcp-metadata "^4.2.0" - gtoken "^5.0.4" - jws "^4.0.0" - lru-cache "^6.0.0" - -google-p12-pem@^3.1.3: - version "3.1.4" - resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-3.1.4.tgz#123f7b40da204de4ed1fbf2fd5be12c047fc8b3b" - integrity sha512-HHuHmkLgwjdmVRngf5+gSmpkyaRI6QmOg77J8tkNBHhNEI62sGHyw4/+UkgyZEI7h84NbWprXDJ+sa3xOYFvTg== - dependencies: - node-forge "^1.3.1" - -gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== - dependencies: - get-intrinsic "^1.1.3" - -got@^9.6.0: - version "9.6.0" - resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" - integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== - dependencies: - "@sindresorhus/is" "^0.14.0" - "@szmarczak/http-timer" "^1.1.2" - cacheable-request "^6.0.0" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^4.1.0" - lowercase-keys "^1.0.1" - mimic-response "^1.0.1" - p-cancelable "^1.0.0" - to-readable-stream "^1.0.0" - url-parse-lax "^3.0.0" - -graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: - version "4.2.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" - integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== - -growl@1.10.5: - version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" - integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== - -gtoken@^5.0.4: - version "5.3.2" - resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-5.3.2.tgz#deb7dc876abe002178e0515e383382ea9446d58f" - integrity sha512-gkvEKREW7dXWF8NV8pVrKfW7WqReAmjjkMBh6lNCCGOM4ucS0r0YyXXl0r/9Yj8wcW/32ISkfc8h5mPTDbtifQ== - dependencies: - gaxios "^4.0.0" - google-p12-pem "^3.1.3" - jws "^4.0.0" - -has-bigints@^1.0.1, has-bigints@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" - integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" - integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== - dependencies: - es-define-property "^1.0.0" - -has-proto@^1.0.1, has-proto@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" - integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== - -has-symbols@^1.0.0, has-symbols@^1.0.2, has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - -has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" - integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== - dependencies: - has-symbols "^1.0.3" - -has-unicode@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== - -has-yarn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" - integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== - -hash-stream-validation@^0.2.2: - version "0.2.4" - resolved "https://registry.yarnpkg.com/hash-stream-validation/-/hash-stream-validation-0.2.4.tgz#ee68b41bf822f7f44db1142ec28ba9ee7ccb7512" - integrity sha512-Gjzu0Xn7IagXVkSu9cSFuK1fqzwtLwFhNhVL8IFJijRNMgUttFbBSIAzKuSIrsFMO1+g1RlsoN49zPIbwPDMGQ== - -hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" - integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== - dependencies: - function-bind "^1.1.2" - -he@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - -helmet@4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/helmet/-/helmet-4.1.1.tgz#751f0e273d809ace9c172073e0003bed27d27a4a" - integrity sha512-Avg4XxSBrehD94mkRwEljnO+6RZx7AGfk8Wa6K1nxaU+hbXlFOhlOIMgPfFqOYQB/dBCsTpootTGuiOG+CHiQA== - -http-cache-semantics@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" - integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== - -http-errors@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" - integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== - dependencies: - depd "2.0.0" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses "2.0.1" - toidentifier "1.0.1" - -http-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" - integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w== - dependencies: - "@tootallnate/once" "2" - agent-base "6" - debug "4" - -http-proxy-agent@^7.0.0: - version "7.0.2" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" - integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== - dependencies: - agent-base "^7.1.0" - debug "^4.3.4" - -https-proxy-agent@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" - integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== - dependencies: - agent-base "6" - debug "4" - -https-proxy-agent@^7.0.0: - version "7.0.5" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" - integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw== - dependencies: - agent-base "^7.0.2" - debug "4" - -iconv-lite@0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -iconv-lite@^0.6.2, iconv-lite@^0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" - integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - -ieee754@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -ignore-by-default@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" - integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA== - -import-lazy@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" - integrity sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A== - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== - -inflection@^1.13.4: - version "1.13.4" - resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.13.4.tgz#65aa696c4e2da6225b148d7a154c449366633a32" - integrity sha512-6I/HUDeYFfuNCVS3td055BaXBwKYuzw7K3ExVMStBowKo9oOAMJIXIHvdyR3iboTCp1b+1i5DSkIZTcwIktuDw== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -ini@1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" - integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ== - -ini@^1.3.4, ini@~1.3.0: - version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== - -internal-slot@^1.0.4, internal-slot@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" - integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== - dependencies: - es-errors "^1.3.0" - hasown "^2.0.0" - side-channel "^1.0.4" - -ipaddr.js@1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== - -is-arguments@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-array-buffer@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" - integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" - -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== - dependencies: - has-bigints "^1.0.1" - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-buffer@~2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" - integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== - -is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" - integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== - -is-ci@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" - integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== - dependencies: - ci-info "^2.0.0" - -is-core-module@^2.13.0: - version "2.15.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.0.tgz#71c72ec5442ace7e76b306e9d48db361f22699ea" - integrity sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA== - dependencies: - hasown "^2.0.2" - -is-data-view@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" - integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== - dependencies: - is-typed-array "^1.1.13" - -is-date-object@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== - dependencies: - has-tostringtag "^1.0.0" - -is-docker@^2.0.0, is-docker@^2.1.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" - integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w== - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-installed-globally@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141" - integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g== - dependencies: - global-dirs "^2.0.1" - is-path-inside "^3.0.1" - -is-map@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" - integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== - -is-negative-zero@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" - integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== - -is-npm@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d" - integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig== - -is-number-object@^1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" - integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== - dependencies: - has-tostringtag "^1.0.0" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" - integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== - -is-path-inside@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== - -is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg== - -is-promise@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" - integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== - -is-property@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - integrity sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g== - -is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-set@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" - integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== - -is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" - integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== - dependencies: - call-bind "^1.0.7" - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - -is-typed-array@^1.1.13: - version "1.1.13" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" - integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== - dependencies: - which-typed-array "^1.1.14" - -is-typedarray@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== - -is-weakref@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== - dependencies: - call-bind "^1.0.2" - -is-wsl@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== - dependencies: - is-docker "^2.0.0" - -is-yarn-global@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" - integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== - -isarray@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -iterate-iterator@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/iterate-iterator/-/iterate-iterator-1.0.2.tgz#551b804c9eaa15b847ea6a7cdc2f5bf1ec150f91" - integrity sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw== - -iterate-value@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/iterate-value/-/iterate-value-1.0.2.tgz#935115bd37d006a52046535ebc8d07e9c9337f57" - integrity sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ== - dependencies: - es-get-iterator "^1.0.2" - iterate-iterator "^1.0.1" - -jackspeak@^3.1.2: - version "3.4.3" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" - integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== - dependencies: - "@isaacs/cliui" "^8.0.2" - optionalDependencies: - "@pkgjs/parseargs" "^0.11.0" - -js-beautify@^1.14.5: - version "1.15.1" - resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.15.1.tgz#4695afb508c324e1084ee0b952a102023fc65b64" - integrity sha512-ESjNzSlt/sWE8sciZH8kBF8BPlwXPwhR6pWKAw8bw4Bwj+iZcnKW6ONWUutJ7eObuBZQpiIb8S7OYspWrKt7rA== - dependencies: - config-chain "^1.1.13" - editorconfig "^1.0.4" - glob "^10.3.3" - js-cookie "^3.0.5" - nopt "^7.2.0" - -js-cookie@^3.0.5: - version "3.0.5" - resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-3.0.5.tgz#0b7e2fd0c01552c58ba86e0841f94dc2557dcdbc" - integrity sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw== - -js-md4@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/js-md4/-/js-md4-0.3.2.tgz#cd3b3dc045b0c404556c81ddb5756c23e59d7cf5" - integrity sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA== - -js-yaml@3.14.0: - version "3.14.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" - integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - -json-bigint@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/json-bigint/-/json-bigint-1.0.0.tgz#ae547823ac0cad8398667f8cd9ef4730f5b01ff1" - integrity sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ== - dependencies: - bignumber.js "^9.0.0" - -json-buffer@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" - integrity sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ== - -json2csv@^5.0.7: - version "5.0.7" - resolved "https://registry.yarnpkg.com/json2csv/-/json2csv-5.0.7.tgz#f3a583c25abd9804be873e495d1e65ad8d1b54ae" - integrity sha512-YRZbUnyaJZLZUJSRi2G/MqahCyRv9n/ds+4oIetjDF3jWQA7AG7iSeKTiZiCNqtMZM7HDyt0e/W6lEnoGEmMGA== - dependencies: - commander "^6.1.0" - jsonparse "^1.3.1" - lodash.get "^4.4.2" - -jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - -jsonparse@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" - integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== - -jsonwebtoken@8.5.1: - version "8.5.1" - resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" - integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== - dependencies: - jws "^3.2.2" - lodash.includes "^4.3.0" - lodash.isboolean "^3.0.3" - lodash.isinteger "^4.0.4" - lodash.isnumber "^3.0.3" - lodash.isplainobject "^4.0.6" - lodash.isstring "^4.0.1" - lodash.once "^4.0.0" - ms "^2.1.1" - semver "^5.6.0" - -jsonwebtoken@^9.0.0: - version "9.0.2" - resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3" - integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ== - dependencies: - jws "^3.2.2" - lodash.includes "^4.3.0" - lodash.isboolean "^3.0.3" - lodash.isinteger "^4.0.4" - lodash.isnumber "^3.0.3" - lodash.isplainobject "^4.0.6" - lodash.isstring "^4.0.1" - lodash.once "^4.0.0" - ms "^2.1.1" - semver "^7.5.4" - -jwa@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" - integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== - dependencies: - buffer-equal-constant-time "1.0.1" - ecdsa-sig-formatter "1.0.11" - safe-buffer "^5.0.1" - -jwa@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/jwa/-/jwa-2.0.0.tgz#a7e9c3f29dae94027ebcaf49975c9345593410fc" - integrity sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA== - dependencies: - buffer-equal-constant-time "1.0.1" - ecdsa-sig-formatter "1.0.11" - safe-buffer "^5.0.1" - -jws@^3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" - integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== - dependencies: - jwa "^1.4.1" - safe-buffer "^5.0.1" - -jws@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jws/-/jws-4.0.0.tgz#2d4e8cf6a318ffaa12615e9dec7e86e6c97310f4" - integrity sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg== - dependencies: - jwa "^2.0.0" - safe-buffer "^5.0.1" - -keyv@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" - integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== - dependencies: - json-buffer "3.0.0" - -latest-version@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" - integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA== - dependencies: - package-json "^6.3.0" - -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - -lodash.get@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" - integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== - -lodash.includes@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" - integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== - -lodash.isboolean@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" - integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== - -lodash.isequal@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" - integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== - -lodash.isinteger@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" - integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== - -lodash.isnumber@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" - integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== - -lodash.isplainobject@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" - integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== - -lodash.isstring@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" - integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== - -lodash.mergewith@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" - integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== - -lodash.once@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" - integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== - -lodash@4.17.21, lodash@^4.17.21: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -log-symbols@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920" - integrity sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA== - dependencies: - chalk "^4.0.0" - -long@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" - integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== - -lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" - integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== - -lowercase-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" - integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== - -lru-cache@^10.2.0: - version "10.4.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" - integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -lru-cache@^7.14.1: - version "7.18.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" - integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== - -lru-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" - integrity sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ== - dependencies: - es5-ext "~0.10.2" - -make-dir@^3.0.0, make-dir@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== - -memoizee@^0.4.15: - version "0.4.17" - resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.17.tgz#942a5f8acee281fa6fb9c620bddc57e3b7382949" - integrity sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA== - dependencies: - d "^1.0.2" - es5-ext "^0.10.64" - es6-weak-map "^2.0.3" - event-emitter "^0.3.5" - is-promise "^2.2.2" - lru-queue "^0.1.0" - next-tick "^1.1.0" - timers-ext "^0.1.7" - -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== - -merge-descriptors@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" - integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== - -methods@^1.1.2, methods@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== - -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -"mime-db@>= 1.43.0 < 2": - version "1.53.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.53.0.tgz#3cb63cd820fc29896d9d4e8c32ab4fcd74ccb447" - integrity sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg== - -mime-types@^2.0.8, mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -mime@1.6.0, mime@^1.3.4: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - -mime@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" - integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== - -mimic-response@^1.0.0, mimic-response@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" - integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== - -minimatch@3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimatch@9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.1.tgz#8a555f541cf976c622daf078bb28f29fb927c253" - integrity sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w== - dependencies: - brace-expansion "^2.0.1" - -minimatch@^3.0.4, minimatch@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^9.0.4: - version "9.0.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" - integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== - dependencies: - brace-expansion "^2.0.1" - -minimist@^1.2.0, minimist@^1.2.6: - version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - -minipass@^3.0.0: - version "3.3.6" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" - integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== - dependencies: - yallist "^4.0.0" - -minipass@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" - integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== - -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" - integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== - -minizlib@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" - integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== - dependencies: - minipass "^3.0.0" - yallist "^4.0.0" - -mkdirp@^0.5.4: - version "0.5.6" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" - integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== - dependencies: - minimist "^1.2.6" - -mkdirp@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - -mocha@8.1.3: - version "8.1.3" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-8.1.3.tgz#5e93f873e35dfdd69617ea75f9c68c2ca61c2ac5" - integrity sha512-ZbaYib4hT4PpF4bdSO2DohooKXIn4lDeiYqB+vTmCdr6l2woW0b6H3pf5x4sM5nwQMru9RvjjHYWVGltR50ZBw== - dependencies: - ansi-colors "4.1.1" - browser-stdout "1.3.1" - chokidar "3.4.2" - debug "4.1.1" - diff "4.0.2" - escape-string-regexp "4.0.0" - find-up "5.0.0" - glob "7.1.6" - growl "1.10.5" - he "1.2.0" - js-yaml "3.14.0" - log-symbols "4.0.0" - minimatch "3.0.4" - ms "2.1.2" - object.assign "4.1.0" - promise.allsettled "1.0.2" - serialize-javascript "4.0.0" - strip-json-comments "3.0.1" - supports-color "7.1.0" - which "2.0.2" - wide-align "1.1.3" - workerpool "6.0.0" - yargs "13.3.2" - yargs-parser "13.1.2" - yargs-unparser "1.6.1" - -moment-timezone@^0.5.43: - version "0.5.45" - resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.45.tgz#cb685acd56bac10e69d93c536366eb65aa6bcf5c" - integrity sha512-HIWmqA86KcmCAhnMAN0wuDOARV/525R2+lOLotuGFzn4HO+FH+/645z2wx0Dt3iDv6/p61SIvKnDstISainhLQ== - dependencies: - moment "^2.29.4" - -moment@2.30.1, moment@^2.29.4: - version "2.30.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" - integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how== - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@2.1.3, ms@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -multer@^1.4.4: - version "1.4.4" - resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.4.tgz#e2bc6cac0df57a8832b858d7418ccaa8ebaf7d8c" - integrity sha512-2wY2+xD4udX612aMqMcB8Ws2Voq6NIUPEtD1be6m411T4uDH/VtL9i//xvcyFlTVfRdaBsk7hV5tgrGQqhuBiw== - dependencies: - append-field "^1.0.0" - busboy "^0.2.11" - concat-stream "^1.5.2" - mkdirp "^0.5.4" - object-assign "^4.1.1" - on-finished "^2.3.0" - type-is "^1.6.4" - xtend "^4.0.0" - -mysql2@2.2.5: - version "2.2.5" - resolved "https://registry.yarnpkg.com/mysql2/-/mysql2-2.2.5.tgz#72624ffb4816f80f96b9c97fedd8c00935f9f340" - integrity sha512-XRqPNxcZTpmFdXbJqb+/CtYVLCx14x1RTeNMD4954L331APu75IC74GDqnZMEt1kwaXy6TySo55rF2F3YJS78g== - dependencies: - denque "^1.4.1" - generate-function "^2.3.1" - iconv-lite "^0.6.2" - long "^4.0.0" - lru-cache "^6.0.0" - named-placeholders "^1.1.2" - seq-queue "^0.0.5" - sqlstring "^2.3.2" - -named-placeholders@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/named-placeholders/-/named-placeholders-1.1.3.tgz#df595799a36654da55dda6152ba7a137ad1d9351" - integrity sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w== - dependencies: - lru-cache "^7.14.1" - -native-duplexpair@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/native-duplexpair/-/native-duplexpair-1.0.0.tgz#7899078e64bf3c8a3d732601b3d40ff05db58fa0" - integrity sha512-E7QQoM+3jvNtlmyfqRZ0/U75VFgCls+fSkbml2MpgWkWyz3ox8Y58gNhfuziuQYGNNQAbFZJQck55LHCnCK6CA== - -negotiator@0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== - -next-tick@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" - integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== - -node-addon-api@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762" - integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA== - -node-fetch@^2.6.1, node-fetch@^2.6.7: - version "2.7.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" - integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== - dependencies: - whatwg-url "^5.0.0" - -node-forge@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" - integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== - -node-mocks-http@1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/node-mocks-http/-/node-mocks-http-1.9.0.tgz#6000c570fc4b809603782309be81c73a71d85b71" - integrity sha512-ILf7Ws8xyX9Rl2fLZ7xhZBovrRwgaP84M13esndP6V17M/8j25TpwNzb7Im8U9XCo6fRhdwqiQajWXpsas/E6w== - dependencies: - accepts "^1.3.7" - depd "^1.1.0" - fresh "^0.5.2" - merge-descriptors "^1.0.1" - methods "^1.1.2" - mime "^1.3.4" - parseurl "^1.3.3" - range-parser "^1.2.0" - type-is "^1.6.18" - -nodemailer@6.9.9: - version "6.9.9" - resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.9.9.tgz#4549bfbf710cc6addec5064dd0f19874d24248d9" - integrity sha512-dexTll8zqQoVJEZPwQAKzxxtFn0qTnjdQTchoU6Re9BUUGBJiOy3YMn/0ShTW6J5M0dfQ1NeDeRTTl4oIWgQMA== - -nodemon@2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.5.tgz#df67fe1fd1312ddb0c1e393ae2cf55aacdcec2f3" - integrity sha512-6/jqtZvJdk092pVnD2AIH19KQ9GQZAKOZVy/yT1ueL6aoV+Ix7a1lVZStXzvEh0fP4zE41DDWlkVoHjR6WlozA== - dependencies: - chokidar "^3.2.2" - debug "^3.2.6" - ignore-by-default "^1.0.1" - minimatch "^3.0.4" - pstree.remy "^1.1.7" - semver "^5.7.1" - supports-color "^5.5.0" - touch "^3.1.0" - undefsafe "^2.0.3" - update-notifier "^4.1.0" - -nopt@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" - integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== - dependencies: - abbrev "1" - -nopt@^7.2.0: - version "7.2.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.2.1.tgz#1cac0eab9b8e97c9093338446eddd40b2c8ca1e7" - integrity sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w== - dependencies: - abbrev "^2.0.0" - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -normalize-url@^4.1.0: - version "4.5.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" - integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== - -npmlog@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" - integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== - dependencies: - are-we-there-yet "^2.0.0" - console-control-strings "^1.1.0" - gauge "^3.0.0" - set-blocking "^2.0.0" - -oauth@0.10.x: - version "0.10.0" - resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.10.0.tgz#3551c4c9b95c53ea437e1e21e46b649482339c58" - integrity sha512-1orQ9MT1vHFGQxhuy7E/0gECD3fd2fCC+PIX+/jgmU/gI3EpRocXtmtvxCO5x3WZ443FLTLFWNDjl5MPJf9u+Q== - -oauth@0.9.x: - version "0.9.15" - resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" - integrity sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA== - -object-assign@^4, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== - -object-inspect@^1.13.1: - version "1.13.2" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" - integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== - -object-keys@^1.0.11, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object.assign@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" - integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== - dependencies: - define-properties "^1.1.2" - function-bind "^1.1.1" - has-symbols "^1.0.0" - object-keys "^1.0.11" - -object.assign@^4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" - integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== - dependencies: - call-bind "^1.0.5" - define-properties "^1.2.1" - has-symbols "^1.0.3" - object-keys "^1.1.1" - -on-finished@2.4.1, on-finished@^2.3.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" - integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== - dependencies: - ee-first "1.1.1" - -once@^1.3.0, once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - -open@^8.0.0: - version "8.4.2" - resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" - integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== - dependencies: - define-lazy-prop "^2.0.0" - is-docker "^2.1.1" - is-wsl "^2.2.0" - -p-cancelable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" - integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== - -p-limit@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-limit@^3.0.1, p-limit@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -package-json-from-dist@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" - integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== - -package-json@^6.3.0: - version "6.5.0" - resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" - integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ== - dependencies: - got "^9.6.0" - registry-auth-token "^4.0.0" - registry-url "^5.0.0" - semver "^6.2.0" - -packet-reader@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" - integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== - -parseurl@^1.3.3, parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -passport-google-oauth2@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/passport-google-oauth2/-/passport-google-oauth2-0.2.0.tgz#fc9ea59e7091f02e24fd16d6be9257ea982ebbc3" - integrity sha512-62EdPtbfVdc55nIXi0p1WOa/fFMM8v/M8uQGnbcXA4OexZWCnfsEi3wo2buag+Is5oqpuHzOtI64JpHk0Xi5RQ== - dependencies: - passport-oauth2 "^1.1.2" - -passport-jwt@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/passport-jwt/-/passport-jwt-4.0.1.tgz#c443795eff322c38d173faa0a3c481479646ec3d" - integrity sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ== - dependencies: - jsonwebtoken "^9.0.0" - passport-strategy "^1.0.0" - -passport-microsoft@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/passport-microsoft/-/passport-microsoft-0.1.0.tgz#dc72c1a38b294d74f4dc55fe93f52e25cb9aa5b4" - integrity sha512-0giBDgE1fnR5X84zJZkQ11hnKVrzEgViwRO6RGsormK9zTxFQmN/UHMTDbIpvhk989VqALewB6Pk1R5vNr3GHw== - dependencies: - passport-oauth2 "1.2.0" - pkginfo "0.2.x" - -passport-oauth2@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.2.0.tgz#49613a3eca85c7a1e65bf1019e2b6b80a10c8ac2" - integrity sha512-6128N+n/MOrJdXxdC2q/PVKXtqgihGFIeup+9bsPybAvMPOUKqdGhh9ZIzZF8rFKJOlxUP9fgP3H0JQe18n0rg== - dependencies: - oauth "0.9.x" - passport-strategy "1.x.x" - uid2 "0.0.x" - -passport-oauth2@^1.1.2: - version "1.8.0" - resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.8.0.tgz#55725771d160f09bbb191828d5e3d559eee079c8" - integrity sha512-cjsQbOrXIDE4P8nNb3FQRCCmJJ/utnFKEz2NX209f7KOHPoX18gF7gBzBbLLsj2/je4KrgiwLLGjf0lm9rtTBA== - dependencies: - base64url "3.x.x" - oauth "0.10.x" - passport-strategy "1.x.x" - uid2 "0.0.x" - utils-merge "1.x.x" - -passport-strategy@1.x.x, passport-strategy@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" - integrity sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA== - -passport@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/passport/-/passport-0.7.0.tgz#3688415a59a48cf8068417a8a8092d4492ca3a05" - integrity sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ== - dependencies: - passport-strategy "1.x.x" - pause "0.0.1" - utils-merge "^1.0.1" - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-scurry@^1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" - integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== - dependencies: - lru-cache "^10.2.0" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== - -pause@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" - integrity sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg== - -pg-connection-string@^2.4.0, pg-connection-string@^2.6.1: - version "2.6.4" - resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.6.4.tgz#f543862adfa49fa4e14bc8a8892d2a84d754246d" - integrity sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA== - -pg-hstore@2.3.4: - version "2.3.4" - resolved "https://registry.yarnpkg.com/pg-hstore/-/pg-hstore-2.3.4.tgz#4425e3e2a3e15d2a334c35581186c27cf2e9b8dd" - integrity sha512-N3SGs/Rf+xA1M2/n0JBiXFDVMzdekwLZLAO0g7mpDY9ouX+fDI7jS6kTq3JujmYbtNSJ53TJ0q4G98KVZSM4EA== - dependencies: - underscore "^1.13.1" - -pg-int8@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" - integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== - -pg-pool@^3.2.1: - version "3.6.2" - resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.6.2.tgz#3a592370b8ae3f02a7c8130d245bc02fa2c5f3f2" - integrity sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg== - -pg-protocol@^1.3.0: - version "1.6.1" - resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.6.1.tgz#21333e6d83b01faaebfe7a33a7ad6bfd9ed38cb3" - integrity sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg== - -pg-types@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" - integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== - dependencies: - pg-int8 "1.0.1" - postgres-array "~2.0.0" - postgres-bytea "~1.0.0" - postgres-date "~1.0.4" - postgres-interval "^1.1.0" - -pg@8.4.1: - version "8.4.1" - resolved "https://registry.yarnpkg.com/pg/-/pg-8.4.1.tgz#06cfb6208ae787a869b2f0022da11b90d13d933e" - integrity sha512-NRsH0aGMXmX1z8Dd0iaPCxWUw4ffu+lIAmGm+sTCwuDDWkpEgRCAHZYDwqaNhC5hG5DRMOjSUFasMWhvcmLN1A== - dependencies: - buffer-writer "2.0.0" - packet-reader "1.0.0" - pg-connection-string "^2.4.0" - pg-pool "^3.2.1" - pg-protocol "^1.3.0" - pg-types "^2.1.0" - pgpass "1.x" - -pgpass@1.x: - version "1.0.5" - resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.5.tgz#9b873e4a564bb10fa7a7dbd55312728d422a223d" - integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug== - dependencies: - split2 "^4.1.0" - -picomatch@^2.0.4, picomatch@^2.2.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -pkginfo@0.2.x: - version "0.2.3" - resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.2.3.tgz#7239c42a5ef6c30b8f328439d9b9ff71042490f8" - integrity sha512-7W7wTrE/NsY8xv/DTGjwNIyNah81EQH0MWcTzrHL6pOpMocOGZc0Mbdz9aXxSrp+U0mSmkU8jrNCDCfUs3sOBg== - -possible-typed-array-names@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" - integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== - -postgres-array@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" - integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== - -postgres-bytea@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" - integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w== - -postgres-date@~1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" - integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== - -postgres-interval@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" - integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== - dependencies: - xtend "^4.0.0" - -prepend-http@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" - integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA== - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== - -promise.allsettled@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/promise.allsettled/-/promise.allsettled-1.0.2.tgz#d66f78fbb600e83e863d893e98b3d4376a9c47c9" - integrity sha512-UpcYW5S1RaNKT6pd+s9jp9K9rlQge1UXKskec0j6Mmuq7UJCvlS2J2/s/yuPN8ehftf9HXMxWlKiPbGGUzpoRg== - dependencies: - array.prototype.map "^1.0.1" - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - function-bind "^1.1.1" - iterate-value "^1.0.0" - -proto-list@~1.2.1: - version "1.2.4" - resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" - integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA== - -proxy-addr@~2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" - integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== - dependencies: - forwarded "0.2.0" - ipaddr.js "1.9.1" - -proxy-from-env@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" - integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== - -pstree.remy@^1.1.7: - version "1.1.8" - resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a" - integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== - -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -pumpify@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-2.0.1.tgz#abfc7b5a621307c728b551decbbefb51f0e4aa1e" - integrity sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw== - dependencies: - duplexify "^4.1.1" - inherits "^2.0.3" - pump "^3.0.0" - -punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== - -pupa@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62" - integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A== - dependencies: - escape-goat "^2.0.0" - -qs@6.11.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== - dependencies: - side-channel "^1.0.4" - -randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -range-parser@^1.2.0, range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -raw-body@2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" - integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== - dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.4.24" - unpipe "1.0.0" - -rc@1.2.8, rc@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -readable-stream@1.1.x: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@^2.2.2: - version "2.3.8" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" - integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@^3.1.1, readable-stream@^3.6.0: - version "3.6.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" - integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readable-stream@^4.2.0: - version "4.5.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.5.2.tgz#9e7fc4c45099baeed934bff6eb97ba6cf2729e09" - integrity sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g== - dependencies: - abort-controller "^3.0.0" - buffer "^6.0.3" - events "^3.3.0" - process "^0.11.10" - string_decoder "^1.3.0" - -readdirp@~3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.4.0.tgz#9fdccdf9e9155805449221ac645e8303ab5b9ada" - integrity sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ== - dependencies: - picomatch "^2.2.1" - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -regexp.prototype.flags@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" - integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== - dependencies: - call-bind "^1.0.6" - define-properties "^1.2.1" - es-errors "^1.3.0" - set-function-name "^2.0.1" - -registry-auth-token@^4.0.0: - version "4.2.2" - resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.2.tgz#f02d49c3668884612ca031419491a13539e21fac" - integrity sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg== - dependencies: - rc "1.2.8" - -registry-url@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009" - integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw== - dependencies: - rc "^1.2.8" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== - -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== - -resolve@^1.22.1: - version "1.22.8" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" - integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== - dependencies: - is-core-module "^2.13.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -responselike@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" - integrity sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ== - dependencies: - lowercase-keys "^1.0.0" - -retry-as-promised@^7.0.4: - version "7.0.4" - resolved "https://registry.yarnpkg.com/retry-as-promised/-/retry-as-promised-7.0.4.tgz#9df73adaeea08cb2948b9d34990549dc13d800a2" - integrity sha512-XgmCoxKWkDofwH8WddD0w85ZfqYz+ZHlr5yo+3YUCfycWawU56T5ckWXsScsj5B8tqUcIG67DxXByo3VUgiAdA== - -retry-request@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/retry-request/-/retry-request-4.2.2.tgz#b7d82210b6d2651ed249ba3497f07ea602f1a903" - integrity sha512-xA93uxUD/rogV7BV59agW/JHPGXeREMWiZc9jhcwY4YdZ7QOtC7qbomYg0n4wyk2lJhggjvKvhNX8wln/Aldhg== - dependencies: - debug "^4.1.1" - extend "^3.0.2" - -retry@0.13.1: - version "0.13.1" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" - integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -safe-array-concat@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" - integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== - dependencies: - call-bind "^1.0.7" - get-intrinsic "^1.2.4" - has-symbols "^1.0.3" - isarray "^2.0.5" - -safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-regex-test@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" - integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - is-regex "^1.1.4" - -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -semver-diff@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" - integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg== - dependencies: - semver "^6.3.0" - -semver@^5.6.0, semver@^5.7.1: - version "5.7.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" - integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== - -semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: - version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^7.3.5, semver@^7.5.3, semver@^7.5.4: - version "7.6.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== - -send@0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" - integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== - dependencies: - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "2.0.0" - mime "1.6.0" - ms "2.1.3" - on-finished "2.4.1" - range-parser "~1.2.1" - statuses "2.0.1" - -seq-queue@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e" - integrity sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q== - -sequelize-cli@6.6.2: - version "6.6.2" - resolved "https://registry.yarnpkg.com/sequelize-cli/-/sequelize-cli-6.6.2.tgz#8d838b25c988cf136914cdc3843e19d88c3dcb67" - integrity sha512-V8Oh+XMz2+uquLZltZES6MVAD+yEnmMfwfn+gpXcDiwE3jyQygLt4xoI0zG8gKt6cRcs84hsKnXAKDQjG/JAgg== - dependencies: - cli-color "^2.0.3" - fs-extra "^9.1.0" - js-beautify "^1.14.5" - lodash "^4.17.21" - resolve "^1.22.1" - umzug "^2.3.0" - yargs "^16.2.0" - -sequelize-json-schema@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/sequelize-json-schema/-/sequelize-json-schema-2.1.1.tgz#a82d3813925e81485d76ce291f4ff5c8cb2ae492" - integrity sha512-yCGaHnmQQeL6MQ/fOxhkR5C2aOGZyTD6OrgjP4yw1rbuujuIUVdzWN3AsC6r6AvlGZ3EUBBbCJHKl8OIFFES4Q== - -sequelize-pool@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/sequelize-pool/-/sequelize-pool-7.1.0.tgz#210b391af4002762f823188fd6ecfc7413020768" - integrity sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg== - -sequelize@6.35.2: - version "6.35.2" - resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-6.35.2.tgz#9276d24055a9a07bd6812c89ab402659f5853e70" - integrity sha512-EdzLaw2kK4/aOnWQ7ed/qh3B6/g+1DvmeXr66RwbcqSm/+QRS9X0LDI5INBibsy4eNJHWIRPo3+QK0zL+IPBHg== - dependencies: - "@types/debug" "^4.1.8" - "@types/validator" "^13.7.17" - debug "^4.3.4" - dottie "^2.0.6" - inflection "^1.13.4" - lodash "^4.17.21" - moment "^2.29.4" - moment-timezone "^0.5.43" - pg-connection-string "^2.6.1" - retry-as-promised "^7.0.4" - semver "^7.5.4" - sequelize-pool "^7.1.0" - toposort-class "^1.0.1" - uuid "^8.3.2" - validator "^13.9.0" - wkx "^0.5.0" - -serialize-javascript@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" - integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== - dependencies: - randombytes "^2.1.0" - -serve-static@1.15.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.18.0" - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== - -set-function-length@^1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" - integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== - dependencies: - define-data-property "^1.1.4" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.4" - gopd "^1.0.1" - has-property-descriptors "^1.0.2" - -set-function-name@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" - integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== - dependencies: - define-data-property "^1.1.4" - es-errors "^1.3.0" - functions-have-names "^1.2.3" - has-property-descriptors "^1.0.2" - -setprototypeof@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" - integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -side-channel@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" - integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== - dependencies: - call-bind "^1.0.7" - es-errors "^1.3.0" - get-intrinsic "^1.2.4" - object-inspect "^1.13.1" - -signal-exit@^3.0.0, signal-exit@^3.0.2: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -signal-exit@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" - integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== - -split2@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" - integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== - -sprintf-js@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" - integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== - -sqlite@4.0.15: - version "4.0.15" - resolved "https://registry.yarnpkg.com/sqlite/-/sqlite-4.0.15.tgz#071e0577afb327fbd74a75354ea15964378392e3" - integrity sha512-irPPTrbVoDvwzRGpe0v8vxpNwMl+q0tXQzffQTcCUnaJzQFO0hfLLvFwGDKxd6vYBuvEr3uvPkObVoGOvVsmzA== - -sqlstring@^2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.3.tgz#2ddc21f03bce2c387ed60680e739922c65751d0c" - integrity sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg== - -statuses@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" - integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== - -stop-iteration-iterator@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" - integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ== - dependencies: - internal-slot "^1.0.4" - -stoppable@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/stoppable/-/stoppable-1.1.0.tgz#32da568e83ea488b08e4d7ea2c3bcc9d75015d5b" - integrity sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw== - -stream-events@^1.0.4, stream-events@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/stream-events/-/stream-events-1.0.5.tgz#bbc898ec4df33a4902d892333d47da9bf1c406d5" - integrity sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg== - dependencies: - stubs "^3.0.0" - -stream-shift@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.3.tgz#85b8fab4d71010fc3ba8772e8046cc49b8a3864b" - integrity sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ== - -streamsearch@0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" - integrity sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA== - -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -"string-width@^1.0.2 || 2": - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^3.0.0, string-width@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - -string-width@^5.0.1, string-width@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" - integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== - dependencies: - eastasianwidth "^0.2.0" - emoji-regex "^9.2.2" - strip-ansi "^7.0.1" - -string.prototype.trim@^1.2.9: - version "1.2.9" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" - integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.0" - es-object-atoms "^1.0.0" - -string.prototype.trimend@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" - integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - -string.prototype.trimstart@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" - integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - -string_decoder@^1.1.1, string_decoder@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow== - dependencies: - ansi-regex "^3.0.0" - -strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^7.0.1: - version "7.1.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" - integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== - dependencies: - ansi-regex "^6.0.1" - -strip-json-comments@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" - integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== - -stubs@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/stubs/-/stubs-3.0.0.tgz#e8d2ba1fa9c90570303c030b6900f7d5f89abe5b" - integrity sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw== - -supports-color@7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" - integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== - dependencies: - has-flag "^4.0.0" - -supports-color@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -swagger-jsdoc@^6.2.8: - version "6.2.8" - resolved "https://registry.yarnpkg.com/swagger-jsdoc/-/swagger-jsdoc-6.2.8.tgz#6d33d9fb07ff4a7c1564379c52c08989ec7d0256" - integrity sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ== - dependencies: - commander "6.2.0" - doctrine "3.0.0" - glob "7.1.6" - lodash.mergewith "^4.6.2" - swagger-parser "^10.0.3" - yaml "2.0.0-1" - -swagger-parser@^10.0.3: - version "10.0.3" - resolved "https://registry.yarnpkg.com/swagger-parser/-/swagger-parser-10.0.3.tgz#04cb01c18c3ac192b41161c77f81e79309135d03" - integrity sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg== - dependencies: - "@apidevtools/swagger-parser" "10.0.3" - -swagger-ui-dist@>=5.0.0: - version "5.17.14" - resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-5.17.14.tgz#e2c222e5bf9e15ccf80ec4bc08b4aaac09792fd6" - integrity sha512-CVbSfaLpstV65OnSjbXfVd6Sta3q3F7Cj/yYuvHMp1P90LztOLs6PfUnKEVAeiIVQt9u2SaPwv0LiH/OyMjHRw== - -swagger-ui-express@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/swagger-ui-express/-/swagger-ui-express-5.0.1.tgz#fb8c1b781d2793a6bd2f8a205a3f4bd6fa020dd8" - integrity sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA== - dependencies: - swagger-ui-dist ">=5.0.0" - -tar@^6.1.11: - version "6.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" - integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== - dependencies: - chownr "^2.0.0" - fs-minipass "^2.0.0" - minipass "^5.0.0" - minizlib "^2.1.1" - mkdirp "^1.0.3" - yallist "^4.0.0" - -tedious@^18.2.4: - version "18.2.4" - resolved "https://registry.yarnpkg.com/tedious/-/tedious-18.2.4.tgz#c33986f2561b4fde92bb9df70f44ae1a14f71b46" - integrity sha512-+6Nzn/aURTQ+8OxLAJ8fKK5Fbb84HRTI3bHiAC3ZzBKrBg9BHtcHxjmlIni5Zn46hzKiZ5WrDMSwDH8oIYjV8w== - dependencies: - "@azure/identity" "^4.2.1" - "@azure/keyvault-keys" "^4.4.0" - "@js-joda/core" "^5.6.1" - "@types/node" ">=18" - bl "^6.0.11" - iconv-lite "^0.6.3" - js-md4 "^0.3.2" - native-duplexpair "^1.0.0" - sprintf-js "^1.1.3" - -teeny-request@^7.1.3: - version "7.2.0" - resolved "https://registry.yarnpkg.com/teeny-request/-/teeny-request-7.2.0.tgz#41347ece068f08d741e7b86df38a4498208b2633" - integrity sha512-SyY0pek1zWsi0LRVAALem+avzMLc33MKW/JLLakdP4s9+D7+jHcy5x6P+h94g2QNZsAqQNfX5lsbd3WSeJXrrw== - dependencies: - http-proxy-agent "^5.0.0" - https-proxy-agent "^5.0.0" - node-fetch "^2.6.1" - stream-events "^1.0.5" - uuid "^8.0.0" - -term-size@^2.1.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" - integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg== - -timers-ext@^0.1.7: - version "0.1.8" - resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.8.tgz#b4e442f10b7624a29dd2aa42c295e257150cf16c" - integrity sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww== - dependencies: - es5-ext "^0.10.64" - next-tick "^1.1.0" - -to-readable-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" - integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -toidentifier@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" - integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== - -toposort-class@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/toposort-class/-/toposort-class-1.0.1.tgz#7ffd1f78c8be28c3ba45cd4e1a3f5ee193bd9988" - integrity sha512-OsLcGGbYF3rMjPUf8oKktyvCiUxSbqMMS39m33MAjLTC1DVIH6x3WSt63/M77ihI09+Sdfk1AXvfhCEeUmC7mg== - -touch@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.1.tgz#097a23d7b161476435e5c1344a95c0f75b4a5694" - integrity sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA== - -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== - -tslib@^2.2.0, tslib@^2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" - integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== - -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - -type-is@^1.6.18, type-is@^1.6.4, type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -type@^2.7.2: - version "2.7.3" - resolved "https://registry.yarnpkg.com/type/-/type-2.7.3.tgz#436981652129285cc3ba94f392886c2637ea0486" - integrity sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ== - -typed-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" - integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== - dependencies: - call-bind "^1.0.7" - es-errors "^1.3.0" - is-typed-array "^1.1.13" - -typed-array-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" - integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== - dependencies: - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" - -typed-array-byte-offset@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" - integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== - dependencies: - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" - -typed-array-length@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" - integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== - dependencies: - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" - possible-typed-array-names "^1.0.0" - -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== - dependencies: - is-typedarray "^1.0.0" - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== - -uid2@0.0.x: - version "0.0.4" - resolved "https://registry.yarnpkg.com/uid2/-/uid2-0.0.4.tgz#033f3b1d5d32505f5ce5f888b9f3b667123c0a44" - integrity sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA== - -umzug@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/umzug/-/umzug-2.3.0.tgz#0ef42b62df54e216b05dcaf627830a6a8b84a184" - integrity sha512-Z274K+e8goZK8QJxmbRPhl89HPO1K+ORFtm6rySPhFKfKc5GHhqdzD0SGhSWHkzoXasqJuItdhorSvY7/Cgflw== - dependencies: - bluebird "^3.7.2" - -unbox-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" - integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== - dependencies: - call-bind "^1.0.2" - has-bigints "^1.0.2" - has-symbols "^1.0.3" - which-boxed-primitive "^1.0.2" - -undefsafe@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c" - integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA== - -underscore@^1.13.1: - version "1.13.6" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.6.tgz#04786a1f589dc6c09f761fc5f45b89e935136441" - integrity sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A== - -undici-types@~5.26.4: - version "5.26.5" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" - integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== - -unique-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" - integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== - dependencies: - crypto-random-string "^2.0.0" - -universalify@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" - integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== - -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== - -update-notifier@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.3.tgz#be86ee13e8ce48fb50043ff72057b5bd598e1ea3" - integrity sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A== - dependencies: - boxen "^4.2.0" - chalk "^3.0.0" - configstore "^5.0.1" - has-yarn "^2.1.0" - import-lazy "^2.1.0" - is-ci "^2.0.0" - is-installed-globally "^0.3.1" - is-npm "^4.0.0" - is-yarn-global "^0.3.0" - latest-version "^5.0.0" - pupa "^2.0.1" - semver-diff "^3.1.1" - xdg-basedir "^4.0.0" - -url-parse-lax@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" - integrity sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ== - dependencies: - prepend-http "^2.0.0" - -util-deprecate@^1.0.1, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== - -utils-merge@1.0.1, utils-merge@1.x.x, utils-merge@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== - -uuid@^8.0.0, uuid@^8.3.0, uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - -validator@^13.7.0, validator@^13.9.0: - version "13.12.0" - resolved "https://registry.yarnpkg.com/validator/-/validator-13.12.0.tgz#7d78e76ba85504da3fee4fd1922b385914d4b35f" - integrity sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg== - -vary@^1, vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - -which-module@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" - integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== - -which-typed-array@^1.1.14, which-typed-array@^1.1.15: - version "1.1.15" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" - integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== - dependencies: - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.2" - -which@2.0.2, which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -wide-align@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== - dependencies: - string-width "^1.0.2 || 2" - -wide-align@^1.1.2: - version "1.1.5" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" - integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== - dependencies: - string-width "^1.0.2 || 2 || 3 || 4" - -widest-line@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" - integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== - dependencies: - string-width "^4.0.0" - -wkx@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/wkx/-/wkx-0.5.0.tgz#c6c37019acf40e517cc6b94657a25a3d4aa33e8c" - integrity sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg== - dependencies: - "@types/node" "*" - -workerpool@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.0.0.tgz#85aad67fa1a2c8ef9386a1b43539900f61d03d58" - integrity sha512-fU2OcNA/GVAJLLyKUoHkAgIhKb0JoCpSjLC/G2vYKxUjVmQwGbRVeoPJ1a8U4pnVofz4AQV5Y/NEw8oKqxEBtA== - -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" - integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== - dependencies: - ansi-styles "^3.2.0" - string-width "^3.0.0" - strip-ansi "^5.0.0" - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" - integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== - dependencies: - ansi-styles "^6.1.0" - string-width "^5.0.1" - strip-ansi "^7.0.1" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -write-file-atomic@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" - integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== - dependencies: - imurmurhash "^0.1.4" - is-typedarray "^1.0.0" - signal-exit "^3.0.2" - typedarray-to-buffer "^3.1.5" - -xdg-basedir@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" - integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== - -xtend@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - -y18n@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" - integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== - -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yaml@2.0.0-1: - version "2.0.0-1" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.0.0-1.tgz#8c3029b3ee2028306d5bcf396980623115ff8d18" - integrity sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ== - -yargs-parser@13.1.2, yargs-parser@^13.1.2: - version "13.1.2" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" - integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs-parser@^15.0.1: - version "15.0.3" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-15.0.3.tgz#316e263d5febe8b38eef61ac092b33dfcc9b1115" - integrity sha512-/MVEVjTXy/cGAjdtQf8dW3V9b97bPN7rNn8ETj6BmAQL7ibC7O1Q9SPJbGjgh3SlwoBNXMzj/ZGIj8mBgl12YA== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs-parser@^20.2.2: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - -yargs-unparser@1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.1.tgz#bd4b0ee05b4c94d058929c32cb09e3fce71d3c5f" - integrity sha512-qZV14lK9MWsGCmcr7u5oXGH0dbGqZAIxTDrWXZDo5zUr6b6iUmelNKO6x6R1dQT24AH3LgRxJpr8meWy2unolA== - dependencies: - camelcase "^5.3.1" - decamelize "^1.2.0" - flat "^4.1.0" - is-plain-obj "^1.1.0" - yargs "^14.2.3" - -yargs@13.3.2: - version "13.3.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" - integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== - dependencies: - cliui "^5.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.1.2" - -yargs@^14.2.3: - version "14.2.3" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-14.2.3.tgz#1a1c3edced1afb2a2fea33604bc6d1d8d688a414" - integrity sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg== - dependencies: - cliui "^5.0.0" - decamelize "^1.2.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^15.0.1" - -yargs@^16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - -z-schema@^5.0.1: - version "5.0.6" - resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-5.0.6.tgz#46d6a687b15e4a4369e18d6cb1c7b8618fc256c5" - integrity sha512-+XR1GhnWklYdfr8YaZv/iu+vY+ux7V5DS5zH1DQf6bO5ufrt/5cgNhVO5qyhsjFXvsqQb/f08DWE9b6uPscyAg== - dependencies: - lodash.get "^4.4.2" - lodash.isequal "^4.5.0" - validator "^13.7.0" - optionalDependencies: - commander "^10.0.0" diff --git a/docker/.gitignore b/docker/.gitignore deleted file mode 100644 index adbb97d..0000000 --- a/docker/.gitignore +++ /dev/null @@ -1 +0,0 @@ -data/ \ No newline at end of file diff --git a/docker/README.md b/docker/README.md deleted file mode 100644 index 69d1021..0000000 --- a/docker/README.md +++ /dev/null @@ -1,46 +0,0 @@ -## Description: - - The project contains the **docker folder** and the `Dockerfile`. - - The `Dockerfile` is used to Deploy the project to Google Cloud. - - The **docker folder** contains a couple of helper scripts: - -- `docker-compose.yml` (all our services: web, backend, db are described here) -- `start-backend.sh` (starts backend, but only after the database) -- `wait-for-it.sh` (imported from https://github.com/vishnubob/wait-for-it) - - > To avoid breaking the application, we recommend you don't edit the following files: everything that includes the **docker folder** and `Dokerfile`. - - - ## Run services: - - 1. Install docker compose (https://docs.docker.com/compose/install/) - - 2. Move to `docker` folder. All next steps should be done from this folder. - - ``` cd docker ``` - - 3. Make executables from `wait-for-it.sh` and `start-backend.sh`: - - ``` chmod +x start-backend.sh && chmod +x wait-for-it.sh ``` - - 4. Download dependend projects for services. - - 5. Review the docker-compose.yml file. Make sure that all services have Dockerfiles. Only db service doesn't require a Dockerfile. - - 6. Make sure you have needed ports (see them in `ports`) available on your local machine. - - 7. Start services: - - 7.1. With an empty database `rm -rf data && docker-compose up` - - 7.2. With a stored (from previus runs) database data `docker-compose up` - - 8. Check http://localhost:3000 - - 9. Stop services: - - 9.1. Just press `Ctr+C` - - diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml deleted file mode 100644 index 5a48d29..0000000 --- a/docker/docker-compose.yml +++ /dev/null @@ -1,58 +0,0 @@ - - -version: "3.9" -services: - web: - image: frontend - build: ../frontend - stdin_open: true # docker run -i - tty: true # docker run -t - ports: - - "3000:3000" - logging: - driver: json-file - options: - max-size: "10m" - max-file: "3" - db: - logging: - driver: json-file - options: - max-size: "10m" - max-file: "3" - image: postgres - volumes: - - ./data/db:/var/lib/postgresql/data - environment: - - POSTGRES_HOST_AUTH_METHOD=trust - - POSTGRES_DB=db_store_operations_hub - ports: - - "5432:5432" - logging: - driver: json-file - options: - max-size: "10m" - max-file: "3" - - backend: - image: backend - volumes: - - ./wait-for-it.sh:/usr/src/app/wait-for-it.sh - - ./start-backend.sh:/usr/src/app/start-backend.sh - build: ../backend - environment: - - DB_HOST=db - ports: - - "8080:8080" - logging: - driver: json-file - options: - max-size: "10m" - max-file: "3" - depends_on: - - "db" - - - - command: ["bash", "./wait-for-it.sh", "db:5432", "--timeout=0", "--strict", "--", "bash", "./start-backend.sh"] - diff --git a/docker/start-backend.sh b/docker/start-backend.sh deleted file mode 100644 index fb353bf..0000000 --- a/docker/start-backend.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env bash -yarn start diff --git a/docker/wait-for-it.sh b/docker/wait-for-it.sh deleted file mode 100644 index d990e0d..0000000 --- a/docker/wait-for-it.sh +++ /dev/null @@ -1,182 +0,0 @@ -#!/usr/bin/env bash -# Use this script to test if a given TCP host/port are available - -WAITFORIT_cmdname=${0##*/} - -echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi } - -usage() -{ - cat << USAGE >&2 -Usage: - $WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args] - -h HOST | --host=HOST Host or IP under test - -p PORT | --port=PORT TCP port under test - Alternatively, you specify the host and port as host:port - -s | --strict Only execute subcommand if the test succeeds - -q | --quiet Don't output any status messages - -t TIMEOUT | --timeout=TIMEOUT - Timeout in seconds, zero for no timeout - -- COMMAND ARGS Execute command with args after the test finishes -USAGE - exit 1 -} - -wait_for() -{ - if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then - echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT" - else - echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout" - fi - WAITFORIT_start_ts=$(date +%s) - while : - do - if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then - nc -z $WAITFORIT_HOST $WAITFORIT_PORT - WAITFORIT_result=$? - else - (echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1 - WAITFORIT_result=$? - fi - if [[ $WAITFORIT_result -eq 0 ]]; then - WAITFORIT_end_ts=$(date +%s) - echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds" - break - fi - sleep 1 - done - return $WAITFORIT_result -} - -wait_for_wrapper() -{ - # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692 - if [[ $WAITFORIT_QUIET -eq 1 ]]; then - timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & - else - timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & - fi - WAITFORIT_PID=$! - trap "kill -INT -$WAITFORIT_PID" INT - wait $WAITFORIT_PID - WAITFORIT_RESULT=$? - if [[ $WAITFORIT_RESULT -ne 0 ]]; then - echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT" - fi - return $WAITFORIT_RESULT -} - -# process arguments -while [[ $# -gt 0 ]] -do - case "$1" in - *:* ) - WAITFORIT_hostport=(${1//:/ }) - WAITFORIT_HOST=${WAITFORIT_hostport[0]} - WAITFORIT_PORT=${WAITFORIT_hostport[1]} - shift 1 - ;; - --child) - WAITFORIT_CHILD=1 - shift 1 - ;; - -q | --quiet) - WAITFORIT_QUIET=1 - shift 1 - ;; - -s | --strict) - WAITFORIT_STRICT=1 - shift 1 - ;; - -h) - WAITFORIT_HOST="$2" - if [[ $WAITFORIT_HOST == "" ]]; then break; fi - shift 2 - ;; - --host=*) - WAITFORIT_HOST="${1#*=}" - shift 1 - ;; - -p) - WAITFORIT_PORT="$2" - if [[ $WAITFORIT_PORT == "" ]]; then break; fi - shift 2 - ;; - --port=*) - WAITFORIT_PORT="${1#*=}" - shift 1 - ;; - -t) - WAITFORIT_TIMEOUT="$2" - if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi - shift 2 - ;; - --timeout=*) - WAITFORIT_TIMEOUT="${1#*=}" - shift 1 - ;; - --) - shift - WAITFORIT_CLI=("$@") - break - ;; - --help) - usage - ;; - *) - echoerr "Unknown argument: $1" - usage - ;; - esac -done - -if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then - echoerr "Error: you need to provide a host and port to test." - usage -fi - -WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15} -WAITFORIT_STRICT=${WAITFORIT_STRICT:-0} -WAITFORIT_CHILD=${WAITFORIT_CHILD:-0} -WAITFORIT_QUIET=${WAITFORIT_QUIET:-0} - -# Check to see if timeout is from busybox? -WAITFORIT_TIMEOUT_PATH=$(type -p timeout) -WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH) - -WAITFORIT_BUSYTIMEFLAG="" -if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then - WAITFORIT_ISBUSY=1 - # Check if busybox timeout uses -t flag - # (recent Alpine versions don't support -t anymore) - if timeout &>/dev/stdout | grep -q -e '-t '; then - WAITFORIT_BUSYTIMEFLAG="-t" - fi -else - WAITFORIT_ISBUSY=0 -fi - -if [[ $WAITFORIT_CHILD -gt 0 ]]; then - wait_for - WAITFORIT_RESULT=$? - exit $WAITFORIT_RESULT -else - if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then - wait_for_wrapper - WAITFORIT_RESULT=$? - else - wait_for - WAITFORIT_RESULT=$? - fi -fi - -if [[ $WAITFORIT_CLI != "" ]]; then - if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then - echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess" - exit $WAITFORIT_RESULT - fi - exec "${WAITFORIT_CLI[@]}" -else - exit $WAITFORIT_RESULT -fi diff --git a/frontend/.eslintignore b/frontend/.eslintignore deleted file mode 100644 index f4ef79d..0000000 --- a/frontend/.eslintignore +++ /dev/null @@ -1,3 +0,0 @@ -# Ignore generated files -build/* -next-env.d.ts diff --git a/frontend/.eslintrc.cjs b/frontend/.eslintrc.cjs deleted file mode 100644 index 590e61f..0000000 --- a/frontend/.eslintrc.cjs +++ /dev/null @@ -1,25 +0,0 @@ -module.exports = { - extends: [ - 'next/core-web-vitals', - 'plugin:@typescript-eslint/recommended', - 'eslint-config-prettier', - ], - plugins: ['import'], - settings: { - 'import/resolver': { - typescript: { - project: ['./tsconfig.json'], - }, - }, - }, - rules: { - 'react/no-children-prop': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-unused-vars': 'off', // Turned off to reduce noise - '@typescript-eslint/ban-types': 'off', - 'react-hooks/exhaustive-deps': 'off', // Turned off to reduce noise - 'import/named': 'error', - 'import/no-duplicates': 'error', - 'import/no-unresolved': 'error', - }, -}; diff --git a/frontend/.gitignore b/frontend/.gitignore deleted file mode 100644 index fdc0491..0000000 --- a/frontend/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# local.js env files -.env.local -.env.development.local -.env.test.local -.env.production.local - -# vercel -.vercel -/.idea/ diff --git a/frontend/.prettierrc b/frontend/.prettierrc deleted file mode 100644 index cedf9c7..0000000 --- a/frontend/.prettierrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "singleQuote": true, - "tabWidth": 2, - "trailingComma": "all", - "quoteProps": "as-needed", - "jsxSingleQuote": true, - "bracketSpacing": true, - "bracketSameLine": false, - "arrowParens": "always" -} diff --git a/frontend/Dockerfile b/frontend/Dockerfile deleted file mode 100644 index 56e10d0..0000000 --- a/frontend/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM node:20.15.1-alpine - -# Create app directory -WORKDIR /usr/src/app - -# Install app dependencies -# A wildcard is used to ensure both package.json AND package-lock.json are copied -# where available (npm@5+) -COPY package*.json ./ - -RUN yarn install -# If you are building your code for production -# RUN npm ci --only=production - -# Bundle app source -COPY . . - -EXPOSE 3000 -CMD [ "yarn", "dev" ] \ No newline at end of file diff --git a/frontend/LICENSE-justboil b/frontend/LICENSE-justboil deleted file mode 100644 index 798238d..0000000 --- a/frontend/LICENSE-justboil +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2019-current JustBoil.me (https://justboil.me) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/frontend/README.md b/frontend/README.md deleted file mode 100644 index 8395dcc..0000000 --- a/frontend/README.md +++ /dev/null @@ -1,92 +0,0 @@ -# Store Operations Hub - -## This project was generated by Flatlogic Platform. -## Install - -`cd` to project's dir and run `npm install` - -### Builds - -Build are handled by Next.js CLI — [Info](https://nextjs.org/docs/api-reference/cli) - -### Hot-reloads for development - -``` -npm run dev -``` - -### Builds and minifies for production - -``` -npm run build -``` - -### Exports build for static hosts - -``` -npm run export -``` - -### Lint - -``` -npm run lint -``` - -### Format with prettier - -``` -npm run format -``` - -## Support -For any additional information please refer to [Flatlogic homepage](https://flatlogic.com). - - -## To start the project with Docker: -### Description: - -The project contains the **docker folder** and the `Dockerfile`. - -The `Dockerfile` is used to Deploy the project to Google Cloud. - -The **docker folder** contains a couple of helper scripts: - -- `docker-compose.yml` (all our services: web, backend, db are described here) -- `start-backend.sh` (starts backend, but only after the database) -- `wait-for-it.sh` (imported from https://github.com/vishnubob/wait-for-it) - - > To avoid breaking the application, we recommend you don't edit the following files: everything that includes the **docker folder** and `Dokerfile`. - - - -### Run services: - -1. Install docker compose (https://docs.docker.com/compose/install/) - -2. Move to `docker` folder. All next steps should be done from this folder. - - ``` cd docker ``` - -3. Make executables from `wait-for-it.sh` and `start-backend.sh`: - - ``` chmod +x start-backend.sh && chmod +x wait-for-it.sh ``` - -4. Download dependend projects for services. - -5. Review the docker-compose.yml file. Make sure that all services have Dockerfiles. Only db service doesn't require a Dockerfile. - -6. Make sure you have needed ports (see them in `ports`) available on your local machine. - -7. Start services: - - 7.1. With an empty database `rm -rf data && docker-compose up` - - 7.2. With a stored (from previus runs) database data `docker-compose up` - -8. Check http://localhost:3000 - -9. Stop services: - - 9.1. Just press `Ctr+C` - diff --git a/frontend/next-env.d.ts b/frontend/next-env.d.ts deleted file mode 100644 index 00a8785..0000000 --- a/frontend/next-env.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -/// -/// -/// - -// NOTE: This file should not be edited -// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information. diff --git a/frontend/next.config.mjs b/frontend/next.config.mjs deleted file mode 100644 index 89767ec..0000000 --- a/frontend/next.config.mjs +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @type {import('next').NextConfig} - */ - -const output = process.env.NODE_ENV === 'production' ? 'export' : 'standalone'; - const nextConfig = { -trailingSlash: true, - distDir: 'build', - output, - basePath: "", - devIndicators: { - position: 'bottom-left', - }, - typescript: { - ignoreBuildErrors: true, - }, - eslint: { - ignoreDuringBuilds: true, - }, - images: { - unoptimized: true, - remotePatterns: [ - { - protocol: 'https', - hostname: '**', - }, - ], - }, - -} - -export default nextConfig \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json deleted file mode 100644 index 7eb7de1..0000000 --- a/frontend/package.json +++ /dev/null @@ -1,79 +0,0 @@ -{ - "private": true, - "scripts": { - "dev": "cross-env PORT=${FRONT_PORT:-3000} next dev --turbopack", - "build": "next build", - "start": "next start", - "lint": "eslint . --ext .ts,.tsx", - "format": "prettier '{components,pages,src,interfaces,hooks}/**/*.{tsx,ts,js}' --write" - }, - "dependencies": { - "@emotion/react": "^11.11.3", - "@emotion/styled": "^11.11.0", - "@mdi/js": "^7.4.47", - "@mui/material": "^6.3.0", - "@mui/x-data-grid": "^6.19.2", - "@reduxjs/toolkit": "^2.1.0", - "@tailwindcss/typography": "^0.5.13", - "@tinymce/tinymce-react": "^4.3.2", - "apexcharts": "^3.45.2", - "axios": "^1.8.4", - "chart.js": "^4.4.1", - "chroma-js": "^2.4.2", - "dayjs": "^1.11.10", - "file-saver": "^2.0.5", - "formik": "^2.4.5", - "html2canvas": "^1.4.1", - "i18next": "^25.1.2", - "i18next-browser-languagedetector": "^8.1.0", - "i18next-http-backend": "^3.0.2", - "intro.js": "^7.2.0", - "intro.js-react": "^1.0.0", - "jsonwebtoken": "^9.0.2", - "jwt-decode": "^3.1.2", - "lodash": "^4.17.21", - "moment": "^2.30.1", - "next": "15.5.12", - "next-i18next": "15.4.3", - "numeral": "^2.0.6", - "query-string": "^8.1.0", - "react": "19.0.0", - "react-apexcharts": "^1.4.1", - "react-big-calendar": "^1.10.3", - "react-chartjs-2": "^4.3.1", - "react-datepicker": "^4.10.0", - "react-dnd": "^16.0.1", - "react-dnd-html5-backend": "^16.0.1", - "react-dom": "19.0.0", - "react-i18next": "^15.5.1", - "react-redux": "^8.0.2", - "react-select": "^5.7.0", - "react-select-async-paginate": "^0.7.9", - "react-switch": "^7.0.0", - "react-toastify": "^11.0.2", - "swr": "1.3.0", - "uuid": "^9.0.0" - }, - "devDependencies": { - "@tailwindcss/forms": "^0.5.7", - "@tailwindcss/line-clamp": "^0.4.4", - "@types/node": "18.7.16", - "@types/numeral": "^2.0.2", - "@types/react-big-calendar": "^1.8.8", - "@types/react-redux": "^7.1.24", - "@typescript-eslint/eslint-plugin": "^5.37.0", - "@typescript-eslint/parser": "^5.37.0", - "autoprefixer": "^10.4.0", - "cross-env": "^7.0.3", - "eslint": "^8.23.1", - "eslint-config-next": "^13.0.4", - "eslint-config-prettier": "^8.5.0", - "eslint-import-resolver-typescript": "^3.6.1", - "eslint-plugin-import": "^2.29.1", - "postcss": "^8.4.4", - "postcss-import": "^14.1.0", - "prettier": "^3.2.4", - "tailwindcss": "^3.4.1", - "typescript": "^5.4.5" - } -} diff --git a/frontend/postcss.config.js b/frontend/postcss.config.js deleted file mode 100644 index 36f40f3..0000000 --- a/frontend/postcss.config.js +++ /dev/null @@ -1,9 +0,0 @@ -/* eslint-env node */ -module.exports = { - plugins: { - 'postcss-import': {}, - 'tailwindcss/nesting': {}, - tailwindcss: {}, - autoprefixer: {}, - } -} \ No newline at end of file diff --git a/frontend/prettier.config.js b/frontend/prettier.config.js deleted file mode 100644 index ecde36c..0000000 --- a/frontend/prettier.config.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - semi: false, - singleQuote: true, - printWidth: 100, - trailingComma: 'es5', - arrowParens: 'always', - tabWidth: 2, - useTabs: false, - quoteProps: 'as-needed', - jsxSingleQuote: false, - bracketSpacing: true, - bracketSameLine: false, -} \ No newline at end of file diff --git a/frontend/public/data-sources/clients.json b/frontend/public/data-sources/clients.json deleted file mode 100644 index 297ec7b..0000000 --- a/frontend/public/data-sources/clients.json +++ /dev/null @@ -1 +0,0 @@ -{"data":[{"id":19,"avatar":"https:\/\/avatars.dicebear.com\/v2\/gridy\/Howell-Hand.svg","login":"percy64","name":"Howell Hand","company":"Kiehn-Green","city":"Emelyside","progress":70,"created":"Mar 3, 2022","created_mm_dd_yyyy":"03-03-2022"},{"id":11,"avatar":"https:\/\/avatars.dicebear.com\/v2\/gridy\/Hope-Howe.svg","login":"dare.concepcion","name":"Hope Howe","company":"Nolan Inc","city":"Paristown","progress":68,"created":"Dec 1, 2022","created_mm_dd_yyyy":"12-01-2022"},{"id":32,"avatar":"https:\/\/avatars.dicebear.com\/v2\/gridy\/Nelson-Jerde.svg","login":"geovanni.kessler","name":"Nelson Jerde","company":"Nitzsche LLC","city":"Jailynbury","progress":49,"created":"May 18, 2022","created_mm_dd_yyyy":"05-18-2022"},{"id":22,"avatar":"https:\/\/avatars.dicebear.com\/v2\/gridy\/Kim-Weimann.svg","login":"macejkovic.dashawn","name":"Kim Weimann","company":"Brown-Lueilwitz","city":"New Emie","progress":38,"created":"May 4, 2022","created_mm_dd_yyyy":"05-04-2022"},{"id":34,"avatar":"https:\/\/avatars.dicebear.com\/v2\/gridy\/Justice-OReilly.svg","login":"hilpert.leora","name":"Justice O'Reilly","company":"Lakin-Muller","city":"New Kacie","progress":38,"created":"Mar 27, 2022","created_mm_dd_yyyy":"03-27-2022"},{"id":48,"avatar":"https:\/\/avatars.dicebear.com\/v2\/gridy\/Adrienne-Mayer-III.svg","login":"ferry.sophia","name":"Adrienne Mayer III","company":"Kozey, McLaughlin and Kuhn","city":"Howardbury","progress":39,"created":"Mar 29, 2022","created_mm_dd_yyyy":"03-29-2022"},{"id":20,"avatar":"https:\/\/avatars.dicebear.com\/v2\/gridy\/Mr.-Julien-Ebert.svg","login":"gokuneva","name":"Mr. Julien Ebert","company":"Cormier LLC","city":"South Serenaburgh","progress":29,"created":"Jun 25, 2022","created_mm_dd_yyyy":"06-25-2022"},{"id":47,"avatar":"https:\/\/avatars.dicebear.com\/v2\/gridy\/Lenna-Smitham.svg","login":"paolo.walter","name":"Lenna Smitham","company":"King Inc","city":"McCulloughfort","progress":59,"created":"Oct 8, 2022","created_mm_dd_yyyy":"10-08-2022"},{"id":24,"avatar":"https:\/\/avatars.dicebear.com\/v2\/gridy\/Travis-Davis.svg","login":"lkessler","name":"Travis Davis","company":"Leannon and Sons","city":"West Frankton","progress":52,"created":"Oct 20, 2022","created_mm_dd_yyyy":"10-20-2022"},{"id":49,"avatar":"https:\/\/avatars.dicebear.com\/v2\/gridy\/Prof.-Esteban-Steuber.svg","login":"shana.lang","name":"Prof. Esteban Steuber","company":"Langosh-Ernser","city":"East Sedrick","progress":34,"created":"May 16, 2022","created_mm_dd_yyyy":"05-16-2022"},{"id":36,"avatar":"https:\/\/avatars.dicebear.com\/v2\/gridy\/Russell-Goodwin-V.svg","login":"jewel07","name":"Russell Goodwin V","company":"Nolan-Stracke","city":"Williamsonmouth","progress":55,"created":"Apr 22, 2022","created_mm_dd_yyyy":"04-22-2022"},{"id":33,"avatar":"https:\/\/avatars.dicebear.com\/v2\/gridy\/Ms.-Cassidy-Wiegand-DVM.svg","login":"burnice.okuneva","name":"Ms. Cassidy Wiegand DVM","company":"Kuhlman-Hahn","city":"New Ruthiehaven","progress":76,"created":"Sep 16, 2022","created_mm_dd_yyyy":"09-16-2022"},{"id":44,"avatar":"https:\/\/avatars.dicebear.com\/v2\/gridy\/Mr.-Watson-Brakus-PhD.svg","login":"oconnell.juanita","name":"Mr. Watson Brakus PhD","company":"Osinski, Bins and Kuhn","city":"Lake Gloria","progress":58,"created":"Jun 22, 2022","created_mm_dd_yyyy":"06-22-2022"},{"id":46,"avatar":"https:\/\/avatars.dicebear.com\/v2\/gridy\/Mr.-Garrison-Friesen-V.svg","login":"vgutmann","name":"Mr. Garrison Friesen V","company":"VonRueden, Rippin and Pfeffer","city":"Port Cieloport","progress":39,"created":"Oct 19, 2022","created_mm_dd_yyyy":"10-19-2022"},{"id":14,"avatar":"https:\/\/avatars.dicebear.com\/v2\/gridy\/Ms.-Sister-Morar.svg","login":"veum.lucio","name":"Ms. Sister Morar","company":"Gusikowski, Altenwerth and Abbott","city":"Lake Macville","progress":34,"created":"Jun 11, 2022","created_mm_dd_yyyy":"06-11-2022"},{"id":40,"avatar":"https:\/\/avatars.dicebear.com\/v2\/gridy\/Ms.-Laisha-Reinger.svg","login":"edietrich","name":"Ms. Laisha Reinger","company":"Boehm PLC","city":"West Alexiemouth","progress":73,"created":"Nov 2, 2022","created_mm_dd_yyyy":"11-02-2022"},{"id":5,"avatar":"https:\/\/avatars.dicebear.com\/v2\/gridy\/Cameron-Lind.svg","login":"mose44","name":"Cameron Lind","company":"Tremblay, Padberg and Pouros","city":"Naderview","progress":59,"created":"Sep 14, 2022","created_mm_dd_yyyy":"09-14-2022"},{"id":43,"avatar":"https:\/\/avatars.dicebear.com\/v2\/gridy\/Sarai-Little.svg","login":"rau.abelardo","name":"Sarai Little","company":"Deckow LLC","city":"Jeanieborough","progress":49,"created":"Jun 13, 2022","created_mm_dd_yyyy":"06-13-2022"},{"id":2,"avatar":"https:\/\/avatars.dicebear.com\/v2\/gridy\/Shyann-Kautzer.svg","login":"imurazik","name":"Shyann Kautzer","company":"Osinski, Boehm and Kihn","city":"New Alvera","progress":41,"created":"Feb 15, 2022","created_mm_dd_yyyy":"02-15-2022"},{"id":15,"avatar":"https:\/\/avatars.dicebear.com\/v2\/gridy\/Lorna-Christiansen.svg","login":"annalise97","name":"Lorna Christiansen","company":"Altenwerth-Friesen","city":"Port Elbertland","progress":36,"created":"Mar 9, 2022","created_mm_dd_yyyy":"03-09-2022"}]} diff --git a/frontend/public/data-sources/history.json b/frontend/public/data-sources/history.json deleted file mode 100644 index 1cc0c82..0000000 --- a/frontend/public/data-sources/history.json +++ /dev/null @@ -1 +0,0 @@ -{"data":[{"id":1,"amount":375.53,"account":"45721474","name":"Home Loan Account","date":"3 days ago","type":"deposit","business":"Turcotte"},{"id":2,"amount":470.26,"account":"94486537","name":"Savings Account","date":"3 days ago","type":"payment","business":"Murazik - Graham"},{"id":3,"amount":971.34,"account":"63189893","name":"Checking Account","date":"5 days ago","type":"invoice","business":"Fahey - Keebler"},{"id":4,"amount":374.63,"account":"74828780","name":"Auto Loan Account","date":"7 days ago","type":"withdraw","business":"Collier - Hintz"}]} \ No newline at end of file diff --git a/frontend/public/favicon.svg b/frontend/public/favicon.svg deleted file mode 100644 index c8c4e3e..0000000 --- a/frontend/public/favicon.svg +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/frontend/public/locales/de/common.json b/frontend/public/locales/de/common.json deleted file mode 100644 index 7f2d578..0000000 --- a/frontend/public/locales/de/common.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "pages": { - "dashboard": { - "pageTitle": "Dashboard", - "overview": "Übersicht", - "loadingWidgets": "Widgets werden geladen...", - "loading": "Laden..." - }, - "login": { - "pageTitle": "Anmeldung", - - "sampleCredentialsAdmin": "Verwenden Sie {{email}} / {{password}}, um sich als Administrator anzumelden", - "sampleCredentialsUser": "Verwenden Sie {{email}} / {{password}}, um sich als Benutzer anzumelden", - - "form": { - "loginLabel": "Login", - "loginHelp": "Bitte geben Sie Ihren Login ein", - "passwordLabel": "Passwort", - "passwordHelp": "Bitte geben Sie Ihr Passwort ein", - "remember": "Angemeldet bleiben", - "forgotPassword": "Passwort vergessen?", - "loginButton": "Anmelden", - "loading": "Wird geladen...", - "noAccountYet": "Noch kein Konto?", - "newAccount": "Neues Konto" - }, - - "pexels": { - "photoCredit": "Foto von {{photographer}} auf Pexels", - "videoCredit": "Video von {{name}} auf Pexels", - "videoUnsupported": "Ihr Browser unterstützt das Video-Tag nicht." - }, - - "footer": { - "copyright": "© {{year}} {{title}}. Alle Rechte vorbehalten", - "privacy": "Datenschutzrichtlinie" - } - } - }, - "components": { - "widgetCreator": { - "title": "Diagramm oder Widget erstellen", - "helpText": "Beschreiben Sie Ihr neues Widget oder Diagramm in natürlicher Sprache. Zum Beispiel: \"Anzahl der Admin-Benutzer\" ODER \"rotes Diagramm mit der Anzahl geschlossener Verträge gruppiert nach Monat\"", - "settingsTitle": "Einstellungen für Widget Creator", - "settingsDescription": "Für welche Rolle zeigen wir Widgets an und erstellen sie?", - "doneButton": "Fertig", - "loading": "Laden..." - }, - "search": { - "placeholder": "Suche", - "required": "Pflichtfeld", - "minLength": "Mindestlänge: {{count}} Zeichen" - } - } -} diff --git a/frontend/public/locales/en/common.json b/frontend/public/locales/en/common.json deleted file mode 100644 index 8d45685..0000000 --- a/frontend/public/locales/en/common.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "pages": { - "dashboard": { - "pageTitle": "Dashboard", - "overview": "Overview", - "loadingWidgets": "Loading widgets...", - "loading": "Loading..." - }, - "login": { - "pageTitle": "Login", - - "form": { - "loginLabel": "Login", - "loginHelp": "Please enter your login", - "passwordLabel": "Password", - "passwordHelp": "Please enter your password", - "remember": "Remember", - "forgotPassword": "Forgot password?", - "loginButton": "Login", - "loading": "Loading...", - "noAccountYet": "Don’t have an account yet?", - "newAccount": "New Account" - }, - - "pexels": { - "photoCredit": "Photo by {{photographer}} on Pexels", - "videoCredit": "Video by {{name}} on Pexels", - "videoUnsupported": "Your browser does not support the video tag." - }, - - "footer": { - "copyright": "© {{year}} {{title}}. All rights reserved", - "privacy": "Privacy Policy" - } - } - }, - "components": { - "widgetCreator": { - "title": "Create Chart or Widget", - "helpText": "Describe your new widget or chart in natural language. For example: \"Number of admin users\" OR \"red chart with number of closed contracts grouped by month\"", - "settingsTitle": "Widget Creator Settings", - "settingsDescription": "What role are we showing and creating widgets for?", - "doneButton": "Done", - "loading": "Loading..." - }, - "search": { - "placeholder": "Search", - "required": "Required", - "minLength": "Minimum length: {{count}} characters" - } - } -} diff --git a/frontend/public/locales/es/common.json b/frontend/public/locales/es/common.json deleted file mode 100644 index f3421b1..0000000 --- a/frontend/public/locales/es/common.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "pages": { - "dashboard": { - "pageTitle": "Tablero", - "overview": "Resumen", - "loadingWidgets": "Cargando widgets...", - "loading": "Cargando..." - }, - "login": { - "pageTitle": "Inicio de sesión", - - "sampleCredentialsAdmin": "Use {{email}} / {{password}} para iniciar sesión como Administrador", - "sampleCredentialsUser": "Use {{email}} / {{password}} para iniciar sesión como Usuario", - - "form": { - "loginLabel": "Usuario", - "loginHelp": "Introduzca su usuario", - "passwordLabel": "Contraseña", - "passwordHelp": "Introduzca su contraseña", - "remember": "Recuérdame", - "forgotPassword": "¿Olvidó su contraseña?", - "loginButton": "Acceder", - "loading": "Cargando...", - "noAccountYet": "¿Aún no tiene una cuenta?", - "newAccount": "Crear cuenta" - }, - - "pexels": { - "photoCredit": "Foto de {{photographer}} en Pexels", - "videoCredit": "Vídeo de {{name}} en Pexels", - "videoUnsupported": "Su navegador no admite la etiqueta de vídeo." - }, - - "footer": { - "copyright": "© {{year}} {{title}}. Todos los derechos reservados", - "privacy": "Política de privacidad" - } - } - }, - "components": { - "widgetCreator": { - "title": "Crear gráfico o widget", - "helpText": "Describe tu nuevo widget o gráfico en lenguaje natural. Por ejemplo: \"Número de usuarios administradores\" O \"gráfico rojo con el número de contratos cerrados agrupados por mes\"", - "settingsTitle": "Configuración del creador de widgets", - "settingsDescription": "¿Para qué rol estamos mostrando y creando widgets?", - "doneButton": "Listo", - "loading": "Cargando..." - }, - "search": { - "placeholder": "Buscar", - "required": "Obligatorio", - "minLength": "Longitud mínima: {{count}} caracteres" - } - } -} diff --git a/frontend/public/locales/fr/common.json b/frontend/public/locales/fr/common.json deleted file mode 100644 index ecf531b..0000000 --- a/frontend/public/locales/fr/common.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "pages": { - "dashboard": { - "pageTitle": "Tableau de bord", - "overview": "Vue d'ensemble", - "loadingWidgets": "Chargement des widgets...", - "loading": "Chargement..." - }, - "login": { - "pageTitle": "Connexion", - - "sampleCredentialsAdmin": "Utilisez {{email}} / {{password}} pour vous connecter en tant qu’administrateur", - "sampleCredentialsUser": "Utilisez {{email}} / {{password}} pour vous connecter en tant qu’utilisateur", - - "form": { - "loginLabel": "Identifiant", - "loginHelp": "Veuillez saisir votre identifiant", - "passwordLabel": "Mot de passe", - "passwordHelp": "Veuillez saisir votre mot de passe", - "remember": "Se souvenir de moi", - "forgotPassword": "Mot de passe oublié ?", - "loginButton": "Se connecter", - "loading": "Chargement…", - "noAccountYet": "Vous n’avez pas encore de compte ?", - "newAccount": "Créer un compte" - }, - - "pexels": { - "photoCredit": "Photo de {{photographer}} sur Pexels", - "videoCredit": "Vidéo de {{name}} sur Pexels", - "videoUnsupported": "Votre navigateur ne prend pas en charge la balise vidéo." - }, - - "footer": { - "copyright": "© {{year}} {{title}}. Tous droits réservés", - "privacy": "Politique de confidentialité" - } - } - }, - "components": { - "widgetCreator": { - "title": "Créer un graphique ou un widget", - "helpText": "Décrivez votre nouveau widget ou graphique en langage naturel. Par exemple : \"Nombre d'utilisateurs administrateurs\" OU \"graphique rouge avec le nombre de contrats clôturés regroupés par mois\"", - "settingsTitle": "Paramètres du créateur de widget", - "settingsDescription": "Pour quel rôle affichons-nous et créons-nous des widgets ?", - "doneButton": "Terminé", - "loading": "Chargement..." - }, - "search": { - "placeholder": "Rechercher", - "required": "Champ requis", - "minLength": "Longueur minimale : {{count}} caractères" - } - } -} diff --git a/frontend/src/colors.ts b/frontend/src/colors.ts deleted file mode 100644 index 71e116a..0000000 --- a/frontend/src/colors.ts +++ /dev/null @@ -1,138 +0,0 @@ -import type { ColorButtonKey } from './interfaces' - -export const gradientBgBase = 'bg-gradient-to-tr' -export const colorBgBase = "bg-violet-50/50" -export const gradientBgPurplePink = `${gradientBgBase} from-purple-400 via-pink-500 to-red-500` -export const gradientBgViolet = `${gradientBgBase} ${colorBgBase}` -export const gradientBgDark = `${gradientBgBase} from-dark-700 via-dark-900 to-dark-800`; -export const gradientBgPinkRed = `${gradientBgBase} from-pink-400 via-red-500 to-yellow-500` - -export const colorsBgLight = { - white: 'bg-white text-black', - light: ' bg-white text-black text-black dark:bg-dark-900 dark:text-white', - contrast: 'bg-gray-800 text-white dark:bg-white dark:text-black', - success: 'bg-emerald-500 border-emerald-500 dark:bg-pavitra-blue dark:border-pavitra-blue text-white', - danger: 'bg-red-500 border-red-500 text-white', - warning: 'bg-yellow-500 border-yellow-500 text-white', - info: 'bg-blue-500 border-blue-500 dark:bg-pavitra-blue dark:border-pavitra-blue text-white', -} - -export const colorsText = { - white: 'text-black dark:text-slate-100', - light: 'text-gray-700 dark:text-slate-400', - contrast: 'dark:text-white', - success: 'text-emerald-500', - danger: 'text-red-500', - warning: 'text-yellow-500', - info: 'text-blue-500', -}; - -export const colorsOutline = { - white: [colorsText.white, 'border-gray-100'].join(' '), - light: [colorsText.light, 'border-gray-100'].join(' '), - contrast: [colorsText.contrast, 'border-gray-900 dark:border-slate-100'].join(' '), - success: [colorsText.success, 'border-emerald-500'].join(' '), - danger: [colorsText.danger, 'border-red-500'].join(' '), - warning: [colorsText.warning, 'border-yellow-500'].join(' '), - info: [colorsText.info, 'border-blue-500'].join(' '), -}; - -export const getButtonColor = ( - color: ColorButtonKey, - isOutlined: boolean, - hasHover: boolean, - isActive = false -) => { - if (color === 'void') { - return '' - } - - const colors = { - ring: { - white: 'ring-gray-200 dark:ring-gray-500', - whiteDark: 'ring-gray-200 dark:ring-dark-500', - lightDark: 'ring-gray-200 dark:ring-gray-500', - contrast: 'ring-gray-300 dark:ring-gray-400', - success: 'ring-emerald-300 dark:ring-pavitra-blue', - danger: 'ring-red-300 dark:ring-red-700', - warning: 'ring-yellow-300 dark:ring-yellow-700', - info: "ring-blue-300 dark:ring-pavitra-blue", - }, - active: { - white: 'bg-gray-100', - whiteDark: 'bg-gray-100 dark:bg-dark-800', - lightDark: 'bg-gray-200 dark:bg-slate-700', - contrast: 'bg-gray-700 dark:bg-slate-100', - success: 'bg-emerald-700 dark:bg-pavitra-blue', - danger: 'bg-red-700 dark:bg-red-600', - warning: 'bg-yellow-700 dark:bg-yellow-600', - info: 'bg-blue-700 dark:bg-pavitra-blue', - }, - bg: { - white: 'bg-white text-black', - whiteDark: 'bg-white text-black dark:bg-dark-900 dark:text-white', - lightDark: 'bg-gray-100 text-black dark:bg-slate-800 dark:text-white', - contrast: 'bg-gray-800 text-white dark:bg-white dark:text-black', - success: 'bg-emerald-600 dark:bg-pavitra-blue text-white', - danger: 'bg-red-600 text-white dark:bg-red-500 ', - warning: 'bg-yellow-600 dark:bg-yellow-500 text-white', - info: " bg-blue-600 dark:bg-pavitra-blue text-white ", - }, - bgHover: { - white: 'hover:bg-gray-100', - whiteDark: 'hover:bg-gray-100 hover:dark:bg-dark-800', - lightDark: 'hover:bg-gray-200 hover:dark:bg-slate-700', - contrast: 'hover:bg-gray-700 hover:dark:bg-slate-100', - success: - 'hover:bg-emerald-700 hover:border-emerald-700 hover:dark:bg-pavitra-blue hover:dark:border-pavitra-blue', - danger: - 'hover:bg-red-700 hover:border-red-700 hover:dark:bg-red-600 hover:dark:border-red-600', - warning: - 'hover:bg-yellow-700 hover:border-yellow-700 hover:dark:bg-yellow-600 hover:dark:border-yellow-600', - info: "hover:bg-blue-700 hover:border-blue-700 hover:dark:bg-pavitra-blue/80 hover:dark:border-pavitra-blue/80", - }, - borders: { - white: 'border-white', - whiteDark: 'border-white dark:border-dark-900', - lightDark: 'border-gray-100 dark:border-slate-800', - contrast: 'border-gray-800 dark:border-white', - success: 'border-emerald-600 dark:border-pavitra-blue', - danger: 'border-red-600 dark:border-red-500', - warning: 'border-yellow-600 dark:border-yellow-500', - info: "border-blue-600 border-blue-600 dark:border-pavitra-blue", - }, - text: { - contrast: 'dark:text-slate-100', - success: 'text-emerald-600 dark:text-pavitra-blue', - danger: 'text-red-600 dark:text-red-500', - warning: 'text-yellow-600 dark:text-yellow-500', - info: 'text-blue-600 dark:text-pavitra-blue', - }, - outlineHover: { - contrast: - 'hover:bg-gray-800 hover:text-gray-100 hover:dark:bg-slate-100 hover:dark:text-black', - success: 'hover:bg-emerald-600 hover:text-white hover:text-white hover:dark:text-white hover:dark:border-pavitra-blue', - danger: - 'hover:bg-red-600 hover:text-white hover:text-white hover:dark:text-white hover:dark:border-red-600', - warning: - 'hover:bg-yellow-600 hover:text-white hover:text-white hover:dark:text-white hover:dark:border-yellow-600', - info: "hover:bg-blue-600 hover:bg-blue-600 hover:text-white hover:dark:text-white hover:dark:border-pavitra-blue", - }, - } - - const isOutlinedProcessed = isOutlined && ['white', 'whiteDark', 'lightDark'].indexOf(color) < 0 - - const base = [colors.borders[color], colors.ring[color]] - - if (isActive) { - base.push(colors.active[color]) - } else { - base.push(isOutlinedProcessed ? colors.text[color] : colors.bg[color]) - } - - if (hasHover) { - base.push(isOutlinedProcessed ? colors.outlineHover[color] : colors.bgHover[color]) - } - - return base.join(' ') -} diff --git a/frontend/src/components/AsideMenu.tsx b/frontend/src/components/AsideMenu.tsx deleted file mode 100644 index 442dfac..0000000 --- a/frontend/src/components/AsideMenu.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import React from 'react' -import { MenuAsideItem } from '../interfaces' -import AsideMenuLayer from './AsideMenuLayer' -import OverlayLayer from './OverlayLayer' - -type Props = { - menu: MenuAsideItem[] - isAsideMobileExpanded: boolean - isAsideLgActive: boolean - onAsideLgClose: () => void -} - -export default function AsideMenu({ - isAsideMobileExpanded = false, - isAsideLgActive = false, - ...props -}: Props) { - return ( - <> - - {isAsideLgActive && } - - ) -} diff --git a/frontend/src/components/AsideMenuItem.tsx b/frontend/src/components/AsideMenuItem.tsx deleted file mode 100644 index dbb09b2..0000000 --- a/frontend/src/components/AsideMenuItem.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import React, { useEffect, useState } from 'react' -import { mdiMinus, mdiPlus } from '@mdi/js' -import BaseIcon from './BaseIcon' -import Link from 'next/link' -import { getButtonColor } from '../colors' -import AsideMenuList from './AsideMenuList' -import { MenuAsideItem } from '../interfaces' -import { useAppSelector } from '../stores/hooks' -import { useRouter } from 'next/router' - -type Props = { - item: MenuAsideItem - isDropdownList?: boolean -} - -const AsideMenuItem = ({ item, isDropdownList = false }: Props) => { - const [isLinkActive, setIsLinkActive] = useState(false) - const [isDropdownActive, setIsDropdownActive] = useState(false) - - const asideMenuItemStyle = useAppSelector((state) => state.style.asideMenuItemStyle) - const asideMenuDropdownStyle = useAppSelector((state) => state.style.asideMenuDropdownStyle) - const asideMenuItemActiveStyle = useAppSelector((state) => state.style.asideMenuItemActiveStyle) - const borders = useAppSelector((state) => state.style.borders); - const activeLinkColor = useAppSelector( - (state) => state.style.activeLinkColor, - ); - const activeClassAddon = !item.color && isLinkActive ? asideMenuItemActiveStyle : '' - - const { asPath, isReady } = useRouter() - - useEffect(() => { - if (item.href && isReady) { - const linkPathName = new URL(item.href, location.href).pathname + '/'; - const activePathname = new URL(asPath, location.href).pathname - - const activeView = activePathname.split('/')[1]; - const linkPathNameView = linkPathName.split('/')[1]; - - setIsLinkActive(linkPathNameView === activeView); - } - }, [item.href, isReady, asPath]) - - const asideMenuItemInnerContents = ( - <> - {item.icon && ( - - )} - - {item.label} - - {item.menu && ( - - )} - - ) - - const componentClass = [ - 'flex cursor-pointer py-1.5 ', - isDropdownList ? 'px-6 text-sm' : '', - item.color - ? getButtonColor(item.color, false, true) - : `${asideMenuItemStyle}`, - isLinkActive - ? `text-black ${activeLinkColor} dark:text-white dark:bg-dark-800` - : '', - ].join(' '); - - return ( -
  • - {item.withDevider &&
    } - {item.href && ( - - {asideMenuItemInnerContents} - - )} - {!item.href && ( -
    setIsDropdownActive(!isDropdownActive)}> - {asideMenuItemInnerContents} -
    - )} - {item.menu && ( - - )} -
  • - ) -} - -export default AsideMenuItem diff --git a/frontend/src/components/AsideMenuLayer.tsx b/frontend/src/components/AsideMenuLayer.tsx deleted file mode 100644 index 47ca0e4..0000000 --- a/frontend/src/components/AsideMenuLayer.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import React from 'react' -import { mdiLogout, mdiClose } from '@mdi/js' -import BaseIcon from './BaseIcon' -import AsideMenuList from './AsideMenuList' -import { MenuAsideItem } from '../interfaces' -import { useAppSelector } from '../stores/hooks' -import Link from 'next/link'; - - -type Props = { - menu: MenuAsideItem[] - className?: string - onAsideLgCloseClick: () => void -} - -export default function AsideMenuLayer({ menu, className = '', ...props }: Props) { - const corners = useAppSelector((state) => state.style.corners); - const asideStyle = useAppSelector((state) => state.style.asideStyle) - const asideBrandStyle = useAppSelector((state) => state.style.asideBrandStyle) - const asideScrollbarsStyle = useAppSelector((state) => state.style.asideScrollbarsStyle) - const darkMode = useAppSelector((state) => state.style.darkMode) - - const handleAsideLgCloseClick = (e: React.MouseEvent) => { - e.preventDefault() - props.onAsideLgCloseClick() - } - - - return ( - - ) -} diff --git a/frontend/src/components/AsideMenuList.tsx b/frontend/src/components/AsideMenuList.tsx deleted file mode 100644 index 9e33ea1..0000000 --- a/frontend/src/components/AsideMenuList.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import React from 'react' -import { MenuAsideItem } from '../interfaces' -import AsideMenuItem from './AsideMenuItem' -import {useAppSelector} from "../stores/hooks"; -import {hasPermission} from "../helpers/userPermissions"; - -type Props = { - menu: MenuAsideItem[] - isDropdownList?: boolean - className?: string -} - -export default function AsideMenuList({ menu, isDropdownList = false, className = '' }: Props) { - const { currentUser } = useAppSelector((state) => state.auth); - - if (!currentUser) return null; - - return ( -
      - {menu.map((item, index) => { - - if (!hasPermission(currentUser, item.permissions)) return null; - - return ( -
      - -
      - ) - })} -
    - ) -} diff --git a/frontend/src/components/BaseButton.tsx b/frontend/src/components/BaseButton.tsx deleted file mode 100644 index a137dc2..0000000 --- a/frontend/src/components/BaseButton.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import React from 'react' -import Link from 'next/link' -import { getButtonColor } from '../colors' -import BaseIcon from './BaseIcon' -import type { ColorButtonKey } from '../interfaces' -import { useAppSelector } from '../stores/hooks'; - -type Props = { - label?: string - icon?: string - iconSize?: string | number - href?: string - target?: string - type?: string - color?: ColorButtonKey - className?: string - iconClassName?: string - asAnchor?: boolean - small?: boolean - outline?: boolean - active?: boolean - disabled?: boolean - roundedFull?: boolean - onClick?: (e: React.MouseEvent) => void -} - -export default function BaseButton({ - label, - icon, - iconSize, - href, - target, - type, - color = 'white', - className = '', - iconClassName = '', - asAnchor = false, - small = false, - outline = false, - active = false, - disabled = false, - roundedFull = false, - onClick, -}: Props) { - const corners = useAppSelector((state) => state.style.corners); - const componentClass = [ - 'inline-flex', - 'justify-center', - 'items-center', - 'whitespace-nowrap', - 'focus:outline-none', - 'transition-colors', - 'focus:ring', - 'duration-150', - 'border', - disabled ? 'cursor-not-allowed' : 'cursor-pointer', - roundedFull ? 'rounded-full' : `${corners}`, - getButtonColor(color, outline, !disabled, active), - className, - ] - - if (!label && icon) { - componentClass.push('p-1') - } else if (small) { - componentClass.push('text-sm', roundedFull ? 'px-3 py-1' : 'p-1') - } else { - componentClass.push('py-2', roundedFull ? 'px-6' : 'px-3') - } - - if (disabled) { - componentClass.push(outline ? 'opacity-50' : 'opacity-70') - } - - const componentClassString = componentClass.join(' ') - - const componentChildren = ( - <> - {icon && } - {label && {label}} - - ) - - if (href && !disabled) { - return ( - - {componentChildren} - - ) - } - - return React.createElement( - asAnchor ? 'a' : 'button', - { className: componentClassString, type: type ?? 'button', target, disabled, onClick }, - componentChildren - ) -} diff --git a/frontend/src/components/BaseButtons.tsx b/frontend/src/components/BaseButtons.tsx deleted file mode 100644 index e81a102..0000000 --- a/frontend/src/components/BaseButtons.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { Children, cloneElement, ReactElement } from 'react'; -import type { ReactNode } from 'react'; - -type Props = { - type?: string; - mb?: string; - noWrap?: boolean; - classAddon?: string; - children?: ReactNode; - className?: string; -}; - -const BaseButtons = ({ - type = 'justify-end', - mb = '-mb-3', - classAddon = 'mr-3 last:mr-0 mb-3', - noWrap = false, - children, - className, - }: Props) => { - return ( -
    - {Children.map(children, (child: ReactElement) => - child - ? cloneElement(child as ReactElement<{ className?: string }>, { - className: `${classAddon} ${(child.props as { className?: string }).className || ''}`, - }) - : null, - )} -
    - ); -}; - -export default BaseButtons; diff --git a/frontend/src/components/BaseDivider.tsx b/frontend/src/components/BaseDivider.tsx deleted file mode 100644 index ac56fa6..0000000 --- a/frontend/src/components/BaseDivider.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react' -import { useAppSelector } from '../stores/hooks'; -type Props = { - navBar?: boolean -} - -export default function BaseDivider({ navBar = false }: Props) { - const borders = useAppSelector((state) => state.style.borders); - const classAddon = navBar - ? 'hidden lg:block lg:my-0.5 dark:border-dark-700' - : 'my-6 -mx-6 dark:border-dark-800' - - return
    -} diff --git a/frontend/src/components/BaseIcon.tsx b/frontend/src/components/BaseIcon.tsx deleted file mode 100644 index 98ec891..0000000 --- a/frontend/src/components/BaseIcon.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React, { ReactNode } from 'react' - -type Props = { - path: string - w?: string - h?: string - fill?: string; - size?: string | number | null - className?: string - children?: ReactNode -} - -export default function BaseIcon({ - path, - fill, - w = 'w-6', - h = 'h-6', - size = null, - className = '', - children, -}: Props) { - const iconSize = size ?? 16 - - return ( - - - - - {children} - - ) -} diff --git a/frontend/src/components/BigCalendar.tsx b/frontend/src/components/BigCalendar.tsx deleted file mode 100644 index a457be6..0000000 --- a/frontend/src/components/BigCalendar.tsx +++ /dev/null @@ -1,175 +0,0 @@ -import React, { useEffect, useMemo, useState, useRef } from 'react'; -import { - Calendar, - Views, - momentLocalizer, - SlotInfo, - EventProps, -} from 'react-big-calendar'; -import moment from 'moment'; -import 'react-big-calendar/lib/css/react-big-calendar.css'; -import ListActionsPopover from './ListActionsPopover'; -import Link from 'next/link'; - -import { useAppSelector } from '../stores/hooks'; -import { hasPermission } from '../helpers/userPermissions'; - - -const localizer = momentLocalizer(moment); - -type TEvent = { - id: string; - title: string; - start: Date; - end: Date; -}; - -type Props = { - events: any[]; - handleDeleteAction: (id: string) => void; - handleCreateEventAction: (slotInfo: SlotInfo) => void; - onDateRangeChange: (range: { start: string; end: string }) => void; - entityName: string; - showField: string; - pathEdit?: string; - pathView?: string; - 'start-data-key': string; - 'end-data-key': string; -}; - -const BigCalendar = ({ - events, - handleDeleteAction, - handleCreateEventAction, - onDateRangeChange, - entityName, - showField, - pathEdit, - pathView, - 'start-data-key': startDataKey, - 'end-data-key': endDataKey, - }: Props) => { - const [myEvents, setMyEvents] = useState([]); - const prevRange = useRef<{ start: string; end: string } | null>(null); - - - const currentUser = useAppSelector((state) => state.auth.currentUser); - const hasUpdatePermission = - currentUser && - hasPermission(currentUser, `UPDATE_${entityName.toUpperCase()}`); - const hasCreatePermission = - currentUser && - hasPermission(currentUser, `CREATE_${entityName.toUpperCase()}`); - - - const { defaultDate, scrollToTime } = useMemo( - () => ({ - defaultDate: new Date(), - scrollToTime: new Date(1970, 1, 1, 6), - }), - [], - ); - - useEffect(() => { - if (!events || !Array.isArray(events) || !events?.length) return; - - const formattedEvents = events.map((event) => ({ - ...event, - start: new Date(event[startDataKey]), - end: new Date(event[endDataKey]), - title: event[showField], - })); - - setMyEvents(formattedEvents); - }, [endDataKey, events, startDataKey, showField]); - - const onRangeChange = ( - range: Date[] | { start: Date; end: Date }, - ) => { - const newRange = { start: '', end: '' }; - const format = 'YYYY-MM-DDTHH:mm'; - - if (Array.isArray(range)) { - newRange.start = moment(range[0]).format(format); - newRange.end = moment(range[range.length - 1]).format(format); - } else { - newRange.start = moment(range.start).format(format); - newRange.end = moment(range.end).format(format); - } - - if (newRange.start === newRange.end) { - newRange.end = moment(newRange.end).add(1, 'days').format(format); - } - - // check if the range fits in the previous range - if ( - prevRange.current && - prevRange.current.start <= newRange.start && - prevRange.current.end >= newRange.end - ) { - return; - } - - prevRange.current = { start: newRange.start, end: newRange.end }; - onDateRangeChange(newRange); - }; - - return ( -
    - ( - - ), - }} - /> -
    - ); -}; - -const MyCustomEvent = ( - props: { - onDelete: (id: string) => void; - hasUpdatePermission: boolean; - pathEdit?: string; - pathView?: string; - } & EventProps, -) => { - const { onDelete, hasUpdatePermission, title, event, pathEdit, pathView } = props; - - return ( -
    - - {title} - - -
    - ); -}; - -export default BigCalendar; diff --git a/frontend/src/components/CardBox.tsx b/frontend/src/components/CardBox.tsx deleted file mode 100644 index 988f162..0000000 --- a/frontend/src/components/CardBox.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import React, { ReactNode } from 'react' -import CardBoxComponentBody from './CardBoxComponentBody' -import CardBoxComponentFooter from './CardBoxComponentFooter' -import { useAppSelector } from '../stores/hooks'; - -type Props = { - rounded?: string - flex?: string - className?: string - hasComponentLayout?: boolean - cardBoxClassName?: string - hasTable?: boolean - isHoverable?: boolean - isModal?: boolean - children?: ReactNode - footer?: ReactNode - isList?:boolean - id?: string; - onClick?: (e: React.MouseEvent) => void -} - -export default function CardBox({ - rounded = 'rounded', - flex = 'flex-col', - className = '', - hasComponentLayout = false, - cardBoxClassName = '', - hasTable = false, - isHoverable = false, - isList = false, - isModal = false, - children, - footer, - id ='', - onClick, -}: Props) { - const corners = useAppSelector((state) => state.style.corners); - const cardsStyle = useAppSelector((state) => state.style.cardsStyle); - const componentClass = [ - `flex dark:border-dark-700 dark:bg-dark-900`, - className, - corners !== 'rounded-full'? corners : 'rounded-3xl', - flex, - isList ? '' : `${cardsStyle}`, - hasTable ? '' : `border-dark-700 dark:border-dark-700`, - ] - - if (isHoverable) { - componentClass.push('hover:shadow-lg transition-shadow duration-500') - } - - return React.createElement( - 'div', - { className: componentClass.join(' '), onClick }, - hasComponentLayout ? ( - children - ) : ( - <> - {children} - {footer && {footer}} - - ) - ) -} diff --git a/frontend/src/components/CardBoxComponentBody.tsx b/frontend/src/components/CardBoxComponentBody.tsx deleted file mode 100644 index 4c89896..0000000 --- a/frontend/src/components/CardBoxComponentBody.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import React, { ReactNode } from 'react' - -type Props = { - noPadding?: boolean - className?: string - children?: ReactNode - id?: string -} - -export default function CardBoxComponentBody({ noPadding = false, className, children, id }: Props) { - return
    {children}
    -} diff --git a/frontend/src/components/CardBoxComponentEmpty.tsx b/frontend/src/components/CardBoxComponentEmpty.tsx deleted file mode 100644 index c71413e..0000000 --- a/frontend/src/components/CardBoxComponentEmpty.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react' - -const CardBoxComponentEmpty = () => { - return ( -
    -

    Nothing's here…

    -
    - ) -} - -export default CardBoxComponentEmpty diff --git a/frontend/src/components/CardBoxComponentFooter.tsx b/frontend/src/components/CardBoxComponentFooter.tsx deleted file mode 100644 index 4b41bba..0000000 --- a/frontend/src/components/CardBoxComponentFooter.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import React, { ReactNode } from 'react' - -type Props = { - className?: string - children?: ReactNode -} - -export default function CardBoxComponentFooter({ className, children }: Props) { - return
    {children}
    -} diff --git a/frontend/src/components/CardBoxComponentTitle.tsx b/frontend/src/components/CardBoxComponentTitle.tsx deleted file mode 100644 index 4f92def..0000000 --- a/frontend/src/components/CardBoxComponentTitle.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import React, { ReactNode } from 'react' - -type Props = { - title: string - children?: ReactNode -} - -const CardBoxComponentTitle = ({ title, children }: Props) => { - return ( -
    -

    {title}

    - {children} -
    - ) -} - -export default CardBoxComponentTitle diff --git a/frontend/src/components/CardBoxModal.tsx b/frontend/src/components/CardBoxModal.tsx deleted file mode 100644 index 27d5676..0000000 --- a/frontend/src/components/CardBoxModal.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { mdiClose } from '@mdi/js' -import { ReactNode } from 'react' -import type { ColorButtonKey } from '../interfaces' -import BaseButton from './BaseButton' -import BaseButtons from './BaseButtons' -import CardBox from './CardBox' -import CardBoxComponentTitle from './CardBoxComponentTitle' -import OverlayLayer from './OverlayLayer' - -type Props = { - title: string - buttonColor: ColorButtonKey - buttonLabel: string - isActive: boolean - children?: ReactNode - onConfirm: () => void - onCancel?: () => void -} - -const CardBoxModal = ({ - title, - buttonColor, - buttonLabel, - isActive, - children, - onConfirm, - onCancel, -}: Props) => { - if (!isActive) { - return null - } - - const footer = ( - - - {!!onCancel && } - - ) - - return ( - - - - {!!onCancel && ( - - )} - - -
    {children}
    -
    -
    - ) -} - -export default CardBoxModal diff --git a/frontend/src/components/ChartLineSample/config.ts b/frontend/src/components/ChartLineSample/config.ts deleted file mode 100644 index cacce92..0000000 --- a/frontend/src/components/ChartLineSample/config.ts +++ /dev/null @@ -1,54 +0,0 @@ -export const chartColors = { - default: { - primary: '#00D1B2', - info: '#209CEE', - danger: '#FF3860', - }, -} - -const randomChartData = (n: number) => { - const data = [] - - for (let i = 0; i < n; i++) { - data.push(Math.round(Math.random() * 200)) - } - - return data -} - -const datasetObject = (color: string, points: number) => { - return { - fill: false, - borderColor: chartColors.default[color], - borderWidth: 2, - borderDash: [], - borderDashOffset: 0.0, - pointBackgroundColor: chartColors.default[color], - pointBorderColor: 'rgba(255,255,255,0)', - pointHoverBackgroundColor: chartColors.default[color], - pointBorderWidth: 20, - pointHoverRadius: 4, - pointHoverBorderWidth: 15, - pointRadius: 4, - data: randomChartData(points), - tension: 0.5, - cubicInterpolationMode: 'default', - } -} - -export const sampleChartData = (points = 9) => { - const labels = [] - - for (let i = 1; i <= points; i++) { - labels.push(`0${i}`) - } - - return { - labels, - datasets: [ - datasetObject('primary', points), - datasetObject('info', points), - datasetObject('danger', points), - ], - } -} diff --git a/frontend/src/components/ChartLineSample/index.tsx b/frontend/src/components/ChartLineSample/index.tsx deleted file mode 100644 index c7f417b..0000000 --- a/frontend/src/components/ChartLineSample/index.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react' -import { - Chart, - LineElement, - PointElement, - LineController, - LinearScale, - CategoryScale, - Tooltip, -} from 'chart.js' -import { Line } from 'react-chartjs-2' - -Chart.register(LineElement, PointElement, LineController, LinearScale, CategoryScale, Tooltip) - -const options = { - responsive: true, - maintainAspectRatio: false, - scales: { - y: { - display: false, - }, - x: { - display: true, - }, - }, - plugins: { - legend: { - display: false, - }, - }, -} - -const ChartLineSample = ({ data }) => { - return -} - -export default ChartLineSample diff --git a/frontend/src/components/ClickOutside.tsx b/frontend/src/components/ClickOutside.tsx deleted file mode 100644 index 1673e29..0000000 --- a/frontend/src/components/ClickOutside.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import React, { useCallback, useEffect, useRef, ReactNode, MutableRefObject } from 'react'; - -interface ClickOutsideProps { - children?: ReactNode; - onClickOutside: () => void; - excludedElements: MutableRefObject[]; -} - -const ClickOutside = ({ children, onClickOutside, excludedElements }: ClickOutsideProps) => { - const wrapperRef = useRef(null); - - const handleClickOutside = useCallback( - (event) => { - if ( - wrapperRef.current && - !wrapperRef.current.contains(event.target) && - !excludedElements.some((el) => el.current.contains(event.target)) - ) { - onClickOutside(); - } - }, - [wrapperRef, onClickOutside, ...excludedElements], - ); - - useEffect(() => { - document.addEventListener('mousedown', handleClickOutside); - return () => { - document.removeEventListener('mousedown', handleClickOutside); - }; - }, [handleClickOutside]); - - return
    {children}
    ; -}; - -export default ClickOutside; diff --git a/frontend/src/components/Customers/CardCustomers.tsx b/frontend/src/components/Customers/CardCustomers.tsx deleted file mode 100644 index 904a88e..0000000 --- a/frontend/src/components/Customers/CardCustomers.tsx +++ /dev/null @@ -1,207 +0,0 @@ -import React from 'react'; -import ImageField from '../ImageField'; -import ListActionsPopover from '../ListActionsPopover'; -import { useAppSelector } from '../../stores/hooks'; -import dataFormatter from '../../helpers/dataFormatter'; -import { Pagination } from '../Pagination'; -import {saveFile} from "../../helpers/fileSaver"; -import LoadingSpinner from "../LoadingSpinner"; -import Link from 'next/link'; - -import {hasPermission} from "../../helpers/userPermissions"; - - -type Props = { - customers: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const CardCustomers = ({ - customers, - loading, - onDelete, - currentPage, - numPages, - onPageChange, -}: Props) => { - const asideScrollbarsStyle = useAppSelector( - (state) => state.style.asideScrollbarsStyle, - ); - const bgColor = useAppSelector((state) => state.style.cardsColor); - const darkMode = useAppSelector((state) => state.style.darkMode); - const corners = useAppSelector((state) => state.style.corners); - const focusRing = useAppSelector((state) => state.style.focusRingColor); - - const currentUser = useAppSelector((state) => state.auth.currentUser); - const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_CUSTOMERS') - - - return ( -
    - {loading && } -
      - {!loading && customers.map((item, index) => ( -
    • - -
      - - - {item.full_name} - - - -
      - -
      -
      -
      - - -
      -
      CustomerCode
      -
      -
      - { item.customer_code } -
      -
      -
      - - - - -
      -
      FullName
      -
      -
      - { item.full_name } -
      -
      -
      - - - - -
      -
      Email
      -
      -
      - { item.email } -
      -
      -
      - - - - -
      -
      Phone
      -
      -
      - { item.phone } -
      -
      -
      - - - - -
      -
      BillingAddress
      -
      -
      - { item.billing_address } -
      -
      -
      - - - - -
      -
      ShippingAddress
      -
      -
      - { item.shipping_address } -
      -
      -
      - - - - -
      -
      CustomerStatus
      -
      -
      - { item.customer_status } -
      -
      -
      - - - - -
      -
      RegisteredAt
      -
      -
      - { dataFormatter.dateTimeFormatter(item.registered_at) } -
      -
      -
      - - - - -
      -
      Notes
      -
      -
      - { item.notes } -
      -
      -
      - - - -
      -
    • - ))} - {!loading && customers.length === 0 && ( -
      -

      No data to display

      -
      - )} -
    -
    - -
    -
    - ); -}; - -export default CardCustomers; diff --git a/frontend/src/components/Customers/ListCustomers.tsx b/frontend/src/components/Customers/ListCustomers.tsx deleted file mode 100644 index de7be5c..0000000 --- a/frontend/src/components/Customers/ListCustomers.tsx +++ /dev/null @@ -1,152 +0,0 @@ -import React from 'react'; -import CardBox from '../CardBox'; -import ImageField from '../ImageField'; -import dataFormatter from '../../helpers/dataFormatter'; -import {saveFile} from "../../helpers/fileSaver"; -import ListActionsPopover from "../ListActionsPopover"; -import {useAppSelector} from "../../stores/hooks"; -import {Pagination} from "../Pagination"; -import LoadingSpinner from "../LoadingSpinner"; -import Link from 'next/link'; - -import {hasPermission} from "../../helpers/userPermissions"; - - -type Props = { - customers: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const ListCustomers = ({ customers, loading, onDelete, currentPage, numPages, onPageChange }: Props) => { - - const currentUser = useAppSelector((state) => state.auth.currentUser); - const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_CUSTOMERS') - - const corners = useAppSelector((state) => state.style.corners); - const bgColor = useAppSelector((state) => state.style.cardsColor); - - - return ( - <> -
    - {loading && } - {!loading && customers.map((item) => ( -
    - -
    - - dark:divide-dark-700 overflow-x-auto' - } - > - - -
    -

    CustomerCode

    -

    { item.customer_code }

    -
    - - - - -
    -

    FullName

    -

    { item.full_name }

    -
    - - - - -
    -

    Email

    -

    { item.email }

    -
    - - - - -
    -

    Phone

    -

    { item.phone }

    -
    - - - - -
    -

    BillingAddress

    -

    { item.billing_address }

    -
    - - - - -
    -

    ShippingAddress

    -

    { item.shipping_address }

    -
    - - - - -
    -

    CustomerStatus

    -

    { item.customer_status }

    -
    - - - - -
    -

    RegisteredAt

    -

    { dataFormatter.dateTimeFormatter(item.registered_at) }

    -
    - - - - -
    -

    Notes

    -

    { item.notes }

    -
    - - - - - -
    -
    -
    - ))} - {!loading && customers.length === 0 && ( -
    -

    No data to display

    -
    - )} -
    -
    - -
    - - ) -}; - -export default ListCustomers \ No newline at end of file diff --git a/frontend/src/components/Customers/TableCustomers.tsx b/frontend/src/components/Customers/TableCustomers.tsx deleted file mode 100644 index cab1b04..0000000 --- a/frontend/src/components/Customers/TableCustomers.tsx +++ /dev/null @@ -1,463 +0,0 @@ -import React, { useEffect, useState, useMemo } from 'react' -import { createPortal } from 'react-dom'; -import { ToastContainer, toast } from 'react-toastify'; -import BaseButton from '../BaseButton' -import CardBoxModal from '../CardBoxModal' -import CardBox from "../CardBox"; -import { fetch, update, deleteItem, setRefetch, deleteItemsByIds } from '../../stores/customers/customersSlice' -import { useAppDispatch, useAppSelector } from '../../stores/hooks' -import { useRouter } from 'next/router' -import { Field, Form, Formik } from "formik"; -import { - DataGrid, - GridColDef, -} from '@mui/x-data-grid'; -import {loadColumns} from "./configureCustomersCols"; -import _ from 'lodash'; -import dataFormatter from '../../helpers/dataFormatter' -import {dataGridStyles} from "../../styles"; - - - -const perPage = 10 - -const TableSampleCustomers = ({ filterItems, setFilterItems, filters, showGrid }) => { - const notify = (type, msg) => toast( msg, {type, position: "bottom-center"}); - - const dispatch = useAppDispatch(); - const router = useRouter(); - - const pagesList = []; - const [id, setId] = useState(null); - const [currentPage, setCurrentPage] = useState(0); - const [filterRequest, setFilterRequest] = React.useState(''); - const [columns, setColumns] = useState([]); - const [selectedRows, setSelectedRows] = useState([]); - const [sortModel, setSortModel] = useState([ - { - field: '', - sort: 'desc', - }, - ]); - - const { customers, loading, count, notify: customersNotify, refetch } = useAppSelector((state) => state.customers) - const { currentUser } = useAppSelector((state) => state.auth); - const focusRing = useAppSelector((state) => state.style.focusRingColor); - const bgColor = useAppSelector((state) => state.style.bgLayoutColor); - const corners = useAppSelector((state) => state.style.corners); - const numPages = Math.floor(count / perPage) === 0 ? 1 : Math.ceil(count / perPage); - for (let i = 0; i < numPages; i++) { - pagesList.push(i); - } - - const loadData = async (page = currentPage, request = filterRequest) => { - if (page !== currentPage) setCurrentPage(page); - if (request !== filterRequest) setFilterRequest(request); - const { sort, field } = sortModel[0]; - - const query = `?page=${page}&limit=${perPage}${request}&sort=${sort}&field=${field}`; - dispatch(fetch({ limit: perPage, page, query })); - }; - - useEffect(() => { - if (customersNotify.showNotification) { - notify(customersNotify.typeNotification, customersNotify.textNotification); - } - }, [customersNotify.showNotification]); - - useEffect(() => { - if (!currentUser) return; - loadData(); - }, [sortModel, currentUser]); - - useEffect(() => { - if (refetch) { - loadData(0); - dispatch(setRefetch(false)); - } - }, [refetch, dispatch]); - - const [isModalInfoActive, setIsModalInfoActive] = useState(false) - const [isModalTrashActive, setIsModalTrashActive] = useState(false) - - const handleModalAction = () => { - setIsModalInfoActive(false) - setIsModalTrashActive(false) - } - - - - - - const handleDeleteModalAction = (id: string) => { - setId(id) - setIsModalTrashActive(true) - } - const handleDeleteAction = async () => { - if (id) { - await dispatch(deleteItem(id)); - await loadData(0); - setIsModalTrashActive(false); - } - }; - - const generateFilterRequests = useMemo(() => { - let request = '&'; - filterItems.forEach((item) => { - const isRangeFilter = filters.find( - (filter) => - filter.title === item.fields.selectedField && - (filter.number || filter.date), - ); - - if (isRangeFilter) { - const from = item.fields.filterValueFrom; - const to = item.fields.filterValueTo; - if (from) { - request += `${item.fields.selectedField}Range=${from}&`; - } - if (to) { - request += `${item.fields.selectedField}Range=${to}&`; - } - } else { - const value = item.fields.filterValue; - if (value) { - request += `${item.fields.selectedField}=${value}&`; - } - } - }); - return request; - }, [filterItems, filters]); - - const deleteFilter = (value) => { - const newItems = filterItems.filter((item) => item.id !== value); - - if (newItems.length) { - setFilterItems(newItems); - } else { - loadData(0, ''); - - setFilterItems(newItems); - } - }; - - const handleSubmit = () => { - loadData(0, generateFilterRequests); - - }; - - const handleChange = (id) => (e) => { - const value = e.target.value; - const name = e.target.name; - - setFilterItems( - filterItems.map((item) => { - if (item.id !== id) return item; - if (name === 'selectedField') return { id, fields: { [name]: value } }; - - return { id, fields: { ...item.fields, [name]: value } } - }), - ); - }; - - const handleReset = () => { - setFilterItems([]); - loadData(0, ''); - - }; - - const onPageChange = (page: number) => { - loadData(page); - setCurrentPage(page); - }; - - - useEffect(() => { - if (!currentUser) return; - - loadColumns( - handleDeleteModalAction, - `customers`, - currentUser, - ).then((newCols) => setColumns(newCols)); - }, [currentUser]); - - - - const handleTableSubmit = async (id: string, data) => { - - if (!_.isEmpty(data)) { - await dispatch(update({ id, data })) - .unwrap() - .then((res) => res) - .catch((err) => { - throw new Error(err); - }); - } - }; - - const onDeleteRows = async (selectedRows) => { - await dispatch(deleteItemsByIds(selectedRows)); - await loadData(0); - }; - - const controlClasses = - 'w-full py-2 px-2 my-2 rounded dark:placeholder-gray-400 ' + - ` ${bgColor} ${focusRing} ${corners} ` + - 'dark:bg-slate-800 border'; - - - const dataGrid = ( -
    - `datagrid--row`} - rows={customers ?? []} - columns={columns} - initialState={{ - pagination: { - paginationModel: { - pageSize: 10, - }, - }, - }} - disableRowSelectionOnClick - onProcessRowUpdateError={(params) => { - console.log('Error', params); - }} - processRowUpdate={async (newRow, oldRow) => { - const data = dataFormatter.dataGridEditFormatter(newRow); - - try { - await handleTableSubmit(newRow.id, data); - return newRow; - } catch { - return oldRow; - } - }} - sortingMode={'server'} - checkboxSelection - onRowSelectionModelChange={(ids) => { - setSelectedRows(ids) - }} - onSortModelChange={(params) => { - params.length - ? setSortModel(params) - : setSortModel([{ field: '', sort: 'desc' }]); - }} - rowCount={count} - pageSizeOptions={[10]} - paginationMode={'server'} - loading={loading} - onPaginationModelChange={(params) => { - onPageChange(params.page); - }} - /> -
    - ) - - return ( - <> - {filterItems && Array.isArray( filterItems ) && filterItems.length ? - - null} - > -
    - <> - {filterItems && filterItems.map((filterItem) => { - return ( -
    -
    -
    Filter
    - - {filters.map((selectOption) => ( - - ))} - -
    - {filters.find((filter) => - filter.title === filterItem?.fields?.selectedField - )?.type === 'enum' ? ( -
    -
    - Value -
    - - - {filters.find((filter) => - filter.title === filterItem?.fields?.selectedField - )?.options?.map((option) => ( - - ))} - -
    - ) : filters.find((filter) => - filter.title === filterItem?.fields?.selectedField - )?.number ? ( -
    -
    -
    From
    - -
    -
    -
    To
    - -
    -
    - ) : filters.find( - (filter) => - filter.title === - filterItem?.fields?.selectedField - )?.date ? ( -
    -
    -
    - From -
    - -
    -
    -
    To
    - -
    -
    - ) : ( -
    -
    Contains
    - -
    - )} -
    -
    Action
    - { - deleteFilter(filterItem.id) - }} - /> -
    -
    - ) - })} -
    - - -
    - -
    -
    -
    : null - } - -

    Are you sure you want to delete this item?

    -
    - - - {dataGrid} - - - - - {selectedRows.length > 0 && - createPortal( - onDeleteRows(selectedRows)} - />, - document.getElementById('delete-rows-button'), - )} - - - ) -} - -export default TableSampleCustomers diff --git a/frontend/src/components/Customers/configureCustomersCols.tsx b/frontend/src/components/Customers/configureCustomersCols.tsx deleted file mode 100644 index 9a12754..0000000 --- a/frontend/src/components/Customers/configureCustomersCols.tsx +++ /dev/null @@ -1,206 +0,0 @@ -import React from 'react'; -import BaseIcon from '../BaseIcon'; -import { mdiEye, mdiTrashCan, mdiPencilOutline } from '@mdi/js'; -import axios from 'axios'; -import { - GridActionsCellItem, - GridRowParams, - GridValueGetterParams, -} from '@mui/x-data-grid'; -import ImageField from '../ImageField'; -import {saveFile} from "../../helpers/fileSaver"; -import dataFormatter from '../../helpers/dataFormatter' -import DataGridMultiSelect from "../DataGridMultiSelect"; -import ListActionsPopover from '../ListActionsPopover'; - -import {hasPermission} from "../../helpers/userPermissions"; - -type Params = (id: string) => void; - -export const loadColumns = async ( - onDelete: Params, - entityName: string, - - user - -) => { - async function callOptionsApi(entityName: string) { - - if (!hasPermission(user, 'READ_' + entityName.toUpperCase())) return []; - - try { - const data = await axios(`/${entityName}/autocomplete?limit=100`); - return data.data; - } catch (error) { - console.log(error); - return []; - } - } - - const hasUpdatePermission = hasPermission(user, 'UPDATE_CUSTOMERS') - - return [ - - { - field: 'customer_code', - headerName: 'CustomerCode', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'full_name', - headerName: 'FullName', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'email', - headerName: 'Email', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'phone', - headerName: 'Phone', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'billing_address', - headerName: 'BillingAddress', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'shipping_address', - headerName: 'ShippingAddress', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'customer_status', - headerName: 'CustomerStatus', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'registered_at', - headerName: 'RegisteredAt', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'dateTime', - valueGetter: (params: GridValueGetterParams) => - new Date(params.row.registered_at), - - }, - - { - field: 'notes', - headerName: 'Notes', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'actions', - type: 'actions', - minWidth: 30, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - getActions: (params: GridRowParams) => { - - return [ -
    - -
    , - ] - }, - }, - ]; -}; diff --git a/frontend/src/components/DataGridMultiSelect.tsx b/frontend/src/components/DataGridMultiSelect.tsx deleted file mode 100644 index bb82434..0000000 --- a/frontend/src/components/DataGridMultiSelect.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { GridRenderEditCellParams, useGridApiContext } from '@mui/x-data-grid'; -import React, { useEffect, useState } from 'react'; -import axios from 'axios'; -import { MenuItem, Select } from '@mui/material'; - -interface Props { - entityName: string; -} - -const DataGridMultiSelect = (props: GridRenderEditCellParams & Props) => { - const { id, value, field, entityName } = props; - const apiRef = useGridApiContext(); - const [options, setOptions] = useState([]); - - async function callApi(entityName: string) { - const data = await axios(`/${entityName}/autocomplete?limit=100`); - return data.data; - } - - useEffect(() => { - callApi(entityName).then((data) => { - setOptions(data); - }); - }, []); - - const handleChange = (event) => { - const eventValue = event.target.value; // The new value entered by the user - - const newValue = - typeof eventValue === 'string' ? value.split(',') : eventValue; - - apiRef.current.setEditCellValue({ - id, - field, - value: newValue.filter((x) => x !== ''), - }); - }; - - return ( - - ); -}; - -export default DataGridMultiSelect; diff --git a/frontend/src/components/DevModeBadge.tsx b/frontend/src/components/DevModeBadge.tsx deleted file mode 100644 index bc238c4..0000000 --- a/frontend/src/components/DevModeBadge.tsx +++ /dev/null @@ -1,150 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import useDevCompilationStatus from '../hooks/useDevCompilationStatus'; -const DevModeBadge: React.FC = () => { - const [isVisible, setIsVisible] = useState(false); - const [isCollapsed, setIsCollapsed] = useState(true); - const compilationStatus = useDevCompilationStatus(); - - const [badgeStyles, setBadgeStyles] = useState({ - position: 'fixed', - bottom: '20px', - left: '70px', - background: 'rgba(0, 0, 0, 0.85)', - color: 'white', - padding: '15px', - borderRadius: '8px', - fontFamily: 'sans-serif', - fontSize: '14px', - lineHeight: '1.5', - textAlign: 'left', - zIndex: 2147483647, - boxShadow: '0 4px 10px rgba(0, 0, 0, 0.3)', - whiteSpace: 'pre-wrap', - transition: 'width 0.3s cubic-bezier(0.25, 0.1, 0.25, 1), padding 0.3s ease-in-out, opacity 0.3s ease-in-out, background-color 0.3s ease-in-out', // Improved transition for width - opacity: 0, - pointerEvents: 'none', - width: '340px', - maxWidth: '340px', - height: 'auto', - overflow: 'hidden', - cursor: 'pointer', - }); - - const fullText = `🚧 Your app is running in development mode. -Current request is compiling and may take a few moments. - -💡 Tip: Set up a stable environment to run your app in production mode—pages will load instantly without compilation delays.`; - - const collapsedText = '🚧 DEV stage'; - - useEffect(() => { - if (compilationStatus === 'ready') { - setIsCollapsed(true); - } else { - setIsCollapsed(false); - } - - }, [compilationStatus]); - - useEffect(() => { - if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'dev_stage') { - setIsVisible(true); - - setBadgeStyles(prev => ({ - ...prev, - opacity: 1, - width: '120px', - maxWidth: '120px', - padding: '6px 10px', - borderRadius: '18px', - whiteSpace: 'nowrap', - fontSize: '12px', - cursor: 'pointer', - pointerEvents: 'auto', - })); - - } else { - setIsVisible(false); - setBadgeStyles(prev => ({ ...prev, opacity: 0 })); - } - }, []); - - useEffect(() => { - if (!isVisible) return; - - if (isCollapsed) { - setBadgeStyles(prev => ({ - ...prev, - width: '140px', - maxWidth: '160px', - padding: '6px 20px', - borderRadius: '18px', - whiteSpace: 'nowrap', - fontSize: '12px', - })); - } else { - setBadgeStyles(prev => ({ - ...prev, - width: '340px', - maxWidth: '340px', - padding: '15px', - borderRadius: '8px', - whiteSpace: 'pre-wrap', - fontSize: '14px', - })); - } - }, [isCollapsed, isVisible]); - - const handleToggleCollapse = (e: React.MouseEvent) => { - e.stopPropagation(); - setIsCollapsed(prev => !prev); - }; - - if (!isVisible) { - return null; - } - - return ( -
    - - - {!isCollapsed && ( -
    - {fullText} -
    - )} - {isCollapsed && ( -
    - {collapsedText} -
    - )} -
    - ); -}; - -export default DevModeBadge; diff --git a/frontend/src/components/DragDropFilePicker.tsx b/frontend/src/components/DragDropFilePicker.tsx deleted file mode 100644 index 821570d..0000000 --- a/frontend/src/components/DragDropFilePicker.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import React, { ChangeEvent, useEffect, useState } from 'react'; -import BaseIcon from './BaseIcon'; -import { mdiFileUploadOutline } from '@mdi/js'; - -type Props = { - file: File | null; - setFile: (file: File) => void; - formats?: string; -}; - -const DragDropFilePicker = ({ file, setFile, formats = '' }: Props) => { - const [highlight, setHighlight] = useState(false); - const [errorMessage, setErrorMessage] = useState(''); - const fileInput = React.createRef(); - - useEffect(() => { - if (!file && fileInput) fileInput.current.value = ''; - }, [file, fileInput]); - - function onFilesAdded(files: FileList | null) { - if (files && files[0]) { - const newFile = files[0]; - const fileExtension = newFile.name.split('.').pop().toLowerCase(); - - if (formats.includes(fileExtension) || !formats) { - setFile(newFile); - setErrorMessage(''); - } else { - setErrorMessage(`Allowed formats: ${formats}`); - } - } - } - - function onDragOver(e) { - e.preventDefault(); - setHighlight(true); - } - - function onDragLeave() { - setHighlight(false); - } - - function onDrop(e) { - e.preventDefault(); - - const files = e.dataTransfer.files; - - onFilesAdded(files); - setHighlight(false); - } - - const onClear = () => { - setFile(null); - setErrorMessage(''); - }; - - return ( -
    - -
    - ); -}; - -export default DragDropFilePicker; diff --git a/frontend/src/components/ErrorBoundary.tsx b/frontend/src/components/ErrorBoundary.tsx deleted file mode 100644 index 93b2833..0000000 --- a/frontend/src/components/ErrorBoundary.tsx +++ /dev/null @@ -1,218 +0,0 @@ -import React, { Component, ErrorInfo, ReactNode } from 'react'; -import { mdiAlertCircle } from '@mdi/js'; -import BaseIcon from './BaseIcon'; - -// Define the props and state interfaces -interface ErrorBoundaryProps { - children: ReactNode; -} - -interface ErrorBoundaryState { - hasError: boolean; - error: Error | null; - errorInfo: ErrorInfo | null; - showStack: boolean; -} - -// Class-based ErrorBoundary Component -class ErrorBoundary extends Component { - constructor(props: ErrorBoundaryProps) { - super(props); - - // Define state variables - this.state = { - hasError: false, - error: null, - errorInfo: null, - showStack: false, - }; - } - - static getDerivedStateFromError(error: Error): Partial { - // Update state so the next render will show the fallback UI - return { - hasError: true, - error: error, - }; - } - - componentDidUpdate( - prevProps: Readonly, - prevState: Readonly, - snapshot?: any, - ) { - if (process.env.NODE_ENV !== 'production') { - console.log('componentDidUpdate'); - } - } - - async componentWillUnmount() { - if (process.env.NODE_ENV !== 'production') { - console.log('componentWillUnmount'); - const response = await fetch('/api/logError', { - method: 'DELETE', - }); - - const data = await response.json(); - console.log('Error logs cleared:', data); - } - } - - async componentDidCatch(error: Error, errorInfo: ErrorInfo) { - // Update state with error details (always needed for UI) - this.setState({ - errorInfo: errorInfo, - }); - - // Only perform logging in non-production environments - if (process.env.NODE_ENV !== 'production') { - console.log('Error caught in boundary:', error, errorInfo); - - // Function to log errors to the server - const logErrorToServer = async () => { - try { - const response = await fetch('/api/logError', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - message: error.message, - stack: errorInfo.componentStack, - }), - }); - - const data = await response.json(); - console.log('Error logged:', data); - } catch (err) { - console.error('Failed to log error:', err); - } - }; - - // Function to fetch logged errors (optional) - const fetchLoggedErrors = async () => { - try { - const response = await fetch('/api/logError'); - const data = await response.json(); - console.log('Fetched logs:', data); - } catch (err) { - console.error('Failed to fetch logs:', err); - } - }; - - await logErrorToServer(); - await fetchLoggedErrors(); - } - } - - toggleStack = () => { - this.setState((prevState) => ({ - showStack: !prevState.showStack, - })); - }; - - resetError = () => { - this.setState({ - hasError: false, - error: null, - errorInfo: null, - showStack: false, - }); - }; - - tryAgain = async () => { - // Only clear error logs in non-production environments - if (process.env.NODE_ENV !== 'production') { - try { - const response = await fetch('/api/logError', { - method: 'DELETE', - }); - - const data = await response.json(); - console.log('Error logs cleared:', data); - } catch (e) { - console.error('Failed to clear error logs:', e); - } - } - - // Always reset the error state (needed for UI recovery) - this.setState({ hasError: false }); - }; - - render() { - if (this.state.hasError) { - // Extract error details - const { error, errorInfo, showStack } = this.state; - const errorMessage = error?.message || 'An unexpected error occurred'; - const stackTrace = - errorInfo?.componentStack || error?.stack || 'No stack trace available'; - - return ( -
    -
    -
    -
    - -
    - -
    -

    - Something went wrong -

    -

    - We're sorry, but we encountered an unexpected error. -

    -
    - -
    -

    - {errorMessage} -

    - -
    - - - {showStack && ( -
    -                      {stackTrace}
    -                    
    - )} -
    -
    - -
    - - - -
    -
    -
    -
    - ); - } - - return this.props.children; - } -} - -export default ErrorBoundary; diff --git a/frontend/src/components/FooterBar.tsx b/frontend/src/components/FooterBar.tsx deleted file mode 100644 index 0acc9c5..0000000 --- a/frontend/src/components/FooterBar.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import React, { ReactNode } from 'react' -import { containerMaxW } from '../config' -import Logo from './Logo' - -type Props = { - children?: ReactNode -} - -export default function FooterBar({ children }: Props) { - const year = new Date().getFullYear() - - return ( - - ) -} diff --git a/frontend/src/components/FormCheckRadio.tsx b/frontend/src/components/FormCheckRadio.tsx deleted file mode 100644 index 7a9bc31..0000000 --- a/frontend/src/components/FormCheckRadio.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { ReactNode } from 'react' - -type Props = { - children: ReactNode - type: 'checkbox' | 'radio' | 'switch' - label?: string - className?: string -} - -const FormCheckRadio = (props: Props) => { - return ( - - ) -} - -export default FormCheckRadio diff --git a/frontend/src/components/FormCheckRadioGroup.tsx b/frontend/src/components/FormCheckRadioGroup.tsx deleted file mode 100644 index 90d98e0..0000000 --- a/frontend/src/components/FormCheckRadioGroup.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { Children, cloneElement, ReactElement, ReactNode } from 'react' - -type Props = { - isColumn?: boolean - children: ReactNode -} - -const FormCheckRadioGroup = (props: Props) => { - return ( -
    - {Children.map(props.children, (child: ReactElement) => - cloneElement(child as ReactElement<{ className?: string }>, { - className: `mr-6 mb-3 last:mr-0 ${(child.props as { className?: string }).className || ''}`, - }), - )} -
    - ) -} - -export default FormCheckRadioGroup diff --git a/frontend/src/components/FormField.tsx b/frontend/src/components/FormField.tsx deleted file mode 100644 index 988ac39..0000000 --- a/frontend/src/components/FormField.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import { Children, cloneElement, ReactElement, ReactNode } from 'react' -import BaseIcon from './BaseIcon' -import { useAppSelector } from '../stores/hooks'; - -type Props = { - label?: string - labelFor?: string - help?: string - icons?: string[] | null[] - isBorderless?: boolean - isTransparent?: boolean - hasTextareaHeight?: boolean - children: ReactNode - disabled?: boolean - borderButtom?: boolean - diversity?: boolean - websiteBg?: boolean -} - -const FormField = ({ icons = [], ...props }: Props) => { - const childrenCount = Children.count(props.children) - const bgColor = useAppSelector((state) => state.style.cardsColor); - const focusRing = useAppSelector((state) => state.style.focusRingColor); - const corners = useAppSelector((state) => state.style.corners); - const bgWebsiteColor = useAppSelector((state) => state.style.bgLayoutColor); - let elementWrapperClass = '' - - switch (childrenCount) { - case 2: - elementWrapperClass = 'grid grid-cols-1 gap-3 md:grid-cols-2' - break - case 3: - elementWrapperClass = 'grid grid-cols-1 gap-3 md:grid-cols-3' - } - - const controlClassName = [ - `px-3 py-2 max-w-full border-gray-300 dark:border-dark-700 ${corners} w-full dark:placeholder-gray-400`, - `${focusRing}`, - props.hasTextareaHeight ? 'h-24' : 'h-12', - props.isBorderless ? 'border-0' : 'border', - props.isTransparent ? 'bg-transparent' : `${props.websiteBg ? ` bg-white` : bgColor} dark:bg-dark-800`, - props.disabled ? 'bg-gray-200 text-gray-100 dark:bg-dark-900 disabled' : '', - props.borderButtom ? `border-0 border-b ${props.diversity ? "border-gray-400" : " placeholder-white border-gray-300/10 border-white "} rounded-none focus:ring-0` : '', - ].join(' '); - - return ( -
    - {props.label && ( - - )} -
    - {Children.map(props.children, (child: ReactElement, index) => ( -
    - {cloneElement(child as ReactElement<{ className?: string }>, { - className: `${controlClassName} ${icons[index] ? 'pl-10' : ''}`, - })} - {icons[index] && ( - - )} -
    - ))} -
    - {props.help && ( -
    {props.help}
    - )} -
    - ) -} - -export default FormField diff --git a/frontend/src/components/FormFilePicker.tsx b/frontend/src/components/FormFilePicker.tsx deleted file mode 100644 index 4302edd..0000000 --- a/frontend/src/components/FormFilePicker.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import {useEffect, useState} from 'react'; -import { ColorButtonKey } from '../interfaces'; -import BaseButton from './BaseButton'; -import FileUploader from "./Uploaders/UploadService"; -import { mdiReload } from '@mdi/js'; -import { useAppSelector } from '../stores/hooks'; - -type Props = { - label?: string; - icon?: string; - accept?: string; - color: ColorButtonKey; - isRoundIcon?: boolean; - path: string; - schema: object; - field: any; - form: any; -}; - -const FormFilePicker = ({ label, icon, accept, color, isRoundIcon, path, - schema, - form, - field, }: Props) => { - const [file, setFile] = useState(null); - const [loading, setLoading] = useState(false); - const corners = useAppSelector((state) => state.style.corners); - const bgColor = useAppSelector((state) => state.style.cardsColor); - let cornersRight; - if (corners === 'rounded'){ - cornersRight = 'rounded-r' - } else if (corners === 'rounded-lg'){ - cornersRight = 'rounded-r-lg' - }else if (corners === 'rounded-full'){ - cornersRight = 'rounded-r-3xl' - }else{ - cornersRight = '' - } - - useEffect(() => { - if (field.value) { - setFile(field.value[0]); - } - }, [field.value]); - const handleFileChange = async (event) => { - const file = event.currentTarget.files[0]; - setFile(file); - - FileUploader.validate(file, schema); - setLoading(true); - const remoteFile = await FileUploader.upload(path, file, schema); - - form.setFieldValue(field.name, [{ ...remoteFile }]); - setLoading(false); - }; - - const showFilename = !isRoundIcon && file; - - return ( -
    - - {showFilename && !loading && ( -
    - - {file.name} - -
    - )} -
    - ); -}; - -export default FormFilePicker; diff --git a/frontend/src/components/FormImagePicker.tsx b/frontend/src/components/FormImagePicker.tsx deleted file mode 100644 index 7bc34ae..0000000 --- a/frontend/src/components/FormImagePicker.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { useState, useEffect } from 'react'; -import { ColorButtonKey } from '../interfaces'; -import BaseButton from './BaseButton'; -import ImagesUploader from "./Uploaders/ImagesUploader"; -import FileUploader from './Uploaders/UploadService'; -import { mdiReload } from '@mdi/js'; -import { useAppSelector } from '../stores/hooks'; - -type Props = { - label?: string; - icon?: string; - accept?: string; - color: ColorButtonKey; - isRoundIcon?: boolean; - path: string; - schema: object; - field: any, - form: any, -}; - -const FormImagePicker = ({ label, icon, accept, color, isRoundIcon, path, schema, form, field }: Props) => { - const [file, setFile] = useState(null); - const [loading, setLoading] = useState(false); - const corners = useAppSelector((state) => state.style.corners); - const bgColor = useAppSelector((state) => state.style.cardsColor); - let cornersRight; - if (corners === 'rounded'){ - cornersRight = 'rounded-r' - } else if (corners === 'rounded-lg'){ - cornersRight = 'rounded-r-lg' - }else if (corners === 'rounded-full'){ - cornersRight = 'rounded-r-3xl' - }else{ - cornersRight = '' - } - - useEffect(() => { - if(field.value) { - setFile(field.value[0]) - } - }, [field.value]) - const handleFileChange = async (event) => { - const file = event.currentTarget.files[0] - setFile(file); - - FileUploader.validate(file, schema); - setLoading(true); - const remoteFile = await FileUploader.upload(path, file, schema); - - form.setFieldValue(field.name, [{...remoteFile}]); - setLoading(false); - }; - - const showFilename = !isRoundIcon && file; - - return ( -
    - - {showFilename && !loading && ( -
    - - {file.name} - -
    - )} -
    - ); -}; - -export default FormImagePicker; diff --git a/frontend/src/components/IconRounded.tsx b/frontend/src/components/IconRounded.tsx deleted file mode 100644 index fc45023..0000000 --- a/frontend/src/components/IconRounded.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import React from 'react' -import { ColorKey } from '../interfaces' -import { colorsBgLight, colorsText } from '../colors' -import BaseIcon from './BaseIcon' - -type Props = { - icon: string - color: ColorKey - w?: string - h?: string - bg?: boolean - className?: string -} - -export default function IconRounded({ - icon, - color, - w = 'w-12', - h = 'h-12', - bg = false, - className = '', -}: Props) { - const classAddon = bg ? colorsBgLight[color] : `${colorsText[color]} bg-gray-50 dark:bg-slate-800` - - return ( - - ) -} diff --git a/frontend/src/components/ImageField.tsx b/frontend/src/components/ImageField.tsx deleted file mode 100644 index 7ad5b55..0000000 --- a/frontend/src/components/ImageField.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* eslint-disable @next/next/no-img-element */ -// Why disabled: -// avatars.dicebear.com provides svg avatars -// next/image needs dangerouslyAllowSVG option for that - -import React, { ReactNode } from 'react'; -import { mdiImageOutline } from '@mdi/js'; -import BaseIcon from './BaseIcon'; - -type Props = { - name: string; - image?: object | null; - api?: string; - className?: string; - imageClassName?: string; - children?: ReactNode; -}; - -export default function ImageField({ - name, - image, - className = '', - imageClassName = '', - children, - }: Props) { - const imageSrc = image && image[0] ? `${image[0].publicUrl}` : ''; - - return ( -
    - {imageSrc ? ( - {name} - ) : ( -
    - -
    - )} - - {children} -
    - ); -} \ No newline at end of file diff --git a/frontend/src/components/IntroGuide.tsx b/frontend/src/components/IntroGuide.tsx deleted file mode 100644 index e19f6a9..0000000 --- a/frontend/src/components/IntroGuide.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import React from 'react'; -import { Steps, Hints } from 'intro.js-react'; -import { useRouter } from 'next/router'; -interface IntroGuideProps { - steps: Array<{ - element: string; - intro: string; - position?: string; - }>; - disableInteraction?: boolean; - stepsEnabled: boolean; - stepsName: string; - onExit: () => void; -} - -const IntroGuide: React.FC = ({ - steps, - stepsEnabled, - onExit, - stepsName -}) => { - const router = useRouter(); - const handleStepChange = (stepIndex: number ) => { - - if (stepIndex === 7 && stepsName === 'appSteps') { - onExit(); - router.push('/users/users-list/'); - } else if (stepIndex === 2 && stepsName === 'usersSteps') { - onExit(); - router.push('/roles/roles-list/'); - } - }; - - const handleExit = () => { - localStorage.setItem(`completed_${stepsName}`, 'true'); - onExit(); - }; - return ( - <> - - - ); -}; - -export default IntroGuide; \ No newline at end of file diff --git a/frontend/src/components/KanbanBoard/KanbanBoard.tsx b/frontend/src/components/KanbanBoard/KanbanBoard.tsx deleted file mode 100644 index 84954b8..0000000 --- a/frontend/src/components/KanbanBoard/KanbanBoard.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import React from 'react'; -import KanbanColumn from './KanbanColumn'; -import { AsyncThunk } from '@reduxjs/toolkit'; -import { DndProvider } from 'react-dnd'; -import { HTML5Backend } from 'react-dnd-html5-backend'; - -type Props = { - columns: Array<{id: string, label: string}>; - filtersQuery: string; - entityName: string; - columnFieldName: string; - showFieldName: string; - deleteThunk: AsyncThunk; - updateThunk: AsyncThunk; -}; - -const KanbanBoard = ({ - columns, - entityName, - columnFieldName, - filtersQuery, - showFieldName, - deleteThunk, - updateThunk, -}: Props) => { - return ( -
    - - {columns.map((column) => ( -
    - -
    - ))} -
    -
    - ); -}; - -export default KanbanBoard; diff --git a/frontend/src/components/KanbanBoard/KanbanCard.tsx b/frontend/src/components/KanbanBoard/KanbanCard.tsx deleted file mode 100644 index 7655572..0000000 --- a/frontend/src/components/KanbanBoard/KanbanCard.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import React from 'react'; -import Link from 'next/link'; -import moment from 'moment'; -import ListActionsPopover from '../ListActionsPopover'; -import { DragSourceMonitor, useDrag } from 'react-dnd'; - -type Props = { - item: any; - column: { id: string; label: string }; - entityName: string; - showFieldName: string; - setItemIdToDelete: (id: string) => void; -}; - -const KanbanCard = ({ - item, - entityName, - showFieldName, - setItemIdToDelete, - column, - }: Props) => { - const [{ isDragging }, drag] = useDrag( - () => ({ - type: 'box', - item: { item, column }, - collect: (monitor: DragSourceMonitor) => ({ - isDragging: monitor.isDragging(), - }), - }), - [item], - ); - - return ( -
    -
    - - {item[showFieldName] ?? 'No data'} - -
    -
    -

    {moment(item.createdAt).format('MMM DD hh:mm a')}

    - setItemIdToDelete(id)} - hasUpdatePermission={true} - className={'w-2 h-2 text-white'} - iconClassName={'w-5'} - /> -
    -
    - ); -}; - -export default KanbanCard; diff --git a/frontend/src/components/KanbanBoard/KanbanColumn.tsx b/frontend/src/components/KanbanBoard/KanbanColumn.tsx deleted file mode 100644 index 425a0d3..0000000 --- a/frontend/src/components/KanbanBoard/KanbanColumn.tsx +++ /dev/null @@ -1,209 +0,0 @@ -import React, { useCallback, useEffect, useRef, useState } from 'react'; -import { useAppDispatch, useAppSelector } from '../../stores/hooks'; -import Axios from 'axios'; -import CardBox from '../CardBox'; -import CardBoxModal from '../CardBoxModal'; -import { AsyncThunk } from '@reduxjs/toolkit'; -import { useDrop } from 'react-dnd'; -import KanbanCard from './KanbanCard'; - -type Props = { - column: { id: string; label: string }; - entityName: string; - columnFieldName: string; - showFieldName: string; - filtersQuery: any; - deleteThunk: AsyncThunk; - updateThunk: AsyncThunk; -}; - -type DropResult = { - sourceColumn: { id: string; label: string }; - item: any; -}; - -const perPage = 10; - -const KanbanColumn = ({ - column, - entityName, - columnFieldName, - showFieldName, - filtersQuery, - deleteThunk, - updateThunk, - }: Props) => { - const [currentPage, setCurrentPage] = useState(0); - const [count, setCount] = useState(0); - const [data, setData] = useState(null); - const [loading, setLoading] = useState(false); - const [itemIdToDelete, setItemIdToDelete] = useState(''); - const currentUser = useAppSelector((state) => state.auth.currentUser); - const listInnerRef = useRef(null); - const dispatch = useAppDispatch(); - - const [{ dropResult }, drop] = useDrop< - { - item: any; - column: { - id: string; - label: string; - }; - }, - unknown, - { - dropResult: DropResult; - } - >( - () => ({ - accept: 'box', - drop: ({ - item, - column: sourceColumn, - }: { - item: any; - column: { id: string; label: string }; - }) => { - if (sourceColumn.id === column.id) return; - - dispatch( - updateThunk({ - id: item.id, - data: { - [columnFieldName]: column.id, - }, - }), - ).then((res) => { - setData((prevState) => (prevState ? [...prevState, item] : [item])); - setCount((prevState) => prevState + 1); - }); - - return { sourceColumn, item }; - }, - collect: (monitor) => ({ - dropResult: monitor.getDropResult(), - }), - }), - [], - ); - - const loadData = useCallback( - (page: number, filters = '') => { - const query = `?page=${page}&limit=${perPage}&field=createdAt&sort=desc&${columnFieldName}=${column.id}&${filters}`; - setLoading(true); - Axios.get(`${entityName}${query}`) - .then((res) => { - setData((prevState) => - page === 0 ? res.data.rows : [...prevState, ...res.data.rows], - ); - setCount(res.data.count); - setCurrentPage(page); - }) - .catch((err) => { - console.error(err); - }) - .finally(() => { - setLoading(false); - }); - }, - [currentUser, column], - ); - - useEffect(() => { - if (!currentUser) return; - loadData(0, filtersQuery); - }, [currentUser, loadData, filtersQuery]); - - useEffect(() => { - loadData(0, filtersQuery); - }, [loadData, filtersQuery]); - - useEffect(() => { - if (dropResult?.sourceColumn && dropResult.sourceColumn.id === column.id) { - setData((prevState) => - prevState.filter((item) => item.id !== dropResult.item.id), - ); - setCount((prevState) => prevState - 1); - } - }, [dropResult]); - - const onScroll = () => { - if (listInnerRef.current) { - const { scrollTop, scrollHeight, clientHeight } = listInnerRef.current; - if (Math.floor(scrollTop + clientHeight) === scrollHeight) { - if (data.length < count && !loading) { - loadData(currentPage + 1, filtersQuery); - } - } - } - }; - - const onDeleteConfirm = () => { - if (!itemIdToDelete) return; - - dispatch(deleteThunk(itemIdToDelete)) - .then((res) => { - if (res.meta.requestStatus === 'fulfilled') { - setItemIdToDelete(''); - loadData(0, filtersQuery); - } - }) - .catch((err) => { - console.error(err); - }) - .finally(() => { - setItemIdToDelete(''); - }); - }; - - return ( - <> - -
    -

    {column.label}

    -

    {count}

    -
    -
    { - drop(node); - listInnerRef.current = node; - }} - className={'p-3 space-y-3 flex-1 overflow-y-auto max-h-[400px]'} - onScroll={onScroll} - > - {data?.map((item) => ( -
    - -
    - ))} - {!data?.length && ( -

    No data

    - )} -
    -
    - setItemIdToDelete('')} - > -

    Are you sure you want to delete this item?

    -
    - - ); -}; - -export default KanbanColumn; diff --git a/frontend/src/components/LanguageSwitcher.tsx b/frontend/src/components/LanguageSwitcher.tsx deleted file mode 100644 index f2f373a..0000000 --- a/frontend/src/components/LanguageSwitcher.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import Select, { components, SingleValueProps, OptionProps } from 'react-select'; - -type LanguageOption = { label: string; value: string }; - -const LANGS: LanguageOption[] = [ - { value: 'en', label: '🇬🇧 EN' }, - { value: 'fr', label: '🇫🇷 FR' }, - { value: 'es', label: '🇪🇸 ES' }, - { value: 'de', label: '🇩🇪 DE' }, -]; - -const Option = (props: OptionProps) => ( - - {props.data.label} - -); - -const SingleVal = (props: SingleValueProps) => ( - - {props.data.label} - -); - -const LanguageSwitcher: React.FC = () => { - const [mounted, setMounted] = useState(false); - const [selected, setSelected] = useState(LANGS[0]); - - useEffect(() => { - setMounted(true); - }, []); - - const handleChange = (opt: LanguageOption | null) => { - if (!opt) return; - setSelected(opt); - }; - - if (!mounted) return null; - - return ( -
    - - - ); - - return ( -
    - {readonly || (max && fileList().length >= max) - ? null - : uploadButton} - - {valuesArr() && valuesArr().length ? ( -
    - {valuesArr().map((item) => { - return ( -
    - - - {item.name} - - - {!readonly && ( - - )} -
    - ); - })} -
    - ) : null} -
    - ) -} - -FilesUploader.propTypes = { - readonly: PropTypes.bool, - path: PropTypes.string, - max: PropTypes.number, - schema: PropTypes.shape({ - image: PropTypes.bool, - size: PropTypes.number, - formats: PropTypes.arrayOf(PropTypes.string), - }), - value: PropTypes.any, - onChange: PropTypes.func, -}; - -export default FilesUploader; diff --git a/frontend/src/components/Uploaders/ImagesUploader.js b/frontend/src/components/Uploaders/ImagesUploader.js deleted file mode 100644 index 725abe7..0000000 --- a/frontend/src/components/Uploaders/ImagesUploader.js +++ /dev/null @@ -1,237 +0,0 @@ -import React, { useState, useRef } from 'react'; -import PropTypes from 'prop-types'; -import Button from '@mui/material/Button'; -import CloseIcon from '@mui/icons-material/Close'; -import SearchIcon from '@mui/icons-material/Search'; -import Grid from '@mui/material/Grid'; -import Box from '@mui/material/Box'; -import Dialog from '@mui/material/Dialog'; -import FileUploader from 'components/FormItems/uploaders/UploadService'; -import Errors from '../../../components/FormItems/error/errors'; -import {makeStyles} from "@mui/styles"; - -const useStyles = makeStyles({ - actionButtonsWrapper: { - position: 'relative', - }, - previewContent: { - padding: '0px !important', - }, - imageItem: { - '&.MuiGrid-root': { - margin: 10, - boxShadow: '2px 2px 8px 0 rgb(0 0 0 / 40%)', - borderRadius: 10, - }, - height: '100px', - }, - actionButtons: { - position: 'absolute', - bottom: 5, - right: 4, - }, - previewContainer: { - '& button': { - position: 'absolute', - top: 10, - right: 10, - '& svg': { - height: 50, - width: 50, - fill: '#FFF', - stroke: '#909090', - strokeWidth: 0.5, - }, - }, - }, - button: { - padding: '0px !important', - minWidth: '45px !important', - '& svg': { - height: 36, - width: 36, - fill: '#FFF', - stroke: '#909090', - strokeWidth: 0.5, - }, - } -}); - -const ImagesUploader = (props) => { - const classes = useStyles(); - const { value, onChange, schema, path, max, readonly, name } = props; - - const [loading, setLoading] = useState(false); - const [showPreview, setShowPreview] = useState(false); - const [imageMeta, setImageMeta] = useState({ - imageSrc: null, - imageAlt: null, - }); - const inputElement = useRef(null); - - const valuesArr = () => { - if (!value) { - return []; - } - return Array.isArray(value) ? value : [value]; - }; - - const fileList = () => { - return valuesArr().map((item) => ({ - uid: item.id || undefined, - name: item.name, - status: 'done', - url: item.publicUrl, - })); - }; - - const handleRemove = (id) => { - onChange(valuesArr().filter((item) => item.id !== id)); - }; - - const handleChange = async (event) => { - try { - const files = event.target.files; - - if (!files || !files.length) { - return; - } - - let file = files[0]; - - FileUploader.validate(file, schema); - - setLoading(true); - - file = await FileUploader.upload(path, file, schema); - - inputElement.current.value = ''; - setLoading(false); - onChange([...valuesArr(), file]); - } catch (error) { - inputElement.current.value = ''; - console.log('error', error); - setLoading(false); - Errors.showMessage(error); - } - }; - - const doPreviewImage = (image) => { - setImageMeta({ - imageSrc: image.publicUrl, - imageAlt: image.name, - }); - setShowPreview(true); - }; - - const doCloseImageModal = () => { - setImageMeta({ - imageSrc: null, - imageAlt: null, - }); - setShowPreview(false); - }; - - const uploadButton = ( - - - - ); - - return ( - - {readonly || (max && fileList().length >= max) ? null : uploadButton} - - {valuesArr() && valuesArr().length ? ( - - {valuesArr().map((item) => { - return ( - - {item.name} - -
    -
    - - {!readonly && ( - - )} -
    -
    -
    - ); - })} -
    - ) : null} - - - {imageMeta.imageAlt} - -
    - ); -}; - -ImagesUploader.propTypes = { - readonly: PropTypes.bool, - path: PropTypes.string, - max: PropTypes.number, - schema: PropTypes.shape({ - image: PropTypes.bool, - size: PropTypes.number, - formats: PropTypes.arrayOf(PropTypes.string), - }), - value: PropTypes.any, - onChange: PropTypes.func, - name: PropTypes.string, -}; - -export default ImagesUploader; diff --git a/frontend/src/components/Uploaders/UploadService.js b/frontend/src/components/Uploaders/UploadService.js deleted file mode 100644 index 33620a6..0000000 --- a/frontend/src/components/Uploaders/UploadService.js +++ /dev/null @@ -1,79 +0,0 @@ -import { v4 as uuidv4 } from 'uuid'; -import Axios from "axios"; -import {baseURLApi} from "../../config"; - -function extractExtensionFrom(filename) { - if (!filename) { - return null; - } - - const regex = /(?:\.([^.]+))?$/; - return regex.exec(filename)[1]; -} - -export default class FileUploader { - static validate(file, schema) { - if (!schema) { - return; - } - - if (schema.image) { - if (!file.type.startsWith("image")) { - throw new Error("You must upload an image"); - } - } - - if (schema.size && file.size > schema.size) { - throw new Error("File is too big."); - } - - const extension = extractExtensionFrom(file.name); - - if (schema.formats && !schema.formats.includes(extension)) { - throw new Error("Invalid format"); - } - } - - static async upload(path, file, schema) { - try { - this.validate(file, schema); - } catch (error) { - return Promise.reject(error); - } - - const extension = extractExtensionFrom(file.name); - const id = uuidv4(); - const filename = `${id}.${extension}`; - const privateUrl = `${path}/${filename}`; - - const publicUrl = await this.uploadToServer(file, path, filename); - - return { - id: id, - name: file.name, - sizeInBytes: file.size, - privateUrl, - publicUrl, - new: true, - }; - } - - static async uploadToServer(file, path, filename) { - const formData = new FormData(); - formData.append("file", file); - formData.append("filename", filename); - const uri = `/file/upload/${path}`; - await Axios.post(uri, formData, { - headers: { - "Content-Type": "multipart/form-data", - }, - }); - - const privateUrl = `${path}/${filename}`; - - console.log("process.env.NODE_ENV in uploadToServer function", process.env.NODE_ENV); - console.log("baseURLApi in uploadToServer function", baseURLApi); - - return `${baseURLApi}/file/download?privateUrl=${privateUrl}`; - } -} diff --git a/frontend/src/components/UserAvatar.tsx b/frontend/src/components/UserAvatar.tsx deleted file mode 100644 index 257ebdb..0000000 --- a/frontend/src/components/UserAvatar.tsx +++ /dev/null @@ -1,46 +0,0 @@ -/* eslint-disable @next/next/no-img-element */ -// Why disabled: -// avatars.dicebear.com provides svg avatars -// next/image needs dangerouslyAllowSVG option for that - -import React, { ReactNode } from 'react'; -import BaseIcon from "./BaseIcon"; -import {mdiAccountCircleOutline} from "@mdi/js"; - -type Props = { - username: string; - avatar?: string | null; - image?: object | null; - api?: string; - className?: string; - children?: ReactNode; -}; - -export default function UserAvatar({ - username, - image, - avatar, - className = '', - children, - }: Props) { - - const avatarImage = (image && image[0]) ? `${image[0].publicUrl}` : '#'; - - return ( -
    - {avatarImage === "#" - ? - : {username} - } - {children} -
    - ); -} diff --git a/frontend/src/components/UserAvatarCurrentUser.tsx b/frontend/src/components/UserAvatarCurrentUser.tsx deleted file mode 100644 index 7bfc768..0000000 --- a/frontend/src/components/UserAvatarCurrentUser.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React, {ReactNode, useEffect, useState} from 'react'; -import { useAppSelector } from '../stores/hooks'; -import UserAvatar from './UserAvatar'; - -type Props = { - className?: string; - children?: ReactNode; -}; - -export default function UserAvatarCurrentUser({ - className = '', - children, - }: Props) { - const userName = useAppSelector((state) => state.main.userName); - const userAvatar = useAppSelector((state) => state.main.userAvatar); - const { currentUser, isFetching, token } = useAppSelector( - (state) => state.auth, - ); - const { users, loading } = useAppSelector((state) => state.users); - - const [ avatar, setAvatar ] = useState(null) - - useEffect(() => { - currentUserAvatarCheck() - }, []); - - useEffect(() => { - currentUserAvatarCheck() - }, [currentUser?.id, users]); - - const currentUserAvatarCheck = () => { - if (currentUser?.id) { - const image = currentUser?.avatar; - setAvatar(image); - } - } - - return ( - - {children} - - ); -} diff --git a/frontend/src/components/UserCard.tsx b/frontend/src/components/UserCard.tsx deleted file mode 100644 index a81e8a2..0000000 --- a/frontend/src/components/UserCard.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { mdiCheckDecagram } from '@mdi/js' -import { Field, Form, Formik } from 'formik' -import { useAppSelector } from '../stores/hooks' -import CardBox from './CardBox' -import FormCheckRadio from './FormCheckRadio' -import UserAvatarCurrentUser from './UserAvatarCurrentUser' - -type Props = { - className?: string -} - -const UserCard = ({ className }: Props) => { - const userName = useAppSelector((state) => state.main.userName) - - return ( - -
    - -
    -
    - alert(JSON.stringify(values, null, 2))} - > -
    - - - -
    -
    -
    -

    - Howdy, {userName}! -

    -

    - Last login 12 mins ago from 127.0.0.1 -

    -
    - Verified -
    -
    -
    -
    - ) -} - -export default UserCard diff --git a/frontend/src/components/Users/CardUsers.tsx b/frontend/src/components/Users/CardUsers.tsx deleted file mode 100644 index 115e00c..0000000 --- a/frontend/src/components/Users/CardUsers.tsx +++ /dev/null @@ -1,208 +0,0 @@ -import React from 'react'; -import ImageField from '../ImageField'; -import ListActionsPopover from '../ListActionsPopover'; -import { useAppSelector } from '../../stores/hooks'; -import dataFormatter from '../../helpers/dataFormatter'; -import { Pagination } from '../Pagination'; -import {saveFile} from "../../helpers/fileSaver"; -import LoadingSpinner from "../LoadingSpinner"; -import Link from 'next/link'; - -import {hasPermission} from "../../helpers/userPermissions"; - - -type Props = { - users: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const CardUsers = ({ - users, - loading, - onDelete, - currentPage, - numPages, - onPageChange, -}: Props) => { - const asideScrollbarsStyle = useAppSelector( - (state) => state.style.asideScrollbarsStyle, - ); - const bgColor = useAppSelector((state) => state.style.cardsColor); - const darkMode = useAppSelector((state) => state.style.darkMode); - const corners = useAppSelector((state) => state.style.corners); - const focusRing = useAppSelector((state) => state.style.focusRingColor); - - const currentUser = useAppSelector((state) => state.auth.currentUser); - const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_USERS') - - - return ( -
    - {loading && } -
      - {!loading && users.map((item, index) => ( -
    • - -
      - - - -

      {item.firstName}

      - - - -
      - -
      -
      -
      - - -
      -
      First Name
      -
      -
      - { item.firstName } -
      -
      -
      - - - - -
      -
      Last Name
      -
      -
      - { item.lastName } -
      -
      -
      - - - - -
      -
      Phone Number
      -
      -
      - { item.phoneNumber } -
      -
      -
      - - - - -
      -
      E-Mail
      -
      -
      - { item.email } -
      -
      -
      - - - - -
      -
      Disabled
      -
      -
      - { dataFormatter.booleanFormatter(item.disabled) } -
      -
      -
      - - - - -
      -
      Avatar
      -
      -
      - -
      -
      -
      - - - - -
      -
      App Role
      -
      -
      - { dataFormatter.rolesOneListFormatter(item.app_role) } -
      -
      -
      - - - - -
      -
      Custom Permissions
      -
      -
      - { dataFormatter.permissionsManyListFormatter(item.custom_permissions).join(', ')} -
      -
      -
      - - - -
      -
    • - ))} - {!loading && users.length === 0 && ( -
      -

      No data to display

      -
      - )} -
    -
    - -
    -
    - ); -}; - -export default CardUsers; diff --git a/frontend/src/components/Users/ListUsers.tsx b/frontend/src/components/Users/ListUsers.tsx deleted file mode 100644 index d410bff..0000000 --- a/frontend/src/components/Users/ListUsers.tsx +++ /dev/null @@ -1,155 +0,0 @@ -import React from 'react'; -import CardBox from '../CardBox'; -import ImageField from '../ImageField'; -import dataFormatter from '../../helpers/dataFormatter'; -import {saveFile} from "../../helpers/fileSaver"; -import ListActionsPopover from "../ListActionsPopover"; -import {useAppSelector} from "../../stores/hooks"; -import {Pagination} from "../Pagination"; -import LoadingSpinner from "../LoadingSpinner"; -import Link from 'next/link'; - -import {hasPermission} from "../../helpers/userPermissions"; - - -type Props = { - users: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const ListUsers = ({ users, loading, onDelete, currentPage, numPages, onPageChange }: Props) => { - - const currentUser = useAppSelector((state) => state.auth.currentUser); - const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_USERS') - - const corners = useAppSelector((state) => state.style.corners); - const bgColor = useAppSelector((state) => state.style.cardsColor); - - - return ( - <> -
    - {loading && } - {!loading && users.map((item) => ( -
    - -
    - - - - dark:divide-dark-700 overflow-x-auto' - } - > - - -
    -

    First Name

    -

    { item.firstName }

    -
    - - - - -
    -

    Last Name

    -

    { item.lastName }

    -
    - - - - -
    -

    Phone Number

    -

    { item.phoneNumber }

    -
    - - - - -
    -

    E-Mail

    -

    { item.email }

    -
    - - - - -
    -

    Disabled

    -

    { dataFormatter.booleanFormatter(item.disabled) }

    -
    - - - - -
    -

    Avatar

    - -
    - - - - -
    -

    App Role

    -

    { dataFormatter.rolesOneListFormatter(item.app_role) }

    -
    - - - - -
    -

    Custom Permissions

    -

    { dataFormatter.permissionsManyListFormatter(item.custom_permissions).join(', ')}

    -
    - - - - - -
    -
    -
    - ))} - {!loading && users.length === 0 && ( -
    -

    No data to display

    -
    - )} -
    -
    - -
    - - ) -}; - -export default ListUsers \ No newline at end of file diff --git a/frontend/src/components/Users/TableUsers.tsx b/frontend/src/components/Users/TableUsers.tsx deleted file mode 100644 index bef1b7f..0000000 --- a/frontend/src/components/Users/TableUsers.tsx +++ /dev/null @@ -1,463 +0,0 @@ -import React, { useEffect, useState, useMemo } from 'react' -import { createPortal } from 'react-dom'; -import { ToastContainer, toast } from 'react-toastify'; -import BaseButton from '../BaseButton' -import CardBoxModal from '../CardBoxModal' -import CardBox from "../CardBox"; -import { fetch, update, deleteItem, setRefetch, deleteItemsByIds } from '../../stores/users/usersSlice' -import { useAppDispatch, useAppSelector } from '../../stores/hooks' -import { useRouter } from 'next/router' -import { Field, Form, Formik } from "formik"; -import { - DataGrid, - GridColDef, -} from '@mui/x-data-grid'; -import {loadColumns} from "./configureUsersCols"; -import _ from 'lodash'; -import dataFormatter from '../../helpers/dataFormatter' -import {dataGridStyles} from "../../styles"; - - - -const perPage = 10 - -const TableSampleUsers = ({ filterItems, setFilterItems, filters, showGrid }) => { - const notify = (type, msg) => toast( msg, {type, position: "bottom-center"}); - - const dispatch = useAppDispatch(); - const router = useRouter(); - - const pagesList = []; - const [id, setId] = useState(null); - const [currentPage, setCurrentPage] = useState(0); - const [filterRequest, setFilterRequest] = React.useState(''); - const [columns, setColumns] = useState([]); - const [selectedRows, setSelectedRows] = useState([]); - const [sortModel, setSortModel] = useState([ - { - field: '', - sort: 'desc', - }, - ]); - - const { users, loading, count, notify: usersNotify, refetch } = useAppSelector((state) => state.users) - const { currentUser } = useAppSelector((state) => state.auth); - const focusRing = useAppSelector((state) => state.style.focusRingColor); - const bgColor = useAppSelector((state) => state.style.bgLayoutColor); - const corners = useAppSelector((state) => state.style.corners); - const numPages = Math.floor(count / perPage) === 0 ? 1 : Math.ceil(count / perPage); - for (let i = 0; i < numPages; i++) { - pagesList.push(i); - } - - const loadData = async (page = currentPage, request = filterRequest) => { - if (page !== currentPage) setCurrentPage(page); - if (request !== filterRequest) setFilterRequest(request); - const { sort, field } = sortModel[0]; - - const query = `?page=${page}&limit=${perPage}${request}&sort=${sort}&field=${field}`; - dispatch(fetch({ limit: perPage, page, query })); - }; - - useEffect(() => { - if (usersNotify.showNotification) { - notify(usersNotify.typeNotification, usersNotify.textNotification); - } - }, [usersNotify.showNotification]); - - useEffect(() => { - if (!currentUser) return; - loadData(); - }, [sortModel, currentUser]); - - useEffect(() => { - if (refetch) { - loadData(0); - dispatch(setRefetch(false)); - } - }, [refetch, dispatch]); - - const [isModalInfoActive, setIsModalInfoActive] = useState(false) - const [isModalTrashActive, setIsModalTrashActive] = useState(false) - - const handleModalAction = () => { - setIsModalInfoActive(false) - setIsModalTrashActive(false) - } - - - - - - const handleDeleteModalAction = (id: string) => { - setId(id) - setIsModalTrashActive(true) - } - const handleDeleteAction = async () => { - if (id) { - await dispatch(deleteItem(id)); - await loadData(0); - setIsModalTrashActive(false); - } - }; - - const generateFilterRequests = useMemo(() => { - let request = '&'; - filterItems.forEach((item) => { - const isRangeFilter = filters.find( - (filter) => - filter.title === item.fields.selectedField && - (filter.number || filter.date), - ); - - if (isRangeFilter) { - const from = item.fields.filterValueFrom; - const to = item.fields.filterValueTo; - if (from) { - request += `${item.fields.selectedField}Range=${from}&`; - } - if (to) { - request += `${item.fields.selectedField}Range=${to}&`; - } - } else { - const value = item.fields.filterValue; - if (value) { - request += `${item.fields.selectedField}=${value}&`; - } - } - }); - return request; - }, [filterItems, filters]); - - const deleteFilter = (value) => { - const newItems = filterItems.filter((item) => item.id !== value); - - if (newItems.length) { - setFilterItems(newItems); - } else { - loadData(0, ''); - - setFilterItems(newItems); - } - }; - - const handleSubmit = () => { - loadData(0, generateFilterRequests); - - }; - - const handleChange = (id) => (e) => { - const value = e.target.value; - const name = e.target.name; - - setFilterItems( - filterItems.map((item) => { - if (item.id !== id) return item; - if (name === 'selectedField') return { id, fields: { [name]: value } }; - - return { id, fields: { ...item.fields, [name]: value } } - }), - ); - }; - - const handleReset = () => { - setFilterItems([]); - loadData(0, ''); - - }; - - const onPageChange = (page: number) => { - loadData(page); - setCurrentPage(page); - }; - - - useEffect(() => { - if (!currentUser) return; - - loadColumns( - handleDeleteModalAction, - `users`, - currentUser, - ).then((newCols) => setColumns(newCols)); - }, [currentUser]); - - - - const handleTableSubmit = async (id: string, data) => { - delete data?.password; - if (!_.isEmpty(data)) { - await dispatch(update({ id, data })) - .unwrap() - .then((res) => res) - .catch((err) => { - throw new Error(err); - }); - } - }; - - const onDeleteRows = async (selectedRows) => { - await dispatch(deleteItemsByIds(selectedRows)); - await loadData(0); - }; - - const controlClasses = - 'w-full py-2 px-2 my-2 rounded dark:placeholder-gray-400 ' + - ` ${bgColor} ${focusRing} ${corners} ` + - 'dark:bg-slate-800 border'; - - - const dataGrid = ( -
    - `datagrid--row`} - rows={users ?? []} - columns={columns} - initialState={{ - pagination: { - paginationModel: { - pageSize: 10, - }, - }, - }} - disableRowSelectionOnClick - onProcessRowUpdateError={(params) => { - console.log('Error', params); - }} - processRowUpdate={async (newRow, oldRow) => { - const data = dataFormatter.dataGridEditFormatter(newRow); - - try { - await handleTableSubmit(newRow.id, data); - return newRow; - } catch { - return oldRow; - } - }} - sortingMode={'server'} - checkboxSelection - onRowSelectionModelChange={(ids) => { - setSelectedRows(ids) - }} - onSortModelChange={(params) => { - params.length - ? setSortModel(params) - : setSortModel([{ field: '', sort: 'desc' }]); - }} - rowCount={count} - pageSizeOptions={[10]} - paginationMode={'server'} - loading={loading} - onPaginationModelChange={(params) => { - onPageChange(params.page); - }} - /> -
    - ) - - return ( - <> - {filterItems && Array.isArray( filterItems ) && filterItems.length ? - - null} - > -
    - <> - {filterItems && filterItems.map((filterItem) => { - return ( -
    -
    -
    Filter
    - - {filters.map((selectOption) => ( - - ))} - -
    - {filters.find((filter) => - filter.title === filterItem?.fields?.selectedField - )?.type === 'enum' ? ( -
    -
    - Value -
    - - - {filters.find((filter) => - filter.title === filterItem?.fields?.selectedField - )?.options?.map((option) => ( - - ))} - -
    - ) : filters.find((filter) => - filter.title === filterItem?.fields?.selectedField - )?.number ? ( -
    -
    -
    From
    - -
    -
    -
    To
    - -
    -
    - ) : filters.find( - (filter) => - filter.title === - filterItem?.fields?.selectedField - )?.date ? ( -
    -
    -
    - From -
    - -
    -
    -
    To
    - -
    -
    - ) : ( -
    -
    Contains
    - -
    - )} -
    -
    Action
    - { - deleteFilter(filterItem.id) - }} - /> -
    -
    - ) - })} -
    - - -
    - -
    -
    -
    : null - } - -

    Are you sure you want to delete this item?

    -
    - - - {dataGrid} - - - - - {selectedRows.length > 0 && - createPortal( - onDeleteRows(selectedRows)} - />, - document.getElementById('delete-rows-button'), - )} - - - ) -} - -export default TableSampleUsers diff --git a/frontend/src/components/Users/configureUsersCols.tsx b/frontend/src/components/Users/configureUsersCols.tsx deleted file mode 100644 index 37cebd3..0000000 --- a/frontend/src/components/Users/configureUsersCols.tsx +++ /dev/null @@ -1,207 +0,0 @@ -import React from 'react'; -import BaseIcon from '../BaseIcon'; -import { mdiEye, mdiTrashCan, mdiPencilOutline } from '@mdi/js'; -import axios from 'axios'; -import { - GridActionsCellItem, - GridRowParams, - GridValueGetterParams, -} from '@mui/x-data-grid'; -import ImageField from '../ImageField'; -import {saveFile} from "../../helpers/fileSaver"; -import dataFormatter from '../../helpers/dataFormatter' -import DataGridMultiSelect from "../DataGridMultiSelect"; -import ListActionsPopover from '../ListActionsPopover'; - -import {hasPermission} from "../../helpers/userPermissions"; - -type Params = (id: string) => void; - -export const loadColumns = async ( - onDelete: Params, - entityName: string, - - user - -) => { - async function callOptionsApi(entityName: string) { - - if (!hasPermission(user, 'READ_' + entityName.toUpperCase())) return []; - - try { - const data = await axios(`/${entityName}/autocomplete?limit=100`); - return data.data; - } catch (error) { - console.log(error); - return []; - } - } - - const hasUpdatePermission = hasPermission(user, 'UPDATE_USERS') - - return [ - - { - field: 'firstName', - headerName: 'First Name', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'lastName', - headerName: 'Last Name', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'phoneNumber', - headerName: 'Phone Number', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'email', - headerName: 'E-Mail', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'disabled', - headerName: 'Disabled', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'boolean', - - }, - - { - field: 'avatar', - headerName: 'Avatar', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - editable: false, - sortable: false, - renderCell: (params: GridValueGetterParams) => ( - - ), - - }, - - { - field: 'app_role', - headerName: 'App Role', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - sortable: false, - type: 'singleSelect', - getOptionValue: (value: any) => value?.id, - getOptionLabel: (value: any) => value?.label, - valueOptions: await callOptionsApi('roles'), - valueGetter: (params: GridValueGetterParams) => - params?.value?.id ?? params?.value, - - }, - - { - field: 'custom_permissions', - headerName: 'Custom Permissions', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - editable: false, - sortable: false, - type: 'singleSelect', - valueFormatter: ({ value }) => - dataFormatter.permissionsManyListFormatter(value).join(', '), - renderEditCell: (params) => ( - - ), - - }, - - { - field: 'actions', - type: 'actions', - minWidth: 30, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - getActions: (params: GridRowParams) => { - - return [ -
    - -
    , - ] - }, - }, - ]; -}; diff --git a/frontend/src/components/WidgetCreator/RoleSelect.tsx b/frontend/src/components/WidgetCreator/RoleSelect.tsx deleted file mode 100644 index 7cc095c..0000000 --- a/frontend/src/components/WidgetCreator/RoleSelect.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import React, { useEffect, useId, useState } from 'react'; -import { AsyncPaginate } from 'react-select-async-paginate'; -import axios from 'axios'; - -export const RoleSelect = ({ options, field, form, itemRef, disabled, currentUser }) => { - const [value, setValue] = useState(null); - const PAGE_SIZE = 100; - - React.useEffect(() => { - if (currentUser.app_role.id) { - setValue({ value: currentUser.app_role.id, label: currentUser.app_role.name }); - } - }, [currentUser]); - - useEffect(() => { - if (options?.value && options?.label) { - setValue({ value: options.value, label: options.label }); - } - }, [options?.id, field?.value?.id]); - - const mapResponseToValuesAndLabels = (data) => ({ - value: data.id, - label: data.label, - }); - const handleChange = (option) => { - form.setFieldValue(field.name, option); - setValue(option); - }; - - async function callApi(inputValue: string, loadedOptions: any[]) { - const path = `/${itemRef}/autocomplete?limit=${PAGE_SIZE}&offset=${loadedOptions.length}${inputValue ? `&query=${inputValue}` : ''}`; - const { data } = await axios(path); - return { - options: data.map(mapResponseToValuesAndLabels), - hasMore: data.length === PAGE_SIZE, - } - } - return ( - 'px-1 py-2', - }} - classNamePrefix={'react-select'} - instanceId={useId()} - value={value} - debounceTimeout={1000} - loadOptions={callApi} - onChange={handleChange} - defaultOptions - isDisabled={disabled} - /> - ); -}; diff --git a/frontend/src/components/WidgetCreator/WidgetCreator.tsx b/frontend/src/components/WidgetCreator/WidgetCreator.tsx deleted file mode 100644 index 80b4999..0000000 --- a/frontend/src/components/WidgetCreator/WidgetCreator.tsx +++ /dev/null @@ -1,140 +0,0 @@ -import CardBox from '../CardBox'; -import { mdiCog } from '@mdi/js'; -import { Field, Form, Formik } from 'formik'; -import { ToastContainer, toast } from 'react-toastify'; -import FormField from '../FormField'; -import React from 'react'; -import { - aiPrompt, - setErrorNotification, - resetNotify, -} from '../../stores/openAiSlice'; -import { useAppDispatch, useAppSelector } from '../../stores/hooks'; - -import { fetchWidgets } from '../../stores/roles/rolesSlice'; - -import BaseButton from '../BaseButton'; -import CardBoxModal from '../CardBoxModal'; -import { RoleSelect } from './RoleSelect'; - -export const WidgetCreator = ({ - currentUser, - isFetchingQuery, - setWidgetsRole, - widgetsRole, - }) => { - const dispatch = useAppDispatch(); - const [isModalOpen, setIsModalOpen] = React.useState(false); - const { notify: openAiNotify } = useAppSelector((state) => state.openAi); - - const notify = (type, msg) => toast(msg, { type, position: 'bottom-center' }); - React.useEffect(() => { - if (openAiNotify.showNotification) { - notify(openAiNotify.typeNotification, openAiNotify.textNotification); - dispatch(resetNotify()); - } - }, [openAiNotify.showNotification]); - - const openModal = (): void => { - setIsModalOpen(true); - }; - - const handleCloseModal = (value = {}) => { - setWidgetsRole(value); - setIsModalOpen(false); - }; - - const getWidgets = async () => { - await dispatch(fetchWidgets(widgetsRole?.role?.value || '')); - }; - - const smartSearch = async (values: { description: string }, resetForm: any) => { - const description = values.description; - const projectId = ''; - - const payload = { - roleId: widgetsRole?.role?.value, - description, - projectId, - userId: currentUser?.id, - }; - const { payload: responcePayload, error }: any = await dispatch(aiPrompt(payload)); - - await getWidgets().then(); - - resetForm({ values: { description: '' } }); - if (responcePayload.data?.error || error) { - const errorMessage = - responcePayload.data?.error?.message || error?.message; - await dispatch( - setErrorNotification(errorMessage || 'Error with widget creation'), - ); - } - }; - - return ( - <> - - - smartSearch(values, resetForm)} - > -
    - - - -
    -
    -
    - handleCloseModal(values)} - > - {({ submitForm }) => ( - setIsModalOpen(false)} - > -

    What role are we showing and creating widgets for?

    - -
    - - - -
    -
    - )} -
    - - - ); -}; diff --git a/frontend/src/config.ts b/frontend/src/config.ts deleted file mode 100644 index a9783c8..0000000 --- a/frontend/src/config.ts +++ /dev/null @@ -1,15 +0,0 @@ -export const hostApi = process.env.NODE_ENV === 'development' && !process.env.NEXT_PUBLIC_BACK_API ? 'http://localhost' : '' -export const portApi = process.env.NODE_ENV === 'development' && !process.env.NEXT_PUBLIC_BACK_API ? 8080 : ''; -export const baseURLApi = `${hostApi}${portApi ? `:${portApi}` : ``}/api` - -export const localStorageDarkModeKey = 'darkMode' - -export const localStorageStyleKey = 'style' - -export const containerMaxW = 'xl:max-w-full xl:mx-auto 2xl:mx-20' - -export const appTitle = 'created by Flatlogic generator!' - -export const getPageTitle = (currentPageTitle: string) => `${currentPageTitle} — ${appTitle}` - -export const tinyKey = process.env.NEXT_PUBLIC_TINY_KEY || '' diff --git a/frontend/src/css/_app.css b/frontend/src/css/_app.css deleted file mode 100644 index affc655..0000000 --- a/frontend/src/css/_app.css +++ /dev/null @@ -1,32 +0,0 @@ -html { - @apply h-full; -} - -body { - @apply pt-14 xl:pl-60 h-full; -} - -#app { - @apply w-screen transition-position lg:w-auto h-full flex flex-col; -} - -.dropdown { - @apply cursor-pointer; -} - -li.stack-item:not(:last-child):after { - content: '/'; - @apply inline-block pl-2; -} - -.m-clipped, .m-clipped body { - @apply overflow-hidden lg:overflow-visible; -} - -.full-screen body { - @apply p-0; -} - -.main-navbar, .app-sidebar-brand { - box-shadow: 0px -1px 40px rgba(112, 144, 176, 0.2); -} diff --git a/frontend/src/css/_calendar.css b/frontend/src/css/_calendar.css deleted file mode 100644 index e3945b4..0000000 --- a/frontend/src/css/_calendar.css +++ /dev/null @@ -1,39 +0,0 @@ -.rbc-event { - @apply bg-blue-600 !important; -} - -.rbc-show-more { - @apply dark:text-white bg-transparent !important; -} - -.rbc-btn-group button { - @apply dark:text-white !important; -} - -.rbc-btn-group button:hover { - @apply text-white dark:bg-dark-700 !important; -} - -.rbc-btn-group button.rbc-active { - @apply text-black dark:bg-blue-600 !important; -} - -.rbc-btn-group button:focus { - @apply dark:bg-blue-600 !important; -} - -.rbc-day-bg.rbc-off-range-bg { - @apply dark:bg-dark-800 !important; -} -.rbc-current-time-indicator{ - @apply h-1 !important; -} -.rbc-today { - @apply dark:bg-dark-600/40 !important; -} - -.rbc-day-bg.rbc-selected-cell { - @apply dark:bg-dark-500 !important; -} - - diff --git a/frontend/src/css/_checkbox-radio-switch.css b/frontend/src/css/_checkbox-radio-switch.css deleted file mode 100644 index b2dab5c..0000000 --- a/frontend/src/css/_checkbox-radio-switch.css +++ /dev/null @@ -1,59 +0,0 @@ -@layer components { - .checkbox, .radio, .switch { - @apply inline-flex items-center cursor-pointer relative; - } - - .checkbox input[type=checkbox], .radio input[type=radio], .switch input[type=checkbox] { - @apply absolute left-0 opacity-0 -z-1; - } - - .checkbox input[type=checkbox]+.check, .radio input[type=radio]+.check, .switch input[type=checkbox]+.check { - @apply border-gray-700 border transition-colors duration-200 dark:bg-slate-800; - } - - .checkbox input[type=checkbox]:focus+.check, .radio input[type=radio]:focus+.check, .switch input[type=checkbox]:focus+.check { - @apply ring ring-blue-700 ; - } - - .checkbox input[type=checkbox]+.check, .radio input[type=radio]+.check { - @apply block w-5 h-5; - } - - .checkbox input[type=checkbox]+.check { - @apply rounded; - } - - .switch input[type=checkbox]+.check { - @apply flex items-center shrink-0 w-12 h-6 p-0.5 bg-gray-200; - } - - .radio input[type=radio]+.check, .switch input[type=checkbox]+.check, .switch input[type=checkbox]+.check:before { - @apply rounded-full; - } - - .checkbox input[type=checkbox]:checked+.check, .radio input[type=radio]:checked+.check { - @apply bg-no-repeat bg-center border-4; - } - - .checkbox input[type=checkbox]:checked+.check { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3Cpath style='fill:%23fff' d='M 0.04038059,0.6267767 0.14644661,0.52071068 0.42928932,0.80355339 0.3232233,0.90961941 z M 0.21715729,0.80355339 0.85355339,0.16715729 0.95961941,0.2732233 0.3232233,0.90961941 z'%3E%3C/path%3E%3C/svg%3E"); - } - - .radio input[type=radio]:checked+.check { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z' /%3E%3C/svg%3E"); - } - - .switch input[type=checkbox]:checked+.check, .checkbox input[type=checkbox]:checked+.check, .radio input[type=radio]:checked+.check { - @apply bg-blue-600 border-blue-600 ; - } - - .switch input[type=checkbox]+.check:before { - content: ''; - @apply block w-5 h-5 bg-white border border-gray-700; - } - - .switch input[type=checkbox]:checked+.check:before { - transform: translate3d(110%, 0 ,0); - @apply border-blue-600; - } -} \ No newline at end of file diff --git a/frontend/src/css/_helper.css b/frontend/src/css/_helper.css deleted file mode 100644 index 3444fa9..0000000 --- a/frontend/src/css/_helper.css +++ /dev/null @@ -1,23 +0,0 @@ -.helper-container { - right: 0; - top: 70px; - transform: translateX(100%); - - .tab { - top: 0; - left: 0; - transform: translateX(-100%); - } - - .tab:hover { - @apply bg-gray-900 cursor-pointer; - } -} - -.helper-container.open { - transform: translateX(0); -} - -.react-datepicker-wrapper, .react-datepicker-popper { - z-index: 10 !important; -} diff --git a/frontend/src/css/_progress.css b/frontend/src/css/_progress.css deleted file mode 100644 index 65d6796..0000000 --- a/frontend/src/css/_progress.css +++ /dev/null @@ -1,21 +0,0 @@ -@layer base { - progress { - @apply h-3 rounded-full overflow-hidden; - } - - progress::-webkit-progress-bar { - @apply bg-blue-200; - } - - progress::-webkit-progress-value { - @apply bg-blue-500; - } - - progress::-moz-progress-bar { - @apply bg-blue-500; - } - - progress::-ms-fill { - @apply bg-blue-500 border-0; - } -} diff --git a/frontend/src/css/_rich-text.css b/frontend/src/css/_rich-text.css deleted file mode 100644 index 8b13789..0000000 --- a/frontend/src/css/_rich-text.css +++ /dev/null @@ -1 +0,0 @@ - diff --git a/frontend/src/css/_scrollbars.css b/frontend/src/css/_scrollbars.css deleted file mode 100644 index a181b84..0000000 --- a/frontend/src/css/_scrollbars.css +++ /dev/null @@ -1,41 +0,0 @@ -@layer base { - html { - scrollbar-width: thin; - scrollbar-color: rgb(156, 163, 175) rgb(249, 250, 251); - } - - body::-webkit-scrollbar { - width: 8px; - height: 8px; - } - - body::-webkit-scrollbar-track { - @apply bg-gray-50; - } - - body::-webkit-scrollbar-thumb { - @apply bg-gray-400 rounded; - } - - body::-webkit-scrollbar-thumb:hover { - @apply bg-gray-500; - } -} - -@layer utilities { - .dark-scrollbars-compat { - scrollbar-color: rgb(71, 85, 105) rgb(30, 41, 59); - } - - .dark-scrollbars::-webkit-scrollbar-track { - @apply bg-slate-800; - } - - .dark-scrollbars::-webkit-scrollbar-thumb { - @apply bg-slate-600; - } - - .dark-scrollbars::-webkit-scrollbar-thumb:hover { - @apply bg-slate-500; - } -} diff --git a/frontend/src/css/_select-dropdown.css b/frontend/src/css/_select-dropdown.css deleted file mode 100644 index d610d8a..0000000 --- a/frontend/src/css/_select-dropdown.css +++ /dev/null @@ -1,31 +0,0 @@ -.react-select__control { - @apply dark:bg-dark-800 dark:border-dark-700 !important; -} - -.react-select__single-value { - @apply dark:text-white !important; -} - -.react-select__menu { - @apply dark:border-dark-700 -} - -.react-select__menu-list { - @apply dark:bg-dark-800 dark:border-dark-700 dark:rounded !important; -} - -.react-select__option { - @apply cursor-pointer hover:bg-gray-200 dark:hover:bg-dark-700 !important; -} - -.react-select__option--is-focused { - @apply dark:bg-dark-800 dark:text-white hover:dark:bg-dark-700 hover:dark:text-white !important; -} - -.react-select__option--is-selected, .react-select__option--is-selected:hover { - @apply dark:bg-dark-600 !important; -} - -.react-select__multi-value__remove { - @apply dark:bg-dark-600 dark:text-white hover:dark:bg-red-300 hover:dark:text-red-600 !important; -} diff --git a/frontend/src/css/_table.css b/frontend/src/css/_table.css deleted file mode 100644 index 893dc89..0000000 --- a/frontend/src/css/_table.css +++ /dev/null @@ -1,117 +0,0 @@ -@layer base { - table { - @apply w-full; - } - - thead { - @apply hidden lg:table-header-group; - } - - tr { - @apply max-w-full block relative border-b-4 border-gray-100 - lg:table-row lg:border-b-0 dark:border-slate-800; - } - - tr:last-child { - @apply border-b-0; - } - - td:not(:first-child) { - @apply lg:border-l lg:border-t-0 lg:border-r-0 lg:border-b-0 lg:border-gray-100 lg:dark:border-slate-700; - } - - th { - @apply lg:text-left lg:p-3 border-b; - } - - th.sortable { - cursor: pointer; - } - - th.sortable:hover:after { - transition: all 1s; - position: absolute; - - content: "↕"; - - margin-left: 1rem; - } - - th.sortable.asc:hover:after { - content: "↑"; - } - th.sortable.desc:hover:after { - content: "↓"; - } - - td { - @apply flex justify-between text-right py-3 px-4 align-top border-b border-gray-100 - lg:table-cell lg:text-left lg:p-3 lg:align-middle lg:border-b-0 dark:border-slate-800 dark:text-white; - } - - td:last-child { - @apply border-b-0; - } - - tbody tr, tbody tr:nth-child(odd) { - @apply lg:hover:bg-pavitra-300/70; - } - - tbody tr:nth-child(even) { - @apply lg:bg-pavitra-300 dark:bg-pavitra-300/70; - } - - td:before { - content: attr(data-label); - @apply font-semibold pr-3 text-left lg:hidden; - } - - tbody tr td { - @apply text-sm font-normal text-pavitra-900 dark:text-white; - } - - .datagrid--table, .MuiDataGrid-root { - @apply rounded border-none !important; - - } - - .datagrid--header { - @apply uppercase !important; - } - - .datagrid--header, - .datagrid--header .MuiIconButton-root, - .datagrid--cell, - .datagrid--cell .MuiIconButton-root { - @apply dark:text-white; - } - - .datagrid--cell .MuiDataGrid-booleanCell { - @apply dark:text-white !important; - } - - .datagrid--cell .MuiIconButton-root:hover { - @apply dark:text-white dark:bg-dark-700; - } - - .datagrid--row { - @apply even:bg-gray-100 dark:even:bg-[#1B1D22] dark:odd:bg-dark-900 !important; - } - - - .datagrid--table .MuiTablePagination-root { - @apply dark:text-white; - } - - .datagrid--table .MuiTablePagination-root .MuiButtonBase-root:disabled { - @apply dark:text-dark-700; - } - - .datagrid--table .MuiTablePagination-root .MuiButtonBase-root:hover { - @apply dark:bg-dark-700; - } - - .MuiButton-colorInherit { - @apply text-blue-600 dark:text-dark-700 !important; - } -} diff --git a/frontend/src/css/_theme.css b/frontend/src/css/_theme.css deleted file mode 100644 index d07e37a..0000000 --- a/frontend/src/css/_theme.css +++ /dev/null @@ -1,103 +0,0 @@ - -.theme-pink { -.app-sidebar { - @apply bg-pavitra-900 text-white; - -.menu-title, -.menu-item-icon, -.menu-item-link { - @apply text-white; -} -} - -.app-sidebar-brand { - @apply bg-white; -} - -.bg-blue-600 { - @apply bg-pavitra-800; -} - -.border-blue-700 { - @apply border-pink-700; -} - -.checkbox input[type=checkbox]:checked + .check, .radio input[type=radio]:checked + .check { - @apply border-pavitra-800; -} - -.helper-container .tab { - @apply bg-pavitra-900; -} - -.focus\:ring:focus { - --tw-ring-color: #14142A; -} - -.checkbox input[type=checkbox]:focus + .check, .radio input[type=radio]:focus + .check, .switch input[type=checkbox]:focus + .check { - --tw-ring-color: #14142A; -} - -} - -.theme-green { - -.app-sidebar { - @apply bg-pavitra-800 text-white; - -.menu-title, -.menu-item-icon, -.menu-item-link { - @apply text-white; -} - -} - -.app-sidebar-brand { - @apply bg-white; -} - -.bg-blue-600 { - @apply bg-pavitra-800; -} - -.border-blue-700 { - @apply bg-pavitra-700; -} - -.hover\:bg-blue-700:hover { - @apply bg-pavitra-700; -} - -.text-blue-600 { - @apply text-pavitra-900; -} - -.checkbox input[type=checkbox]:checked + .check, .radio input[type=radio]:checked + .check { - @apply border-pavitra-800; -} - -.helper-container .tab { - @apply bg-pavitra-700; -} - -.focus\:ring:focus { - --tw-ring-color: #4E4B66; -} - -.checkbox input[type=checkbox]:focus + .check, .radio input[type=radio]:focus + .check, .switch input[type=checkbox]:focus + .check { - --tw-ring-color: #4E4B66; -} - -.text-blue-500 { - @apply text-pavitra-800; -} - -.hover\:text-blue-600:hover { - @apply text-pavitra-800; -} - -.active\:text-blue-700:active { - @apply text-pavitra-800; -} -} diff --git a/frontend/src/css/main.css b/frontend/src/css/main.css deleted file mode 100644 index f061e28..0000000 --- a/frontend/src/css/main.css +++ /dev/null @@ -1,35 +0,0 @@ -@import "tailwind/_base.css"; -@import "tailwind/_components.css"; -@import "tailwind/_utilities.css"; -@import 'intro.js/introjs.css'; -@import "_checkbox-radio-switch.css"; -@import "_progress.css"; -@import "_scrollbars.css"; -@import "_table.css"; -@import "_helper.css"; -@import '_calendar.css'; -@import '_select-dropdown.css'; -@import "_theme.css"; -@import '_rich-text.css'; - - -.introjs-tooltip { - @apply min-w-[400px] max-w-[480px] p-2 !important; -} - -.good-img { - @apply -mt-96 !important; -} -.end-img { - @apply -mt-72 !important; -} -.introjs-button { - @apply bg-blue-600 text-white !important; - text-shadow: none !important; -} -.introjs-bullets ul li a.active { - @apply bg-blue-600 !important; -} -.introjs-prevbutton{ - @apply bg-transparent border border-blue-600 text-blue-600 !important; -} diff --git a/frontend/src/css/tailwind/_base.css b/frontend/src/css/tailwind/_base.css deleted file mode 100644 index 2f02db5..0000000 --- a/frontend/src/css/tailwind/_base.css +++ /dev/null @@ -1 +0,0 @@ -@tailwind base; diff --git a/frontend/src/css/tailwind/_components.css b/frontend/src/css/tailwind/_components.css deleted file mode 100644 index 020aaba..0000000 --- a/frontend/src/css/tailwind/_components.css +++ /dev/null @@ -1 +0,0 @@ -@tailwind components; diff --git a/frontend/src/css/tailwind/_utilities.css b/frontend/src/css/tailwind/_utilities.css deleted file mode 100644 index 65dd5f6..0000000 --- a/frontend/src/css/tailwind/_utilities.css +++ /dev/null @@ -1 +0,0 @@ -@tailwind utilities; diff --git a/frontend/src/helpers/dataFormatter.js b/frontend/src/helpers/dataFormatter.js deleted file mode 100644 index 197b823..0000000 --- a/frontend/src/helpers/dataFormatter.js +++ /dev/null @@ -1,195 +0,0 @@ -import dayjs from 'dayjs'; -import _ from 'lodash'; - -export default { - filesFormatter(arr) { - if (!arr || !arr.length) return []; - return arr.map((item) => item); - }, - imageFormatter(arr) { - if (!arr || !arr.length) return [] - return arr.map(item => ({ - publicUrl: item.publicUrl || '' - })) - }, - oneImageFormatter(arr) { - if (!arr || !arr.length) return '' - return arr[0].publicUrl || '' - }, - dateFormatter(date) { - if (!date) return '' - return dayjs(date).format('YYYY-MM-DD') - }, - dateTimeFormatter(date) { - if (!date) return '' - return dayjs(date).format('YYYY-MM-DD HH:mm') - }, - booleanFormatter(val) { - return val ? 'Yes' : 'No' - }, - dataGridEditFormatter(obj) { - return _.transform(obj, (result, value, key) => { - if (_.isArray(value)) { - result[key] = _.map(value, 'id'); - } else if (_.isObject(value)) { - result[key] = value.id; - } else { - result[key] = value; - } - }); - }, - - - usersManyListFormatter(val) { - if (!val || !val.length) return [] - return val.map((item) => item.firstName) - }, - usersOneListFormatter(val) { - if (!val) return '' - return val.firstName - }, - usersManyListFormatterEdit(val) { - if (!val || !val.length) return [] - return val.map((item) => { - return {id: item.id, label: item.firstName} - }); - }, - usersOneListFormatterEdit(val) { - if (!val) return '' - return {label: val.firstName, id: val.id} - }, - - - - rolesManyListFormatter(val) { - if (!val || !val.length) return [] - return val.map((item) => item.name) - }, - rolesOneListFormatter(val) { - if (!val) return '' - return val.name - }, - rolesManyListFormatterEdit(val) { - if (!val || !val.length) return [] - return val.map((item) => { - return {id: item.id, label: item.name} - }); - }, - rolesOneListFormatterEdit(val) { - if (!val) return '' - return {label: val.name, id: val.id} - }, - - - - permissionsManyListFormatter(val) { - if (!val || !val.length) return [] - return val.map((item) => item.name) - }, - permissionsOneListFormatter(val) { - if (!val) return '' - return val.name - }, - permissionsManyListFormatterEdit(val) { - if (!val || !val.length) return [] - return val.map((item) => { - return {id: item.id, label: item.name} - }); - }, - permissionsOneListFormatterEdit(val) { - if (!val) return '' - return {label: val.name, id: val.id} - }, - - - - customersManyListFormatter(val) { - if (!val || !val.length) return [] - return val.map((item) => item.full_name) - }, - customersOneListFormatter(val) { - if (!val) return '' - return val.full_name - }, - customersManyListFormatterEdit(val) { - if (!val || !val.length) return [] - return val.map((item) => { - return {id: item.id, label: item.full_name} - }); - }, - customersOneListFormatterEdit(val) { - if (!val) return '' - return {label: val.full_name, id: val.id} - }, - - - - product_categoriesManyListFormatter(val) { - if (!val || !val.length) return [] - return val.map((item) => item.name) - }, - product_categoriesOneListFormatter(val) { - if (!val) return '' - return val.name - }, - product_categoriesManyListFormatterEdit(val) { - if (!val || !val.length) return [] - return val.map((item) => { - return {id: item.id, label: item.name} - }); - }, - product_categoriesOneListFormatterEdit(val) { - if (!val) return '' - return {label: val.name, id: val.id} - }, - - - - productsManyListFormatter(val) { - if (!val || !val.length) return [] - return val.map((item) => item.name) - }, - productsOneListFormatter(val) { - if (!val) return '' - return val.name - }, - productsManyListFormatterEdit(val) { - if (!val || !val.length) return [] - return val.map((item) => { - return {id: item.id, label: item.name} - }); - }, - productsOneListFormatterEdit(val) { - if (!val) return '' - return {label: val.name, id: val.id} - }, - - - - ordersManyListFormatter(val) { - if (!val || !val.length) return [] - return val.map((item) => item.order_number) - }, - ordersOneListFormatter(val) { - if (!val) return '' - return val.order_number - }, - ordersManyListFormatterEdit(val) { - if (!val || !val.length) return [] - return val.map((item) => { - return {id: item.id, label: item.order_number} - }); - }, - ordersOneListFormatterEdit(val) { - if (!val) return '' - return {label: val.order_number, id: val.id} - }, - - - - - - - - -} diff --git a/frontend/src/helpers/fileSaver.ts b/frontend/src/helpers/fileSaver.ts deleted file mode 100644 index eff647d..0000000 --- a/frontend/src/helpers/fileSaver.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { saveAs } from "file-saver"; - -export const saveFile = (e, url: string, name: string) => { - e.stopPropagation(); - saveAs(url,name); -}; diff --git a/frontend/src/helpers/humanize.ts b/frontend/src/helpers/humanize.ts deleted file mode 100644 index ea88c06..0000000 --- a/frontend/src/helpers/humanize.ts +++ /dev/null @@ -1,11 +0,0 @@ -export function humanize(str: string) { - if (!str) { - return ''; - } - return str.toString() - .replace(/^[\s_]+|[\s_]+$/g, '') - .replace(/[_\s]+/g, ' ') - .replace(/^[a-z]/, function (m) { - return m.toUpperCase(); - }); - } \ No newline at end of file diff --git a/frontend/src/helpers/notifyStateHandler.ts b/frontend/src/helpers/notifyStateHandler.ts deleted file mode 100644 index b1a247c..0000000 --- a/frontend/src/helpers/notifyStateHandler.ts +++ /dev/null @@ -1,31 +0,0 @@ -export const resetNotify = (state) => { - state.notify.showNotification = false; - state.notify.typeNotification = ''; - state.notify.textNotification = ''; -}; -export const rejectNotify = (state, action) => { - if (typeof action.payload === 'string') { - state.notify.textNotification = action.payload; - } else if (typeof action === 'object') { - const obj = { ...action.payload?.errors }; - delete obj['_errors']; - - let msg = ''; - - for (const key in obj) { - msg += `${key}: ${obj[key]['_errors']}; \n `; - } - - state.notify.textNotification = msg; - } else { - state.notify.textNotification = 'Network error'; - } - state.notify.textNotification = state.notify.textNotification || 'Network error'; - state.notify.typeNotification = 'error'; - state.notify.showNotification = true; -}; -export const fulfilledNotify = (state, msg) => { - state.notify.textNotification = msg; - state.notify.typeNotification = 'success'; - state.notify.showNotification = true; -}; diff --git a/frontend/src/helpers/pexels.ts b/frontend/src/helpers/pexels.ts deleted file mode 100644 index 3789520..0000000 --- a/frontend/src/helpers/pexels.ts +++ /dev/null @@ -1,76 +0,0 @@ -import axios from 'axios'; - -export async function getPexelsImage() { - try { - const response = await axios.get(`/pexels/image`); - return response.data; - } catch (error) { - console.error('Error fetching image:', error); - return null; - } -} - -export async function getPexelsVideo() { - try { - const response = await axios.get(`/pexels/video`); - return response.data; - } catch (error) { - console.error('Error fetching video:', error); - return null; - } -} - - -let localStorageLock = false; - -export async function getMultiplePexelsImages( - queries = ['home', 'apple', 'pizza', 'mountains', 'cat'], -) { - const normalizeQuery = (query) => - query.trim().toLowerCase().replace(/\s+/g, ''); - - while (localStorageLock) { - await new Promise((resolve) => setTimeout(resolve, 50)); - } - localStorageLock = true; - - const cachedImages = JSON.parse(localStorage.getItem('pexelsImagesCache')) || {}; - - - const isImageCached = (query) => { - const normalizedQuery = normalizeQuery(query); - const cached = cachedImages[normalizedQuery]; - const isCached = cached && cached.src && cached.photographer && cached.photographer_url; - return isCached; - }; - - const missingQueries = queries.filter((query) => !isImageCached(query)); - - if (missingQueries.length > 0) { - const queryString = missingQueries.join(','); - - try { - const response = await axios.get(`/pexels/multiple-images`, { - params: { queries: queryString }, - }); - - missingQueries.forEach((query, index) => { - const normalizedQuery = normalizeQuery(query); - if (!cachedImages[normalizedQuery]) { - cachedImages[normalizedQuery] = response.data[index]; - } - }); - - localStorage.setItem('pexelsImagesCache', JSON.stringify(cachedImages)); - - } catch (error) { - console.error(error); - } - } - - const result = queries.map((query) => cachedImages[normalizeQuery(query)]); - - localStorageLock = false; - - return result; -} \ No newline at end of file diff --git a/frontend/src/helpers/userPermissions.ts b/frontend/src/helpers/userPermissions.ts deleted file mode 100644 index 2f9c9f9..0000000 --- a/frontend/src/helpers/userPermissions.ts +++ /dev/null @@ -1,18 +0,0 @@ - -export function hasPermission(user, permission_name: string | string[]) { - if (!user?.app_role?.name) return false; - if (!permission_name) { - return true; - } - const permissions = new Set([ - ...(user?.custom_permissions ?? []).map((p) => p.name), - ...(user?.app_role_permissions ?? []).map((p) => p.name), - ]); - - if (typeof permission_name === 'string') { - return permissions.has(permission_name) || user.app_role.name === 'Administrator' - } else { - return permission_name.some((permission) => permissions.has(permission)); - } -} - diff --git a/frontend/src/hooks/sampleData.ts b/frontend/src/hooks/sampleData.ts deleted file mode 100644 index 7e2aeec..0000000 --- a/frontend/src/hooks/sampleData.ts +++ /dev/null @@ -1,22 +0,0 @@ -import useSWR from 'swr' -const fetcher = (url: string) => fetch(url).then((res) => res.json()) - -export const useSampleClients = () => { - const { data, error } = useSWR('/data-sources/clients.json', fetcher) - - return { - clients: data?.data ?? [], - isLoading: !error && !data, - isError: error, - } -} - -export const useSampleTransactions = () => { - const { data, error } = useSWR('/data-sources/history.json', fetcher) - - return { - transactions: data?.data ?? [], - isLoading: !error && !data, - isError: error, - } -} diff --git a/frontend/src/hooks/useDevCompilationStatus.ts b/frontend/src/hooks/useDevCompilationStatus.ts deleted file mode 100644 index dd07dba..0000000 --- a/frontend/src/hooks/useDevCompilationStatus.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { useState, useEffect } from 'react'; -import { useRouter } from 'next/router'; - -type CompilationStatus = 'ready' | 'compiling' | 'error' | 'initial'; - -const useDevCompilationStatus = (): CompilationStatus => { - const router = useRouter(); - const [status, setStatus] = useState('initial'); - - useEffect(() => { - if (process.env.NODE_ENV !== 'development') { - setStatus('ready'); - return; - } - - const handleRouteChangeStart = () => { - setStatus('compiling'); - }; - - const handleRouteChangeComplete = () => { - setTimeout(() => setStatus('ready'), 300); - }; - - const handleRouteChangeError = () => { - setTimeout(() => setStatus('error'), 300); - }; - - router.events.on('routeChangeStart', handleRouteChangeStart); - router.events.on('routeChangeComplete', handleRouteChangeComplete); - router.events.on('routeChangeError', handleRouteChangeError); - - setStatus('ready'); - - return () => { - router.events.off('routeChangeStart', handleRouteChangeStart); - router.events.off('routeChangeComplete', handleRouteChangeComplete); - router.events.off('routeChangeError', handleRouteChangeError); - }; - }, [router]); - - return status; -}; - -export default useDevCompilationStatus; \ No newline at end of file diff --git a/frontend/src/i18n.ts b/frontend/src/i18n.ts deleted file mode 100644 index 2bc1e8e..0000000 --- a/frontend/src/i18n.ts +++ /dev/null @@ -1,21 +0,0 @@ -import i18n from 'i18next'; -import { initReactI18next } from 'react-i18next'; -import HttpApi from 'i18next-http-backend'; -import LanguageDetector from 'i18next-browser-languagedetector'; - -i18n - .use(HttpApi) - .use(LanguageDetector) - .use(initReactI18next) - .init({ - fallbackLng: 'en', - detection: { - order: ['localStorage', 'navigator'], - lookupLocalStorage: 'app_lang_', - caches: ['localStorage'], - }, - backend: { - loadPath: '/locales/{{lng}}/{{ns}}.json', - }, - interpolation: { escapeValue: false }, - }); \ No newline at end of file diff --git a/frontend/src/interfaces/index.ts b/frontend/src/interfaces/index.ts deleted file mode 100644 index 0c7dd74..0000000 --- a/frontend/src/interfaces/index.ts +++ /dev/null @@ -1,109 +0,0 @@ -export type UserPayloadObject = { - name: string - email: string - avatar: string -} - -export type MenuAsideItem = { - label: string - icon?: string - href?: string - target?: string - color?: ColorButtonKey - isLogout?: boolean - withDevider?: boolean; - menu?: MenuAsideItem[] - permissions?: string | string[] -} - -export type MenuNavBarItem = { - label?: string - icon?: string - href?: string - target?: string - isDivider?: boolean - isLogout?: boolean - isDesktopNoLabel?: boolean - isToggleLightDark?: boolean - isCurrentUser?: boolean - menu?: MenuNavBarItem[] -} - -export type ColorKey = 'white' | 'light' | 'contrast' | 'success' | 'danger' | 'warning' | 'info' - -export type ColorButtonKey = - | 'white' - | 'whiteDark' - | 'lightDark' - | 'contrast' - | 'success' - | 'danger' - | 'warning' - | 'info' - | 'void' - -export type BgKey = 'purplePink' | 'pinkRed' | 'violet' - -export type TrendType = 'up' | 'down' | 'success' | 'danger' | 'warning' | 'info' - -export type TransactionType = 'withdraw' | 'deposit' | 'invoice' | 'payment' - -export type Transaction = { - id: number - amount: number - account: string - name: string - date: string - type: TransactionType - business: string -} - -export type Client = { - id: number - avatar: string - login: string - name: string - city: string, - company: string - firstName: string - lastName: string - phoneNumber: string - email: string - progress: number, - role: string - disabled: boolean - created: string - created_mm_dd_yyyy: string -} - -export interface User { - id: string; - firstName: string; - lastName?: any; - phoneNumber?: any; - email: string; - role: string; - disabled: boolean; - password: string; - emailVerified: boolean; - emailVerificationToken?: any; - emailVerificationTokenExpiresAt?: any; - passwordResetToken?: any; - passwordResetTokenExpiresAt?: any; - provider: string; - importHash?: any; - createdAt: Date; - updatedAt: Date; - deletedAt?: any; - createdById?: any; - updatedById?: any; - avatar: any[]; - notes: any[]; -} - -export type StyleKey = 'white' | 'basic' - -export type UserForm = { - name: string - email: string -} diff --git a/frontend/src/layouts/Authenticated.tsx b/frontend/src/layouts/Authenticated.tsx deleted file mode 100644 index 1b9907d..0000000 --- a/frontend/src/layouts/Authenticated.tsx +++ /dev/null @@ -1,129 +0,0 @@ -import React, { ReactNode, useEffect } from 'react' -import { useState } from 'react' -import jwt from 'jsonwebtoken'; -import { mdiForwardburger, mdiBackburger, mdiMenu } from '@mdi/js' -import menuAside from '../menuAside' -import menuNavBar from '../menuNavBar' -import BaseIcon from '../components/BaseIcon' -import NavBar from '../components/NavBar' -import NavBarItemPlain from '../components/NavBarItemPlain' -import AsideMenu from '../components/AsideMenu' -import FooterBar from '../components/FooterBar' -import { useAppDispatch, useAppSelector } from '../stores/hooks' -import Search from '../components/Search'; -import { useRouter } from 'next/router' -import {findMe, logoutUser} from "../stores/authSlice"; - -import {hasPermission} from "../helpers/userPermissions"; - - -type Props = { - children: ReactNode - - permission?: string - -} - -export default function LayoutAuthenticated({ - children, - - permission - -}: Props) { - const dispatch = useAppDispatch() - const router = useRouter() - const { token, currentUser } = useAppSelector((state) => state.auth) - const bgColor = useAppSelector((state) => state.style.bgLayoutColor); - let localToken - if (typeof window !== 'undefined') { - // Perform localStorage action - localToken = localStorage.getItem('token') - } - - const isTokenValid = () => { - const token = localStorage.getItem('token'); - if (!token) return; - const date = new Date().getTime() / 1000; - const data = jwt.decode(token); - if (!data) return; - return date < data.exp; - }; - - useEffect(() => { - dispatch(findMe()); - if (!isTokenValid()) { - dispatch(logoutUser()); - router.push('/login'); - } - }, [token, localToken]); - - - useEffect(() => { - if (!permission || !currentUser) return; - - if (!hasPermission(currentUser, permission)) router.push('/error'); - }, [currentUser, permission]); - - - const darkMode = useAppSelector((state) => state.style.darkMode) - - const [isAsideMobileExpanded, setIsAsideMobileExpanded] = useState(false) - const [isAsideLgActive, setIsAsideLgActive] = useState(false) - - useEffect(() => { - const handleRouteChangeStart = () => { - setIsAsideMobileExpanded(false) - setIsAsideLgActive(false) - } - - router.events.on('routeChangeStart', handleRouteChangeStart) - - // If the component is unmounted, unsubscribe - // from the event with the `off` method: - return () => { - router.events.off('routeChangeStart', handleRouteChangeStart) - } - }, [router.events, dispatch]) - - - const layoutAsidePadding = 'xl:pl-60' - - return ( -
    -
    - - setIsAsideMobileExpanded(!isAsideMobileExpanded)} - > - - - setIsAsideLgActive(true)} - > - - - - - - - setIsAsideLgActive(false)} - /> - {children} - Hand-crafted & Made with ❤️ -
    -
    - ) -} diff --git a/frontend/src/layouts/Guest.tsx b/frontend/src/layouts/Guest.tsx deleted file mode 100644 index 657813c..0000000 --- a/frontend/src/layouts/Guest.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import React, { ReactNode } from 'react' -import { useAppSelector } from '../stores/hooks' - -type Props = { - children: ReactNode -} - -export default function LayoutGuest({ children }: Props) { - const darkMode = useAppSelector((state) => state.style.darkMode) - const bgColor = useAppSelector((state) => state.style.bgLayoutColor); - - return ( -
    -
    {children}
    -
    - ) -} diff --git a/frontend/src/menuAside.ts b/frontend/src/menuAside.ts deleted file mode 100644 index 337116f..0000000 --- a/frontend/src/menuAside.ts +++ /dev/null @@ -1,107 +0,0 @@ -import * as icon from '@mdi/js'; -import { MenuAsideItem } from './interfaces' - -const menuAside: MenuAsideItem[] = [ - { - href: '/dashboard', - icon: icon.mdiViewDashboardOutline, - label: 'Dashboard', - }, - - { - href: '/users/users-list', - label: 'Users', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: icon.mdiAccountGroup ?? icon.mdiTable, - permissions: 'READ_USERS' - }, - { - href: '/roles/roles-list', - label: 'Roles', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: icon.mdiShieldAccountVariantOutline ?? icon.mdiTable, - permissions: 'READ_ROLES' - }, - { - href: '/permissions/permissions-list', - label: 'Permissions', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: icon.mdiShieldAccountOutline ?? icon.mdiTable, - permissions: 'READ_PERMISSIONS' - }, - { - href: '/customers/customers-list', - label: 'Customers', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiAccountGroup' in icon ? icon['mdiAccountGroup' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_CUSTOMERS' - }, - { - href: '/product_categories/product_categories-list', - label: 'Product categories', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiTagMultiple' in icon ? icon['mdiTagMultiple' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_PRODUCT_CATEGORIES' - }, - { - href: '/products/products-list', - label: 'Products', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiPackageVariantClosed' in icon ? icon['mdiPackageVariantClosed' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_PRODUCTS' - }, - { - href: '/orders/orders-list', - label: 'Orders', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiCart' in icon ? icon['mdiCart' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_ORDERS' - }, - { - href: '/order_items/order_items-list', - label: 'Order items', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiFormatListBulleted' in icon ? icon['mdiFormatListBulleted' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_ORDER_ITEMS' - }, - { - href: '/payments/payments-list', - label: 'Payments', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiCreditCardOutline' in icon ? icon['mdiCreditCardOutline' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_PAYMENTS' - }, - { - href: '/shipments/shipments-list', - label: 'Shipments', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiTruckFast' in icon ? icon['mdiTruckFast' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_SHIPMENTS' - }, - { - href: '/profile', - label: 'Profile', - icon: icon.mdiAccountCircle, - }, - - - { - href: '/api-docs', - target: '_blank', - label: 'Swagger API', - icon: icon.mdiFileCode, - permissions: 'READ_API_DOCS' - }, -] - -export default menuAside diff --git a/frontend/src/menuNavBar.ts b/frontend/src/menuNavBar.ts deleted file mode 100644 index a5dd956..0000000 --- a/frontend/src/menuNavBar.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { - mdiMenu, - mdiClockOutline, - mdiCloud, - mdiCrop, - mdiAccount, - mdiCogOutline, - mdiEmail, - mdiLogout, - mdiThemeLightDark, - mdiGithub, - mdiVuejs, -} from '@mdi/js' -import { MenuNavBarItem } from './interfaces' - -const menuNavBar: MenuNavBarItem[] = [ - { - isCurrentUser: true, - menu: [ - { - icon: mdiAccount, - label: 'My Profile', - href: '/profile', - }, - { - isDivider: true, - }, - { - icon: mdiLogout, - label: 'Log Out', - isLogout: true, - }, - ], - }, - { - icon: mdiThemeLightDark, - label: 'Light/Dark', - isDesktopNoLabel: true, - isToggleLightDark: true, - }, - { - icon: mdiLogout, - label: 'Log out', - isDesktopNoLabel: true, - isLogout: true, - }, -] - -export const webPagesNavBar = [ - -]; - -export default menuNavBar diff --git a/frontend/src/pages/_app.tsx b/frontend/src/pages/_app.tsx deleted file mode 100644 index 101a072..0000000 --- a/frontend/src/pages/_app.tsx +++ /dev/null @@ -1,201 +0,0 @@ -import React from 'react'; -import type { AppProps } from 'next/app'; -import type { ReactElement, ReactNode } from 'react'; -import type { NextPage } from 'next'; -import Head from 'next/head'; -import { store } from '../stores/store'; -import { Provider } from 'react-redux'; -import '../css/main.css'; -import axios from 'axios'; -import { baseURLApi } from '../config'; -import { useRouter } from 'next/router'; -import ErrorBoundary from "../components/ErrorBoundary"; -import DevModeBadge from '../components/DevModeBadge'; -import 'intro.js/introjs.css'; -import { appWithTranslation } from 'next-i18next'; -import '../i18n'; -import IntroGuide from '../components/IntroGuide'; -import { appSteps, loginSteps, usersSteps, rolesSteps } from '../stores/introSteps'; - -// Initialize axios -axios.defaults.baseURL = process.env.NEXT_PUBLIC_BACK_API - ? process.env.NEXT_PUBLIC_BACK_API - : baseURLApi; - -axios.defaults.headers.common['Content-Type'] = 'application/json'; - -export type NextPageWithLayout

    , IP = P> = NextPage & { - getLayout?: (page: ReactElement) => ReactNode -} - -type AppPropsWithLayout = AppProps & { - Component: NextPageWithLayout -} - -function MyApp({ Component, pageProps }: AppPropsWithLayout) { - // Use the layout defined at the page level, if available - const getLayout = Component.getLayout || ((page) => page); - const router = useRouter(); - const [stepsEnabled, setStepsEnabled] = React.useState(false); - const [stepName, setStepName] = React.useState(''); - const [steps, setSteps] = React.useState([]); - - axios.interceptors.request.use( - config => { - const token = localStorage.getItem('token'); - - if (token) { - config.headers.Authorization = `Bearer ${token}`; - } else { - delete config.headers.Authorization; - } - - return config; - }, - error => { - return Promise.reject(error); - } - ); - - // TODO: Remove this code in future releases - React.useEffect(() => { - const allowedOrigin = (() => { - if (!document.referrer) { - return null; - } - try { - return new URL(document.referrer).origin; - } catch (error) { - console.warn('[postMessage] Failed to parse parent origin from referrer', error); - return null; - } - })(); - - const handleMessage = async (event: MessageEvent) => { - if (event.data === 'getLocation') { - event.source?.postMessage( - { iframeLocation: window.location.pathname }, - event.origin, - ); - return; - } - - if (event.data === 'getAuthToken') { - if (allowedOrigin && event.origin !== allowedOrigin) { - console.warn('[postMessage] Blocked getAuthToken from origin', event.origin); - return; - } - const token = localStorage.getItem('token'); - const user = localStorage.getItem('user'); - event.source?.postMessage( - { iframeAuthToken: token, iframeAuthUser: user }, - event.origin, - ); - return; - } - - if (event.data === 'getScreenshot') { - try { - const html2canvas = (await import('html2canvas')).default; - const canvas = await html2canvas(document.body, { useCORS: true }); - const url = canvas.toDataURL('image/jpeg', 0.8); - event.source?.postMessage({ iframeScreenshot: url }, event.origin); - } catch (e) { - console.error('html2canvas failed', e); - event.source?.postMessage({ iframeScreenshot: null }, event.origin); - } - } - }; - - window.addEventListener('message', handleMessage); - return () => window.removeEventListener('message', handleMessage); - }, []); - - React.useEffect(() => { - // Tour is disabled by default in generated projects. - return; - const isCompleted = (stepKey: string) => { - return localStorage.getItem(`completed_${stepKey}`) === 'true'; - }; - if (router.pathname === '/login' && !isCompleted('loginSteps')) { - setSteps(loginSteps); - setStepName('loginSteps'); - setStepsEnabled(true); - }else if (router.pathname === '/dashboard' && !isCompleted('appSteps')) { - setTimeout(() => { - setSteps(appSteps); - setStepName('appSteps'); - setStepsEnabled(true); - }, 1000); - } else if (router.pathname === '/users/users-list' && !isCompleted('usersSteps')) { - setTimeout(() => { - setSteps(usersSteps); - setStepName('usersSteps'); - setStepsEnabled(true); - }, 1000); - } else if (router.pathname === '/roles/roles-list' && !isCompleted('rolesSteps')) { - setTimeout(() => { - setSteps(rolesSteps); - setStepName('rolesSteps'); - setStepsEnabled(true); - }, 1000); - } else { - setSteps([]); - setStepsEnabled(false); - } - }, [router.pathname]); - - const handleExit = () => { - setStepsEnabled(false); - }; - - const title = 'Store Operations Hub' - const description = "Back-office hub to manage products, customers, orders, fulfillment, and payments in one dashboard." - const url = "https://flatlogic.com/" - const image = "https://project-screens.s3.amazonaws.com/screenshots/39840/app-hero-20260429-183000.png" - const imageWidth = '1920' - const imageHeight = '960' - - return ( - - {getLayout( - <> - - - - - - - - - - - - - - - - - - - - - - - - - - - {(process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'dev_stage') && } - - )} - - ) -} - -export default appWithTranslation(MyApp); diff --git a/frontend/src/pages/api/hello.js b/frontend/src/pages/api/hello.js deleted file mode 100644 index f163396..0000000 --- a/frontend/src/pages/api/hello.js +++ /dev/null @@ -1,5 +0,0 @@ -// Next.js API route support: https://nextjs.org/docs/api-routes/introduction - -export default function helloAPI(req, res) { - res.status(200).json({ name: 'John Doe' }) -} diff --git a/frontend/src/pages/api/logError.ts b/frontend/src/pages/api/logError.ts deleted file mode 100644 index d72b3fd..0000000 --- a/frontend/src/pages/api/logError.ts +++ /dev/null @@ -1,83 +0,0 @@ -import fsPromises from 'fs/promises'; -import path from 'path'; - -const dataFilePath = path.join(process.cwd(), 'json/runtimeError.json'); - -export default async function handler(req, res) { - // Ensure directory exists - try { - await fsPromises.mkdir(path.dirname(dataFilePath), { recursive: true }); - } catch (error) { - // Ignore if directory already exists - } - - if (req.method === 'GET') { - try { - // Check if file exists - try { - await fsPromises.access(dataFilePath); - } catch (error) { - // File doesn't exist, return empty object - return res.status(200).json({}); - } - - // Read the existing data from the JSON file - const jsonData = await fsPromises.readFile(dataFilePath, 'utf-8'); - - // Handle empty file - if (!jsonData || jsonData.trim() === '') { - // Write empty JSON object to file - await fsPromises.writeFile(dataFilePath, '{}', 'utf-8'); - return res.status(200).json({}); - } - - // Parse JSON data - try { - const objectData = JSON.parse(jsonData); - return res.status(200).json(objectData); - } catch (parseError) { - console.error('Error parsing JSON from file:', parseError); - // Reset the file with valid JSON if parsing fails - await fsPromises.writeFile(dataFilePath, '{}', 'utf-8'); - return res.status(200).json({}); - } - } catch (error) { - console.error('Error in GET handler:', error); - return res.status(200).json({}); // Return empty object instead of error - } - } else if (req.method === 'POST') { - try { - const updatedData = JSON.stringify(req.body); - - // Create directory if it doesn't exist - await fsPromises.mkdir(path.dirname(dataFilePath), { recursive: true }); - - // Write the updated data to the JSON file - await fsPromises.writeFile(dataFilePath, updatedData); - - // Send a success response - res.status(200).json({ message: 'Data stored successfully' }); - } catch (error) { - console.error('Error in POST handler:', error); - // Send an error response - res.status(500).json({ message: 'Error storing data' }); - } - } else if (req.method === 'DELETE') { - try { - // Create directory if it doesn't exist - await fsPromises.mkdir(path.dirname(dataFilePath), { recursive: true }); - - // Write empty JSON object to file - await fsPromises.writeFile(dataFilePath, '{}'); - - // Send a success response - res.status(200).json({message: 'Data deleted successfully'}); - } catch (error) { - console.error('Error in DELETE handler:', error); - // Send an error response - res.status(500).json({message: 'Error deleting data'}); - } - } else { - res.status(405).json({ message: 'Method not allowed' }); - } -} diff --git a/frontend/src/pages/customers/[customersId].tsx b/frontend/src/pages/customers/[customersId].tsx deleted file mode 100644 index 86b601e..0000000 --- a/frontend/src/pages/customers/[customersId].tsx +++ /dev/null @@ -1,705 +0,0 @@ -import { mdiChartTimelineVariant, mdiUpload } from '@mdi/js' -import Head from 'next/head' -import React, { ReactElement, useEffect, useState } from 'react' -import DatePicker from "react-datepicker"; -import "react-datepicker/dist/react-datepicker.css"; -import dayjs from "dayjs"; - -import CardBox from '../../components/CardBox' -import LayoutAuthenticated from '../../layouts/Authenticated' -import SectionMain from '../../components/SectionMain' -import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton' -import { getPageTitle } from '../../config' - -import { Field, Form, Formik } from 'formik' -import FormField from '../../components/FormField' -import BaseDivider from '../../components/BaseDivider' -import BaseButtons from '../../components/BaseButtons' -import BaseButton from '../../components/BaseButton' -import FormCheckRadio from '../../components/FormCheckRadio' -import FormCheckRadioGroup from '../../components/FormCheckRadioGroup' -import FormFilePicker from '../../components/FormFilePicker' -import FormImagePicker from '../../components/FormImagePicker' -import { SelectField } from "../../components/SelectField"; -import { SelectFieldMany } from "../../components/SelectFieldMany"; -import { SwitchField } from '../../components/SwitchField' -import {RichTextField} from "../../components/RichTextField"; - -import { update, fetch } from '../../stores/customers/customersSlice' -import { useAppDispatch, useAppSelector } from '../../stores/hooks' -import { useRouter } from 'next/router' -import {saveFile} from "../../helpers/fileSaver"; -import dataFormatter from '../../helpers/dataFormatter'; -import ImageField from "../../components/ImageField"; - - - -const EditCustomers = () => { - const router = useRouter() - const dispatch = useAppDispatch() - const initVals = { - - - 'customer_code': '', - - - - - - - - - - - - - - - - - - - - - - - - - - - - 'full_name': '', - - - - - - - - - - - - - - - - - - - - - - - - - - - - 'email': '', - - - - - - - - - - - - - - - - - - - - - - - - - - - - 'phone': '', - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - billing_address: '', - - - - - - - - - - - - - - - - - - - - - - - - - - - - shipping_address: '', - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - customer_status: '', - - - - - - - - - - - - - - - - - - - - - - registered_at: new Date(), - - - - - - - - - - - - - - - - - - - - - - notes: '', - - - - - - - - - - - - - - - - - - - - - - - - } - const [initialValues, setInitialValues] = useState(initVals) - - const { customers } = useAppSelector((state) => state.customers) - - - const { customersId } = router.query - - useEffect(() => { - dispatch(fetch({ id: customersId })) - }, [customersId]) - - useEffect(() => { - if (typeof customers === 'object') { - setInitialValues(customers) - } - }, [customers]) - - useEffect(() => { - if (typeof customers === 'object') { - - const newInitialVal = {...initVals}; - - Object.keys(initVals).forEach(el => newInitialVal[el] = (customers)[el]) - - setInitialValues(newInitialVal); - } - }, [customers]) - - const handleSubmit = async (data) => { - await dispatch(update({ id: customersId, data })) - await router.push('/customers/customers-list') - } - - return ( - <> - - {getPageTitle('Edit customers')} - - - - {''} - - - handleSubmit(values)} - > -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - setInitialValues({...initialValues, 'registered_at': date})} - /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - router.push('/customers/customers-list')}/> - - - - - - - ) -} - -EditCustomers.getLayout = function getLayout(page: ReactElement) { - return ( - - {page} - - ) -} - -export default EditCustomers diff --git a/frontend/src/pages/customers/customers-edit.tsx b/frontend/src/pages/customers/customers-edit.tsx deleted file mode 100644 index c1e4652..0000000 --- a/frontend/src/pages/customers/customers-edit.tsx +++ /dev/null @@ -1,702 +0,0 @@ -import { mdiChartTimelineVariant, mdiUpload } from '@mdi/js' -import Head from 'next/head' -import React, { ReactElement, useEffect, useState } from 'react' -import DatePicker from "react-datepicker"; -import "react-datepicker/dist/react-datepicker.css"; -import dayjs from "dayjs"; - -import CardBox from '../../components/CardBox' -import LayoutAuthenticated from '../../layouts/Authenticated' -import SectionMain from '../../components/SectionMain' -import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton' -import { getPageTitle } from '../../config' - -import { Field, Form, Formik } from 'formik' -import FormField from '../../components/FormField' -import BaseDivider from '../../components/BaseDivider' -import BaseButtons from '../../components/BaseButtons' -import BaseButton from '../../components/BaseButton' -import FormCheckRadio from '../../components/FormCheckRadio' -import FormCheckRadioGroup from '../../components/FormCheckRadioGroup' -import FormFilePicker from '../../components/FormFilePicker' -import FormImagePicker from '../../components/FormImagePicker' -import { SelectField } from "../../components/SelectField"; -import { SelectFieldMany } from "../../components/SelectFieldMany"; -import { SwitchField } from '../../components/SwitchField' -import {RichTextField} from "../../components/RichTextField"; - -import { update, fetch } from '../../stores/customers/customersSlice' -import { useAppDispatch, useAppSelector } from '../../stores/hooks' -import { useRouter } from 'next/router' -import {saveFile} from "../../helpers/fileSaver"; -import dataFormatter from '../../helpers/dataFormatter'; -import ImageField from "../../components/ImageField"; - - - -const EditCustomersPage = () => { - const router = useRouter() - const dispatch = useAppDispatch() - const initVals = { - - - 'customer_code': '', - - - - - - - - - - - - - - - - - - - - - - - - - - - - 'full_name': '', - - - - - - - - - - - - - - - - - - - - - - - - - - - - 'email': '', - - - - - - - - - - - - - - - - - - - - - - - - - - - - 'phone': '', - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - billing_address: '', - - - - - - - - - - - - - - - - - - - - - - - - - - - - shipping_address: '', - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - customer_status: '', - - - - - - - - - - - - - - - - - - - - - - registered_at: new Date(), - - - - - - - - - - - - - - - - - - - - - - notes: '', - - - - - - - - - - - - - - - - - - - - - - - - } - const [initialValues, setInitialValues] = useState(initVals) - - const { customers } = useAppSelector((state) => state.customers) - - - const { id } = router.query - - useEffect(() => { - dispatch(fetch({ id: id })) - }, [id]) - - useEffect(() => { - if (typeof customers === 'object') { - setInitialValues(customers) - } - }, [customers]) - - useEffect(() => { - if (typeof customers === 'object') { - const newInitialVal = {...initVals}; - Object.keys(initVals).forEach(el => newInitialVal[el] = (customers)[el]) - setInitialValues(newInitialVal); - } - }, [customers]) - - const handleSubmit = async (data) => { - await dispatch(update({ id: id, data })) - await router.push('/customers/customers-list') - } - - return ( - <> - - {getPageTitle('Edit customers')} - - - - {''} - - - handleSubmit(values)} - > -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - setInitialValues({...initialValues, 'registered_at': date})} - /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - router.push('/customers/customers-list')}/> - - -
    -
    -
    - - ) -} - -EditCustomersPage.getLayout = function getLayout(page: ReactElement) { - return ( - - {page} - - ) -} - -export default EditCustomersPage diff --git a/frontend/src/pages/customers/customers-list.tsx b/frontend/src/pages/customers/customers-list.tsx deleted file mode 100644 index b617bd4..0000000 --- a/frontend/src/pages/customers/customers-list.tsx +++ /dev/null @@ -1,162 +0,0 @@ -import { mdiChartTimelineVariant } from '@mdi/js' -import Head from 'next/head' -import { uniqueId } from 'lodash'; -import React, { ReactElement, useState } from 'react' -import CardBox from '../../components/CardBox' -import LayoutAuthenticated from '../../layouts/Authenticated' -import SectionMain from '../../components/SectionMain' -import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton' -import { getPageTitle } from '../../config' -import TableCustomers from '../../components/Customers/TableCustomers' -import BaseButton from '../../components/BaseButton' -import axios from "axios"; -import Link from "next/link"; -import {useAppDispatch, useAppSelector} from "../../stores/hooks"; -import CardBoxModal from "../../components/CardBoxModal"; -import DragDropFilePicker from "../../components/DragDropFilePicker"; -import {setRefetch, uploadCsv} from '../../stores/customers/customersSlice'; - - -import {hasPermission} from "../../helpers/userPermissions"; - - - -const CustomersTablesPage = () => { - const [filterItems, setFilterItems] = useState([]); - const [csvFile, setCsvFile] = useState(null); - const [isModalActive, setIsModalActive] = useState(false); - const [showTableView, setShowTableView] = useState(false); - - - const { currentUser } = useAppSelector((state) => state.auth); - - - const dispatch = useAppDispatch(); - - - const [filters] = useState([{label: 'CustomerCode', title: 'customer_code'},{label: 'FullName', title: 'full_name'},{label: 'Email', title: 'email'},{label: 'Phone', title: 'phone'},{label: 'BillingAddress', title: 'billing_address'},{label: 'ShippingAddress', title: 'shipping_address'},{label: 'Notes', title: 'notes'}, - - - {label: 'RegisteredAt', title: 'registered_at', date: 'true'}, - - - {label: 'CustomerStatus', title: 'customer_status', type: 'enum', options: ['active','inactive','blocked']}, - ]); - - const hasCreatePermission = currentUser && hasPermission(currentUser, 'CREATE_CUSTOMERS'); - - - const addFilter = () => { - const newItem = { - id: uniqueId(), - fields: { - filterValue: '', - filterValueFrom: '', - filterValueTo: '', - selectedField: '', - }, - }; - newItem.fields.selectedField = filters[0].title; - setFilterItems([...filterItems, newItem]); - }; - - const getCustomersCSV = async () => { - const response = await axios({url: '/customers?filetype=csv', method: 'GET',responseType: 'blob'}); - const type = response.headers['content-type'] - const blob = new Blob([response.data], { type: type }) - const link = document.createElement('a') - link.href = window.URL.createObjectURL(blob) - link.download = 'customersCSV.csv' - link.click() - }; - - const onModalConfirm = async () => { - if (!csvFile) return; - await dispatch(uploadCsv(csvFile)); - dispatch(setRefetch(true)); - setCsvFile(null); - setIsModalActive(false); - }; - - const onModalCancel = () => { - setCsvFile(null); - setIsModalActive(false); - }; - - return ( - <> - - {getPageTitle('Customers')} - - - - {''} - - - - {hasCreatePermission && } - - - - - {hasCreatePermission && ( - setIsModalActive(true)} - /> - )} - -
    -
    -
    - -
    - - - - - -
    - - - - - ) -} - -CustomersTablesPage.getLayout = function getLayout(page: ReactElement) { - return ( - - {page} - - ) -} - -export default CustomersTablesPage diff --git a/frontend/src/pages/customers/customers-new.tsx b/frontend/src/pages/customers/customers-new.tsx deleted file mode 100644 index 80f010e..0000000 --- a/frontend/src/pages/customers/customers-new.tsx +++ /dev/null @@ -1,545 +0,0 @@ -import { mdiAccount, mdiChartTimelineVariant, mdiMail, mdiUpload } from '@mdi/js' -import Head from 'next/head' -import React, { ReactElement } from 'react' -import CardBox from '../../components/CardBox' -import LayoutAuthenticated from '../../layouts/Authenticated' -import SectionMain from '../../components/SectionMain' -import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton' -import { getPageTitle } from '../../config' - -import { Field, Form, Formik } from 'formik' -import FormField from '../../components/FormField' -import BaseDivider from '../../components/BaseDivider' -import BaseButtons from '../../components/BaseButtons' -import BaseButton from '../../components/BaseButton' -import FormCheckRadio from '../../components/FormCheckRadio' -import FormCheckRadioGroup from '../../components/FormCheckRadioGroup' -import FormFilePicker from '../../components/FormFilePicker' -import FormImagePicker from '../../components/FormImagePicker' -import { SwitchField } from '../../components/SwitchField' - -import { SelectField } from '../../components/SelectField' -import { SelectFieldMany } from "../../components/SelectFieldMany"; -import {RichTextField} from "../../components/RichTextField"; - -import { create } from '../../stores/customers/customersSlice' -import { useAppDispatch } from '../../stores/hooks' -import { useRouter } from 'next/router' -import moment from 'moment'; - -const initialValues = { - - - customer_code: '', - - - - - - - - - - - - - - - - full_name: '', - - - - - - - - - - - - - - - - email: '', - - - - - - - - - - - - - - - - phone: '', - - - - - - - - - - - - - - - - - billing_address: '', - - - - - - - - - - - - - - - - shipping_address: '', - - - - - - - - - - - - - - - - - - - - - - - - customer_status: 'active', - - - - - - - - - - - - - registered_at: '', - - - - - - - - - - - - - notes: '', - - - - - - - - - - - - -} - - -const CustomersNew = () => { - const router = useRouter() - const dispatch = useAppDispatch() - - - - - const handleSubmit = async (data) => { - await dispatch(create(data)) - await router.push('/customers/customers-list') - } - return ( - <> - - {getPageTitle('New Item')} - - - - {''} - - - handleSubmit(values)} - > -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - router.push('/customers/customers-list')}/> - - -
    -
    -
    - - ) -} - -CustomersNew.getLayout = function getLayout(page: ReactElement) { - return ( - - {page} - - ) -} - -export default CustomersNew diff --git a/frontend/src/pages/customers/customers-table.tsx b/frontend/src/pages/customers/customers-table.tsx deleted file mode 100644 index 93e5a5c..0000000 --- a/frontend/src/pages/customers/customers-table.tsx +++ /dev/null @@ -1,164 +0,0 @@ -import { mdiChartTimelineVariant } from '@mdi/js' -import Head from 'next/head' -import { uniqueId } from 'lodash'; -import React, { ReactElement, useState } from 'react' -import CardBox from '../../components/CardBox' -import LayoutAuthenticated from '../../layouts/Authenticated' -import SectionMain from '../../components/SectionMain' -import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton' -import { getPageTitle } from '../../config' -import TableCustomers from '../../components/Customers/TableCustomers' -import BaseButton from '../../components/BaseButton' -import axios from "axios"; -import Link from "next/link"; -import {useAppDispatch, useAppSelector} from "../../stores/hooks"; -import CardBoxModal from "../../components/CardBoxModal"; -import DragDropFilePicker from "../../components/DragDropFilePicker"; -import {setRefetch, uploadCsv} from '../../stores/customers/customersSlice'; - - -import {hasPermission} from "../../helpers/userPermissions"; - - - -const CustomersTablesPage = () => { - const [filterItems, setFilterItems] = useState([]); - const [csvFile, setCsvFile] = useState(null); - const [isModalActive, setIsModalActive] = useState(false); - const [showTableView, setShowTableView] = useState(false); - - - const { currentUser } = useAppSelector((state) => state.auth); - - - const dispatch = useAppDispatch(); - - - const [filters] = useState([{label: 'CustomerCode', title: 'customer_code'},{label: 'FullName', title: 'full_name'},{label: 'Email', title: 'email'},{label: 'Phone', title: 'phone'},{label: 'BillingAddress', title: 'billing_address'},{label: 'ShippingAddress', title: 'shipping_address'},{label: 'Notes', title: 'notes'}, - - - {label: 'RegisteredAt', title: 'registered_at', date: 'true'}, - - - {label: 'CustomerStatus', title: 'customer_status', type: 'enum', options: ['active','inactive','blocked']}, - ]); - - const hasCreatePermission = currentUser && hasPermission(currentUser, 'CREATE_CUSTOMERS'); - - - const addFilter = () => { - const newItem = { - id: uniqueId(), - fields: { - filterValue: '', - filterValueFrom: '', - filterValueTo: '', - selectedField: '', - }, - }; - newItem.fields.selectedField = filters[0].title; - setFilterItems([...filterItems, newItem]); - }; - - const getCustomersCSV = async () => { - const response = await axios({url: '/customers?filetype=csv', method: 'GET',responseType: 'blob'}); - const type = response.headers['content-type'] - const blob = new Blob([response.data], { type: type }) - const link = document.createElement('a') - link.href = window.URL.createObjectURL(blob) - link.download = 'customersCSV.csv' - link.click() - }; - - const onModalConfirm = async () => { - if (!csvFile) return; - await dispatch(uploadCsv(csvFile)); - dispatch(setRefetch(true)); - setCsvFile(null); - setIsModalActive(false); - }; - - const onModalCancel = () => { - setCsvFile(null); - setIsModalActive(false); - }; - - return ( - <> - - {getPageTitle('Customers')} - - - - {''} - - - - {hasCreatePermission && } - - - - - {hasCreatePermission && ( - setIsModalActive(true)} - /> - )} - -
    -
    - - - Back to table - - -
    -
    - - - -
    - - - - - ) -} - -CustomersTablesPage.getLayout = function getLayout(page: ReactElement) { - return ( - - {page} - - ) -} - -export default CustomersTablesPage diff --git a/frontend/src/pages/customers/customers-view.tsx b/frontend/src/pages/customers/customers-view.tsx deleted file mode 100644 index 860acd0..0000000 --- a/frontend/src/pages/customers/customers-view.tsx +++ /dev/null @@ -1,641 +0,0 @@ -import React, { ReactElement, useEffect } from 'react'; -import Head from 'next/head' -import DatePicker from "react-datepicker"; -import "react-datepicker/dist/react-datepicker.css"; -import dayjs from "dayjs"; -import {useAppDispatch, useAppSelector} from "../../stores/hooks"; -import {useRouter} from "next/router"; -import { fetch } from '../../stores/customers/customersSlice' -import {saveFile} from "../../helpers/fileSaver"; -import dataFormatter from '../../helpers/dataFormatter'; -import ImageField from "../../components/ImageField"; -import LayoutAuthenticated from "../../layouts/Authenticated"; -import {getPageTitle} from "../../config"; -import SectionTitleLineWithButton from "../../components/SectionTitleLineWithButton"; -import SectionMain from "../../components/SectionMain"; -import CardBox from "../../components/CardBox"; -import BaseButton from "../../components/BaseButton"; -import BaseDivider from "../../components/BaseDivider"; -import {mdiChartTimelineVariant} from "@mdi/js"; -import {SwitchField} from "../../components/SwitchField"; -import FormField from "../../components/FormField"; - - -const CustomersView = () => { - const router = useRouter() - const dispatch = useAppDispatch() - const { customers } = useAppSelector((state) => state.customers) - - - const { id } = router.query; - - function removeLastCharacter(str) { - console.log(str,`str`) - return str.slice(0, -1); - } - - useEffect(() => { - dispatch(fetch({ id })); - }, [dispatch, id]); - - - return ( - <> - - {getPageTitle('View customers')} - - - - - - - - - -
    -

    CustomerCode

    -

    {customers?.customer_code}

    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -

    FullName

    -

    {customers?.full_name}

    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -

    Email

    -

    {customers?.email}

    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -

    Phone

    -

    {customers?.phone}

    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -