From 9bf5ff301f9984a44c3294ee0fa6c393e97a1839 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Tue, 10 Feb 2026 06:18:28 +0000 Subject: [PATCH] Autosave: 20260210-061827 --- .dockerignore | 3 - .../contactForm.js => .perm_test_apache | 0 .perm_test_exec | 0 Dockerfile | 21 - Dockerfile.dev | 85 - backend/.env | 14 - 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/benefits.js | 446 -- backend/src/db/api/file.js | 87 - backend/src/db/api/inquiries.js | 614 --- backend/src/db/api/page_sections.js | 665 --- backend/src/db/api/pages.js | 553 -- backend/src/db/api/permissions.js | 339 -- backend/src/db/api/portfolio_items.js | 644 --- backend/src/db/api/roles.js | 409 -- backend/src/db/api/services.js | 560 --- backend/src/db/api/site_settings.js | 663 --- backend/src/db/api/skills.js | 455 -- backend/src/db/api/social_links.js | 442 -- backend/src/db/api/testimonials.js | 619 --- backend/src/db/api/users.js | 945 ---- backend/src/db/db.config.js | 33 - backend/src/db/migrations/1770697522414.js | 3012 ----------- backend/src/db/models/benefits.js | 109 - backend/src/db/models/file.js | 53 - backend/src/db/models/index.js | 38 - backend/src/db/models/inquiries.js | 164 - backend/src/db/models/page_sections.js | 196 - backend/src/db/models/pages.js | 158 - backend/src/db/models/permissions.js | 78 - backend/src/db/models/portfolio_items.js | 191 - backend/src/db/models/roles.js | 111 - backend/src/db/models/services.js | 168 - backend/src/db/models/site_settings.js | 168 - backend/src/db/models/skills.js | 124 - backend/src/db/models/social_links.js | 133 - backend/src/db/models/testimonials.js | 157 - backend/src/db/models/users.js | 252 - backend/src/db/reset.js | 16 - .../db/seeders/20200430130759-admin-user.js | 66 - .../db/seeders/20200430130760-user-roles.js | 1060 ---- .../db/seeders/20231127130745-sample-data.js | 3725 -------------- backend/src/db/utils.js | 27 - backend/src/helpers.js | 23 - backend/src/index.js | 178 - backend/src/middlewares/check-permissions.js | 149 - backend/src/middlewares/upload.js | 11 - backend/src/routes/auth.js | 207 - backend/src/routes/benefits.js | 438 -- backend/src/routes/file.js | 32 - backend/src/routes/inquiries.js | 448 -- backend/src/routes/openai.js | 328 -- backend/src/routes/organizationLogin.js | 2 - backend/src/routes/page_sections.js | 454 -- backend/src/routes/pages.js | 442 -- backend/src/routes/permissions.js | 429 -- backend/src/routes/pexels.js | 104 - backend/src/routes/portfolio_items.js | 445 -- backend/src/routes/roles.js | 429 -- backend/src/routes/search.js | 52 - backend/src/routes/services.js | 448 -- backend/src/routes/site_settings.js | 459 -- backend/src/routes/skills.js | 436 -- backend/src/routes/social_links.js | 436 -- backend/src/routes/sql.js | 61 - backend/src/routes/testimonials.js | 447 -- backend/src/routes/users.js | 440 -- backend/src/services/auth.js | 312 -- backend/src/services/benefits.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 - backend/src/services/inquiries.js | 138 - .../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/page_sections.js | 138 - backend/src/services/pages.js | 138 - backend/src/services/permissions.js | 138 - backend/src/services/portfolio_items.js | 138 - backend/src/services/roles.js | 437 -- backend/src/services/search.js | 424 -- backend/src/services/services.js | 138 - backend/src/services/site_settings.js | 138 - backend/src/services/skills.js | 138 - backend/src/services/social_links.js | 138 - backend/src/services/testimonials.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/src/components/AsideMenu.tsx | 30 - frontend/src/components/AsideMenuItem.tsx | 102 - frontend/src/components/AsideMenuLayer.tsx | 63 - frontend/src/components/AsideMenuList.tsx | 35 - .../src/components/Benefits/CardBenefits.tsx | 159 - .../src/components/Benefits/ListBenefits.tsx | 120 - .../src/components/Benefits/TableBenefits.tsx | 476 -- .../Benefits/configureBenefitsCols.tsx | 145 - frontend/src/components/BigCalendar.tsx | 175 - frontend/src/components/CardBoxModal.tsx | 59 - .../src/components/ChartLineSample/config.ts | 54 - .../src/components/ChartLineSample/index.tsx | 37 - .../src/components/DataGridMultiSelect.tsx | 55 - .../src/components/DragDropFilePicker.tsx | 124 - frontend/src/components/FormFilePicker.tsx | 92 - frontend/src/components/FormImagePicker.tsx | 90 - .../components/Inquiries/CardInquiries.tsx | 231 - .../components/Inquiries/ListInquiries.tsx | 168 - .../components/Inquiries/TableInquiries.tsx | 507 -- .../Inquiries/configureInquiriesCols.tsx | 246 - frontend/src/components/IntroGuide.tsx | 55 - .../components/KanbanBoard/KanbanBoard.tsx | 51 - .../src/components/KanbanBoard/KanbanCard.tsx | 64 - .../components/KanbanBoard/KanbanColumn.tsx | 209 - .../src/components/ListActionsPopover.tsx | 115 - 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 - frontend/src/components/OverlayLayer.tsx | 41 - .../Page_sections/CardPage_sections.tsx | 268 - .../Page_sections/ListPage_sections.tsx | 195 - .../Page_sections/TablePage_sections.tsx | 515 -- .../configurePage_sectionsCols.tsx | 278 - frontend/src/components/Pages/CardPages.tsx | 207 - frontend/src/components/Pages/ListPages.tsx | 152 - frontend/src/components/Pages/TablePages.tsx | 463 -- .../components/Pages/configurePagesCols.tsx | 213 - frontend/src/components/Pagination.tsx | 85 - .../src/components/PasswordSetOrReset.tsx | 113 - .../Permissions/CardPermissions.tsx | 111 - .../Permissions/ListPermissions.tsx | 88 - .../Permissions/TablePermissions.tsx | 463 -- .../Permissions/configurePermissionsCols.tsx | 83 - .../Portfolio_items/CardPortfolio_items.tsx | 263 - .../Portfolio_items/ListPortfolio_items.tsx | 194 - .../Portfolio_items/TablePortfolio_items.tsx | 463 -- .../configurePortfolio_itemsCols.tsx | 270 - 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/SelectField.tsx | 53 - frontend/src/components/SelectFieldMany.tsx | 67 - .../src/components/Services/CardServices.tsx | 219 - .../src/components/Services/ListServices.tsx | 160 - .../src/components/Services/TableServices.tsx | 476 -- .../Services/configureServicesCols.tsx | 221 - .../Site_settings/CardSite_settings.tsx | 272 - .../Site_settings/ListSite_settings.tsx | 199 - .../Site_settings/TableSite_settings.tsx | 476 -- .../configureSite_settingsCols.tsx | 275 - frontend/src/components/Skills/CardSkills.tsx | 159 - frontend/src/components/Skills/ListSkills.tsx | 120 - .../src/components/Skills/TableSkills.tsx | 463 -- .../components/Skills/configureSkillsCols.tsx | 146 - .../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 - .../Social_links/CardSocial_links.tsx | 159 - .../Social_links/ListSocial_links.tsx | 120 - .../Social_links/TableSocial_links.tsx | 463 -- .../configureSocial_linksCols.tsx | 145 - frontend/src/components/SwitchField.tsx | 29 - .../src/components/TableSampleClients.tsx | 141 - .../Testimonials/CardTestimonials.tsx | 244 - .../Testimonials/ListTestimonials.tsx | 179 - .../Testimonials/TableTestimonials.tsx | 476 -- .../configureTestimonialsCols.tsx | 245 - 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 | 8 +- frontend/src/css/main.css | 5 +- frontend/src/helpers/notifyStateHandler.ts | 31 - frontend/src/helpers/userPermissions.ts | 18 - frontend/src/layouts/Authenticated.tsx | 129 - frontend/src/menuAside.ts | 132 +- frontend/src/menuNavBar.ts | 54 +- frontend/src/pages/_app.tsx | 137 +- frontend/src/pages/benefits/[benefitsId].tsx | 442 -- frontend/src/pages/benefits/benefits-edit.tsx | 439 -- frontend/src/pages/benefits/benefits-list.tsx | 166 - frontend/src/pages/benefits/benefits-new.tsx | 342 -- .../src/pages/benefits/benefits-table.tsx | 164 - frontend/src/pages/benefits/benefits-view.tsx | 260 - frontend/src/pages/dashboard.tsx | 526 -- frontend/src/pages/forgot.tsx | 82 - frontend/src/pages/forms.tsx | 142 - frontend/src/pages/index.tsx | 439 +- .../src/pages/inquiries/[inquiriesId].tsx | 882 ---- .../src/pages/inquiries/inquiries-edit.tsx | 879 ---- .../src/pages/inquiries/inquiries-list.tsx | 168 - .../src/pages/inquiries/inquiries-new.tsx | 651 --- .../src/pages/inquiries/inquiries-table.tsx | 168 - .../src/pages/inquiries/inquiries-view.tsx | 495 -- frontend/src/pages/login.tsx | 276 - .../pages/page_sections/[page_sectionsId].tsx | 1014 ---- .../page_sections/page_sections-edit.tsx | 1011 ---- .../page_sections/page_sections-list.tsx | 168 - .../pages/page_sections/page_sections-new.tsx | 765 --- .../page_sections/page_sections-table.tsx | 168 - .../page_sections/page_sections-view.tsx | 557 -- frontend/src/pages/pages/[pagesId].tsx | 735 --- frontend/src/pages/pages/pages-edit.tsx | 732 --- frontend/src/pages/pages/pages-list.tsx | 166 - frontend/src/pages/pages/pages-new.tsx | 542 -- frontend/src/pages/pages/pages-table.tsx | 168 - frontend/src/pages/pages/pages-view.tsx | 560 --- frontend/src/pages/password-reset.tsx | 12 - .../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 | 130 - .../portfolio_items/[portfolio_itemsId].tsx | 925 ---- .../portfolio_items/portfolio_items-edit.tsx | 922 ---- .../portfolio_items/portfolio_items-list.tsx | 162 - .../portfolio_items/portfolio_items-new.tsx | 723 --- .../portfolio_items/portfolio_items-table.tsx | 164 - .../portfolio_items/portfolio_items-view.tsx | 515 -- frontend/src/pages/profile.tsx | 180 - frontend/src/pages/projects.tsx | 261 + frontend/src/pages/register.tsx | 92 - frontend/src/pages/roles/[rolesId].tsx | 282 -- frontend/src/pages/roles/roles-edit.tsx | 279 - 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 | 313 -- frontend/src/pages/search.tsx | 91 - frontend/src/pages/services/[servicesId].tsx | 774 --- frontend/src/pages/services/services-edit.tsx | 771 --- frontend/src/pages/services/services-list.tsx | 166 - frontend/src/pages/services/services-new.tsx | 605 --- .../src/pages/services/services-table.tsx | 164 - frontend/src/pages/services/services-view.tsx | 426 -- .../pages/site_settings/[site_settingsId].tsx | 976 ---- .../site_settings/site_settings-edit.tsx | 973 ---- .../site_settings/site_settings-list.tsx | 166 - .../pages/site_settings/site_settings-new.tsx | 764 --- .../site_settings/site_settings-table.tsx | 164 - .../site_settings/site_settings-view.tsx | 529 -- frontend/src/pages/skills/[skillsId].tsx | 453 -- frontend/src/pages/skills/skills-edit.tsx | 450 -- frontend/src/pages/skills/skills-list.tsx | 162 - frontend/src/pages/skills/skills-new.tsx | 354 -- frontend/src/pages/skills/skills-table.tsx | 164 - frontend/src/pages/skills/skills-view.tsx | 261 - .../pages/social_links/[social_linksId].tsx | 458 -- .../pages/social_links/social_links-edit.tsx | 455 -- .../pages/social_links/social_links-list.tsx | 162 - .../pages/social_links/social_links-new.tsx | 359 -- .../pages/social_links/social_links-table.tsx | 164 - .../pages/social_links/social_links-view.tsx | 261 - frontend/src/pages/tables.tsx | 33 - .../pages/testimonials/[testimonialsId].tsx | 844 ---- .../pages/testimonials/testimonials-edit.tsx | 841 ---- .../pages/testimonials/testimonials-list.tsx | 166 - .../pages/testimonials/testimonials-new.tsx | 655 --- .../pages/testimonials/testimonials-table.tsx | 164 - .../pages/testimonials/testimonials-view.tsx | 471 -- frontend/src/pages/users/[usersId].tsx | 722 --- frontend/src/pages/users/users-edit.tsx | 719 --- 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 | 699 --- frontend/src/pages/verify-email.tsx | 62 - frontend/src/stores/authSlice.ts | 124 - frontend/src/stores/benefits/benefitsSlice.ts | 231 - .../src/stores/inquiries/inquiriesSlice.ts | 231 - frontend/src/stores/introSteps.ts | 139 - frontend/src/stores/openAiSlice.ts | 151 - .../page_sections/page_sectionsSlice.ts | 231 - frontend/src/stores/pages/pagesSlice.ts | 231 - .../stores/permissions/permissionsSlice.ts | 231 - .../portfolio_items/portfolio_itemsSlice.ts | 231 - frontend/src/stores/roles/rolesSlice.ts | 280 -- frontend/src/stores/services/servicesSlice.ts | 231 - .../site_settings/site_settingsSlice.ts | 231 - frontend/src/stores/skills/skillsSlice.ts | 231 - .../stores/social_links/social_linksSlice.ts | 231 - frontend/src/stores/store.ts | 34 +- .../stores/testimonials/testimonialsSlice.ts | 231 - frontend/src/stores/users/usersSlice.ts | 231 - frontend/src/stores/usersSlice.ts | 117 - nginx.conf | 96 - package.json | 6 +- 334 files changed, 574 insertions(+), 90620 deletions(-) delete mode 100644 .dockerignore rename backend/src/routes/contactForm.js => .perm_test_apache (100%) create mode 100644 .perm_test_exec delete mode 100644 Dockerfile delete mode 100644 Dockerfile.dev 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/benefits.js delete mode 100644 backend/src/db/api/file.js delete mode 100644 backend/src/db/api/inquiries.js delete mode 100644 backend/src/db/api/page_sections.js delete mode 100644 backend/src/db/api/pages.js delete mode 100644 backend/src/db/api/permissions.js delete mode 100644 backend/src/db/api/portfolio_items.js delete mode 100644 backend/src/db/api/roles.js delete mode 100644 backend/src/db/api/services.js delete mode 100644 backend/src/db/api/site_settings.js delete mode 100644 backend/src/db/api/skills.js delete mode 100644 backend/src/db/api/social_links.js delete mode 100644 backend/src/db/api/testimonials.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/1770697522414.js delete mode 100644 backend/src/db/models/benefits.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/inquiries.js delete mode 100644 backend/src/db/models/page_sections.js delete mode 100644 backend/src/db/models/pages.js delete mode 100644 backend/src/db/models/permissions.js delete mode 100644 backend/src/db/models/portfolio_items.js delete mode 100644 backend/src/db/models/roles.js delete mode 100644 backend/src/db/models/services.js delete mode 100644 backend/src/db/models/site_settings.js delete mode 100644 backend/src/db/models/skills.js delete mode 100644 backend/src/db/models/social_links.js delete mode 100644 backend/src/db/models/testimonials.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/benefits.js delete mode 100644 backend/src/routes/file.js delete mode 100644 backend/src/routes/inquiries.js delete mode 100644 backend/src/routes/openai.js delete mode 100644 backend/src/routes/organizationLogin.js delete mode 100644 backend/src/routes/page_sections.js delete mode 100644 backend/src/routes/pages.js delete mode 100644 backend/src/routes/permissions.js delete mode 100644 backend/src/routes/pexels.js delete mode 100644 backend/src/routes/portfolio_items.js delete mode 100644 backend/src/routes/roles.js delete mode 100644 backend/src/routes/search.js delete mode 100644 backend/src/routes/services.js delete mode 100644 backend/src/routes/site_settings.js delete mode 100644 backend/src/routes/skills.js delete mode 100644 backend/src/routes/social_links.js delete mode 100644 backend/src/routes/sql.js delete mode 100644 backend/src/routes/testimonials.js delete mode 100644 backend/src/routes/users.js delete mode 100644 backend/src/services/auth.js delete mode 100644 backend/src/services/benefits.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/inquiries.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/page_sections.js delete mode 100644 backend/src/services/pages.js delete mode 100644 backend/src/services/permissions.js delete mode 100644 backend/src/services/portfolio_items.js delete mode 100644 backend/src/services/roles.js delete mode 100644 backend/src/services/search.js delete mode 100644 backend/src/services/services.js delete mode 100644 backend/src/services/site_settings.js delete mode 100644 backend/src/services/skills.js delete mode 100644 backend/src/services/social_links.js delete mode 100644 backend/src/services/testimonials.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/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/Benefits/CardBenefits.tsx delete mode 100644 frontend/src/components/Benefits/ListBenefits.tsx delete mode 100644 frontend/src/components/Benefits/TableBenefits.tsx delete mode 100644 frontend/src/components/Benefits/configureBenefitsCols.tsx delete mode 100644 frontend/src/components/BigCalendar.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/DataGridMultiSelect.tsx delete mode 100644 frontend/src/components/DragDropFilePicker.tsx delete mode 100644 frontend/src/components/FormFilePicker.tsx delete mode 100644 frontend/src/components/FormImagePicker.tsx delete mode 100644 frontend/src/components/Inquiries/CardInquiries.tsx delete mode 100644 frontend/src/components/Inquiries/ListInquiries.tsx delete mode 100644 frontend/src/components/Inquiries/TableInquiries.tsx delete mode 100644 frontend/src/components/Inquiries/configureInquiriesCols.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/ListActionsPopover.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/OverlayLayer.tsx delete mode 100644 frontend/src/components/Page_sections/CardPage_sections.tsx delete mode 100644 frontend/src/components/Page_sections/ListPage_sections.tsx delete mode 100644 frontend/src/components/Page_sections/TablePage_sections.tsx delete mode 100644 frontend/src/components/Page_sections/configurePage_sectionsCols.tsx delete mode 100644 frontend/src/components/Pages/CardPages.tsx delete mode 100644 frontend/src/components/Pages/ListPages.tsx delete mode 100644 frontend/src/components/Pages/TablePages.tsx delete mode 100644 frontend/src/components/Pages/configurePagesCols.tsx delete mode 100644 frontend/src/components/Pagination.tsx delete mode 100644 frontend/src/components/PasswordSetOrReset.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/Portfolio_items/CardPortfolio_items.tsx delete mode 100644 frontend/src/components/Portfolio_items/ListPortfolio_items.tsx delete mode 100644 frontend/src/components/Portfolio_items/TablePortfolio_items.tsx delete mode 100644 frontend/src/components/Portfolio_items/configurePortfolio_itemsCols.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/SelectField.tsx delete mode 100644 frontend/src/components/SelectFieldMany.tsx delete mode 100644 frontend/src/components/Services/CardServices.tsx delete mode 100644 frontend/src/components/Services/ListServices.tsx delete mode 100644 frontend/src/components/Services/TableServices.tsx delete mode 100644 frontend/src/components/Services/configureServicesCols.tsx delete mode 100644 frontend/src/components/Site_settings/CardSite_settings.tsx delete mode 100644 frontend/src/components/Site_settings/ListSite_settings.tsx delete mode 100644 frontend/src/components/Site_settings/TableSite_settings.tsx delete mode 100644 frontend/src/components/Site_settings/configureSite_settingsCols.tsx delete mode 100644 frontend/src/components/Skills/CardSkills.tsx delete mode 100644 frontend/src/components/Skills/ListSkills.tsx delete mode 100644 frontend/src/components/Skills/TableSkills.tsx delete mode 100644 frontend/src/components/Skills/configureSkillsCols.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/Social_links/CardSocial_links.tsx delete mode 100644 frontend/src/components/Social_links/ListSocial_links.tsx delete mode 100644 frontend/src/components/Social_links/TableSocial_links.tsx delete mode 100644 frontend/src/components/Social_links/configureSocial_linksCols.tsx delete mode 100644 frontend/src/components/SwitchField.tsx delete mode 100644 frontend/src/components/TableSampleClients.tsx delete mode 100644 frontend/src/components/Testimonials/CardTestimonials.tsx delete mode 100644 frontend/src/components/Testimonials/ListTestimonials.tsx delete mode 100644 frontend/src/components/Testimonials/TableTestimonials.tsx delete mode 100644 frontend/src/components/Testimonials/configureTestimonialsCols.tsx 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/helpers/notifyStateHandler.ts delete mode 100644 frontend/src/helpers/userPermissions.ts delete mode 100644 frontend/src/layouts/Authenticated.tsx delete mode 100644 frontend/src/pages/benefits/[benefitsId].tsx delete mode 100644 frontend/src/pages/benefits/benefits-edit.tsx delete mode 100644 frontend/src/pages/benefits/benefits-list.tsx delete mode 100644 frontend/src/pages/benefits/benefits-new.tsx delete mode 100644 frontend/src/pages/benefits/benefits-table.tsx delete mode 100644 frontend/src/pages/benefits/benefits-view.tsx delete mode 100644 frontend/src/pages/dashboard.tsx delete mode 100644 frontend/src/pages/forgot.tsx delete mode 100644 frontend/src/pages/forms.tsx delete mode 100644 frontend/src/pages/inquiries/[inquiriesId].tsx delete mode 100644 frontend/src/pages/inquiries/inquiries-edit.tsx delete mode 100644 frontend/src/pages/inquiries/inquiries-list.tsx delete mode 100644 frontend/src/pages/inquiries/inquiries-new.tsx delete mode 100644 frontend/src/pages/inquiries/inquiries-table.tsx delete mode 100644 frontend/src/pages/inquiries/inquiries-view.tsx delete mode 100644 frontend/src/pages/login.tsx delete mode 100644 frontend/src/pages/page_sections/[page_sectionsId].tsx delete mode 100644 frontend/src/pages/page_sections/page_sections-edit.tsx delete mode 100644 frontend/src/pages/page_sections/page_sections-list.tsx delete mode 100644 frontend/src/pages/page_sections/page_sections-new.tsx delete mode 100644 frontend/src/pages/page_sections/page_sections-table.tsx delete mode 100644 frontend/src/pages/page_sections/page_sections-view.tsx delete mode 100644 frontend/src/pages/pages/[pagesId].tsx delete mode 100644 frontend/src/pages/pages/pages-edit.tsx delete mode 100644 frontend/src/pages/pages/pages-list.tsx delete mode 100644 frontend/src/pages/pages/pages-new.tsx delete mode 100644 frontend/src/pages/pages/pages-table.tsx delete mode 100644 frontend/src/pages/pages/pages-view.tsx delete mode 100644 frontend/src/pages/password-reset.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/portfolio_items/[portfolio_itemsId].tsx delete mode 100644 frontend/src/pages/portfolio_items/portfolio_items-edit.tsx delete mode 100644 frontend/src/pages/portfolio_items/portfolio_items-list.tsx delete mode 100644 frontend/src/pages/portfolio_items/portfolio_items-new.tsx delete mode 100644 frontend/src/pages/portfolio_items/portfolio_items-table.tsx delete mode 100644 frontend/src/pages/portfolio_items/portfolio_items-view.tsx delete mode 100644 frontend/src/pages/profile.tsx create mode 100644 frontend/src/pages/projects.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/services/[servicesId].tsx delete mode 100644 frontend/src/pages/services/services-edit.tsx delete mode 100644 frontend/src/pages/services/services-list.tsx delete mode 100644 frontend/src/pages/services/services-new.tsx delete mode 100644 frontend/src/pages/services/services-table.tsx delete mode 100644 frontend/src/pages/services/services-view.tsx delete mode 100644 frontend/src/pages/site_settings/[site_settingsId].tsx delete mode 100644 frontend/src/pages/site_settings/site_settings-edit.tsx delete mode 100644 frontend/src/pages/site_settings/site_settings-list.tsx delete mode 100644 frontend/src/pages/site_settings/site_settings-new.tsx delete mode 100644 frontend/src/pages/site_settings/site_settings-table.tsx delete mode 100644 frontend/src/pages/site_settings/site_settings-view.tsx delete mode 100644 frontend/src/pages/skills/[skillsId].tsx delete mode 100644 frontend/src/pages/skills/skills-edit.tsx delete mode 100644 frontend/src/pages/skills/skills-list.tsx delete mode 100644 frontend/src/pages/skills/skills-new.tsx delete mode 100644 frontend/src/pages/skills/skills-table.tsx delete mode 100644 frontend/src/pages/skills/skills-view.tsx delete mode 100644 frontend/src/pages/social_links/[social_linksId].tsx delete mode 100644 frontend/src/pages/social_links/social_links-edit.tsx delete mode 100644 frontend/src/pages/social_links/social_links-list.tsx delete mode 100644 frontend/src/pages/social_links/social_links-new.tsx delete mode 100644 frontend/src/pages/social_links/social_links-table.tsx delete mode 100644 frontend/src/pages/social_links/social_links-view.tsx delete mode 100644 frontend/src/pages/tables.tsx delete mode 100644 frontend/src/pages/testimonials/[testimonialsId].tsx delete mode 100644 frontend/src/pages/testimonials/testimonials-edit.tsx delete mode 100644 frontend/src/pages/testimonials/testimonials-list.tsx delete mode 100644 frontend/src/pages/testimonials/testimonials-new.tsx delete mode 100644 frontend/src/pages/testimonials/testimonials-table.tsx delete mode 100644 frontend/src/pages/testimonials/testimonials-view.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/benefits/benefitsSlice.ts delete mode 100644 frontend/src/stores/inquiries/inquiriesSlice.ts delete mode 100644 frontend/src/stores/introSteps.ts delete mode 100644 frontend/src/stores/openAiSlice.ts delete mode 100644 frontend/src/stores/page_sections/page_sectionsSlice.ts delete mode 100644 frontend/src/stores/pages/pagesSlice.ts delete mode 100644 frontend/src/stores/permissions/permissionsSlice.ts delete mode 100644 frontend/src/stores/portfolio_items/portfolio_itemsSlice.ts delete mode 100644 frontend/src/stores/roles/rolesSlice.ts delete mode 100644 frontend/src/stores/services/servicesSlice.ts delete mode 100644 frontend/src/stores/site_settings/site_settingsSlice.ts delete mode 100644 frontend/src/stores/skills/skillsSlice.ts delete mode 100644 frontend/src/stores/social_links/social_linksSlice.ts delete mode 100644 frontend/src/stores/testimonials/testimonialsSlice.ts delete mode 100644 frontend/src/stores/users/usersSlice.ts delete mode 100644 frontend/src/stores/usersSlice.ts delete mode 100644 nginx.conf diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 2c83cc6..0000000 --- a/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -backend/node_modules -frontend/node_modules -frontend/build diff --git a/backend/src/routes/contactForm.js b/.perm_test_apache similarity index 100% rename from backend/src/routes/contactForm.js rename to .perm_test_apache diff --git a/.perm_test_exec b/.perm_test_exec new file mode 100644 index 0000000..e69de29 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/backend/.env b/backend/.env deleted file mode 100644 index 8f7985c..0000000 --- a/backend/.env +++ /dev/null @@ -1,14 +0,0 @@ -DB_NAME=app_38334 -DB_USER=app_38334 -DB_PASS=02f73895-cabe-4aa2-94ec-5acefd8fd4d0 -DB_HOST=127.0.0.1 -DB_PORT=5432 -PORT=3000 -GOOGLE_CLIENT_ID=671001533244-kf1k1gmp6mnl0r030qmvdu6v36ghmim6.apps.googleusercontent.com -GOOGLE_CLIENT_SECRET=Yo4qbKZniqvojzUQ60iKlxqR -MS_CLIENT_ID=4696f457-31af-40de-897c-e00d7d4cff73 -MS_CLIENT_SECRET=m8jzZ.5UpHF3=-dXzyxiZ4e[F8OF54@p -EMAIL_USER=AKIAVEW7G4PQUBGM52OF -EMAIL_PASS=BLnD4hKGb6YkSz3gaQrf8fnyLi3C3/EdjOOsLEDTDPTz -SECRET_KEY=HUEyqESqgQ1yTwzVlO6wprC9Kf1J1xuA -PEXELS_KEY=Vc99rnmOhHhJAbgGQoKLZtsaIVfkeownoQNbTj78VemUjKh08ZYRbf18 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 876e123..0000000 --- a/backend/README.md +++ /dev/null @@ -1,56 +0,0 @@ - -#Blackness Studio Website - 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_blackness_studio_website;` - -- Then give that new user privileges to the new database then quit the `psql`. - - `postgres=> GRANT ALL PRIVILEGES ON DATABASE db_blackness_studio_website 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 1d79fcc..0000000 --- a/backend/package.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "name": "blacknessstudiowebsite", - "description": "Blackness Studio Website - 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 6378a84..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: "02f73895", - user_pass: "5acefd8fd4d0", - admin_email: "admin@flatlogic.com", - providers: { - LOCAL: 'local', - GOOGLE: 'google', - MICROSOFT: 'microsoft' - }, - secret_key: process.env.SECRET_KEY || '02f73895-cabe-4aa2-94ec-5acefd8fd4d0', - 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: 'Blackness Studio Website ', - 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: 'Analytics Viewer', - - }, - - project_uuid: '02f73895-cabe-4aa2-94ec-5acefd8fd4d0', - 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 = 'Abstract gold light trails'; -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/benefits.js b/backend/src/db/api/benefits.js deleted file mode 100644 index 22a99d3..0000000 --- a/backend/src/db/api/benefits.js +++ /dev/null @@ -1,446 +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 BenefitsDBApi { - - - - static async create(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const benefits = await db.benefits.create( - { - id: data.id || undefined, - - title: data.title - || - null - , - - description: data.description - || - null - , - - icon_name: data.icon_name - || - null - , - - sort_order: data.sort_order - || - null - , - - is_active: data.is_active - || - false - - , - - importHash: data.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - - - - - - - return benefits; - } - - - 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 benefitsData = data.map((item, index) => ({ - id: item.id || undefined, - - title: item.title - || - null - , - - description: item.description - || - null - , - - icon_name: item.icon_name - || - null - , - - sort_order: item.sort_order - || - 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 benefits = await db.benefits.bulkCreate(benefitsData, { transaction }); - - // For each item created, replace relation files - - - return benefits; - } - - static async update(id, data, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - - const benefits = await db.benefits.findByPk(id, {}, {transaction}); - - - - - const updatePayload = {}; - - if (data.title !== undefined) updatePayload.title = data.title; - - - if (data.description !== undefined) updatePayload.description = data.description; - - - if (data.icon_name !== undefined) updatePayload.icon_name = data.icon_name; - - - if (data.sort_order !== undefined) updatePayload.sort_order = data.sort_order; - - - if (data.is_active !== undefined) updatePayload.is_active = data.is_active; - - - updatePayload.updatedById = currentUser.id; - - await benefits.update(updatePayload, {transaction}); - - - - - - - - - - return benefits; - } - - static async deleteByIds(ids, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const benefits = await db.benefits.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); - - await db.sequelize.transaction(async (transaction) => { - for (const record of benefits) { - await record.update( - {deletedBy: currentUser.id}, - {transaction} - ); - } - for (const record of benefits) { - await record.destroy({transaction}); - } - }); - - - return benefits; - } - - static async remove(id, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - const benefits = await db.benefits.findByPk(id, options); - - await benefits.update({ - deletedBy: currentUser.id - }, { - transaction, - }); - - await benefits.destroy({ - transaction - }); - - return benefits; - } - - static async findBy(where, options) { - const transaction = (options && options.transaction) || undefined; - - const benefits = await db.benefits.findOne( - { where }, - { transaction }, - ); - - if (!benefits) { - return benefits; - } - - const output = benefits.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.title) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'benefits', - 'title', - filter.title, - ), - }; - } - - if (filter.description) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'benefits', - 'description', - filter.description, - ), - }; - } - - if (filter.icon_name) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'benefits', - 'icon_name', - filter.icon_name, - ), - }; - } - - - - - - - if (filter.sort_orderRange) { - const [start, end] = filter.sort_orderRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - sort_order: { - ...where.sort_order, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - sort_order: { - ...where.sort_order, - [Op.lte]: end, - }, - }; - } - } - - - 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.benefits.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( - 'benefits', - 'title', - query, - ), - ], - }; - } - - const records = await db.benefits.findAll({ - attributes: [ 'id', 'title' ], - where, - limit: limit ? Number(limit) : undefined, - offset: offset ? Number(offset) : undefined, - orderBy: [['title', 'ASC']], - }); - - return records.map((record) => ({ - id: record.id, - label: record.title, - })); - } - - -}; - 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/inquiries.js b/backend/src/db/api/inquiries.js deleted file mode 100644 index 1c186e6..0000000 --- a/backend/src/db/api/inquiries.js +++ /dev/null @@ -1,614 +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 InquiriesDBApi { - - - - static async create(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const inquiries = await db.inquiries.create( - { - id: data.id || undefined, - - full_name: data.full_name - || - null - , - - email: data.email - || - null - , - - company_name: data.company_name - || - null - , - - subject: data.subject - || - null - , - - message: data.message - || - null - , - - source_page: data.source_page - || - null - , - - status: data.status - || - null - , - - received_at: data.received_at - || - null - , - - replied_at: data.replied_at - || - null - , - - fiverr_url: data.fiverr_url - || - null - , - - importHash: data.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - - await inquiries.setAssigned_to( data.assigned_to || null, { - transaction, - }); - - - - - - - return inquiries; - } - - - 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 inquiriesData = data.map((item, index) => ({ - id: item.id || undefined, - - full_name: item.full_name - || - null - , - - email: item.email - || - null - , - - company_name: item.company_name - || - null - , - - subject: item.subject - || - null - , - - message: item.message - || - null - , - - source_page: item.source_page - || - null - , - - status: item.status - || - null - , - - received_at: item.received_at - || - null - , - - replied_at: item.replied_at - || - null - , - - fiverr_url: item.fiverr_url - || - null - , - - importHash: item.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - createdAt: new Date(Date.now() + index * 1000), - })); - - // Bulk create items - const inquiries = await db.inquiries.bulkCreate(inquiriesData, { transaction }); - - // For each item created, replace relation files - - - return inquiries; - } - - static async update(id, data, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - - const inquiries = await db.inquiries.findByPk(id, {}, {transaction}); - - - - - const updatePayload = {}; - - if (data.full_name !== undefined) updatePayload.full_name = data.full_name; - - - if (data.email !== undefined) updatePayload.email = data.email; - - - if (data.company_name !== undefined) updatePayload.company_name = data.company_name; - - - if (data.subject !== undefined) updatePayload.subject = data.subject; - - - if (data.message !== undefined) updatePayload.message = data.message; - - - if (data.source_page !== undefined) updatePayload.source_page = data.source_page; - - - if (data.status !== undefined) updatePayload.status = data.status; - - - if (data.received_at !== undefined) updatePayload.received_at = data.received_at; - - - if (data.replied_at !== undefined) updatePayload.replied_at = data.replied_at; - - - if (data.fiverr_url !== undefined) updatePayload.fiverr_url = data.fiverr_url; - - - updatePayload.updatedById = currentUser.id; - - await inquiries.update(updatePayload, {transaction}); - - - - if (data.assigned_to !== undefined) { - await inquiries.setAssigned_to( - - data.assigned_to, - - { transaction } - ); - } - - - - - - - - return inquiries; - } - - static async deleteByIds(ids, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const inquiries = await db.inquiries.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); - - await db.sequelize.transaction(async (transaction) => { - for (const record of inquiries) { - await record.update( - {deletedBy: currentUser.id}, - {transaction} - ); - } - for (const record of inquiries) { - await record.destroy({transaction}); - } - }); - - - return inquiries; - } - - static async remove(id, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - const inquiries = await db.inquiries.findByPk(id, options); - - await inquiries.update({ - deletedBy: currentUser.id - }, { - transaction, - }); - - await inquiries.destroy({ - transaction - }); - - return inquiries; - } - - static async findBy(where, options) { - const transaction = (options && options.transaction) || undefined; - - const inquiries = await db.inquiries.findOne( - { where }, - { transaction }, - ); - - if (!inquiries) { - return inquiries; - } - - const output = inquiries.get({plain: true}); - - - - - - - - - - - - - - - - - output.assigned_to = await inquiries.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.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.full_name) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'inquiries', - 'full_name', - filter.full_name, - ), - }; - } - - if (filter.email) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'inquiries', - 'email', - filter.email, - ), - }; - } - - if (filter.company_name) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'inquiries', - 'company_name', - filter.company_name, - ), - }; - } - - if (filter.subject) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'inquiries', - 'subject', - filter.subject, - ), - }; - } - - if (filter.message) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'inquiries', - 'message', - filter.message, - ), - }; - } - - if (filter.source_page) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'inquiries', - 'source_page', - filter.source_page, - ), - }; - } - - if (filter.fiverr_url) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'inquiries', - 'fiverr_url', - filter.fiverr_url, - ), - }; - } - - - - - - - if (filter.received_atRange) { - const [start, end] = filter.received_atRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - received_at: { - ...where.received_at, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - received_at: { - ...where.received_at, - [Op.lte]: end, - }, - }; - } - } - - if (filter.replied_atRange) { - const [start, end] = filter.replied_atRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - replied_at: { - ...where.replied_at, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - replied_at: { - ...where.replied_at, - [Op.lte]: end, - }, - }; - } - } - - - if (filter.active !== undefined) { - where = { - ...where, - active: filter.active === true || filter.active === 'true' - }; - } - - - if (filter.status) { - where = { - ...where, - status: filter.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.inquiries.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( - 'inquiries', - 'subject', - query, - ), - ], - }; - } - - const records = await db.inquiries.findAll({ - attributes: [ 'id', 'subject' ], - where, - limit: limit ? Number(limit) : undefined, - offset: offset ? Number(offset) : undefined, - orderBy: [['subject', 'ASC']], - }); - - return records.map((record) => ({ - id: record.id, - label: record.subject, - })); - } - - -}; - diff --git a/backend/src/db/api/page_sections.js b/backend/src/db/api/page_sections.js deleted file mode 100644 index 1f20212..0000000 --- a/backend/src/db/api/page_sections.js +++ /dev/null @@ -1,665 +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 Page_sectionsDBApi { - - - - static async create(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const page_sections = await db.page_sections.create( - { - id: data.id || undefined, - - section_type: data.section_type - || - null - , - - section_label: data.section_label - || - null - , - - headline: data.headline - || - null - , - - subheadline: data.subheadline - || - null - , - - body: data.body - || - null - , - - primary_button_label: data.primary_button_label - || - null - , - - primary_button_url: data.primary_button_url - || - null - , - - secondary_button_label: data.secondary_button_label - || - null - , - - secondary_button_url: data.secondary_button_url - || - null - , - - sort_order: data.sort_order - || - null - , - - is_visible: data.is_visible - || - false - - , - - importHash: data.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - - await page_sections.setPage( data.page || null, { - transaction, - }); - - - - - - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.page_sections.getTableName(), - belongsToColumn: 'background_images', - belongsToId: page_sections.id, - }, - data.background_images, - options, - ); - - - return page_sections; - } - - - 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 page_sectionsData = data.map((item, index) => ({ - id: item.id || undefined, - - section_type: item.section_type - || - null - , - - section_label: item.section_label - || - null - , - - headline: item.headline - || - null - , - - subheadline: item.subheadline - || - null - , - - body: item.body - || - null - , - - primary_button_label: item.primary_button_label - || - null - , - - primary_button_url: item.primary_button_url - || - null - , - - secondary_button_label: item.secondary_button_label - || - null - , - - secondary_button_url: item.secondary_button_url - || - null - , - - sort_order: item.sort_order - || - null - , - - is_visible: item.is_visible - || - false - - , - - importHash: item.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - createdAt: new Date(Date.now() + index * 1000), - })); - - // Bulk create items - const page_sections = await db.page_sections.bulkCreate(page_sectionsData, { transaction }); - - // For each item created, replace relation files - - for (let i = 0; i < page_sections.length; i++) { - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.page_sections.getTableName(), - belongsToColumn: 'background_images', - belongsToId: page_sections[i].id, - }, - data[i].background_images, - options, - ); - } - - - return page_sections; - } - - static async update(id, data, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - - const page_sections = await db.page_sections.findByPk(id, {}, {transaction}); - - - - - const updatePayload = {}; - - if (data.section_type !== undefined) updatePayload.section_type = data.section_type; - - - if (data.section_label !== undefined) updatePayload.section_label = data.section_label; - - - if (data.headline !== undefined) updatePayload.headline = data.headline; - - - if (data.subheadline !== undefined) updatePayload.subheadline = data.subheadline; - - - if (data.body !== undefined) updatePayload.body = data.body; - - - if (data.primary_button_label !== undefined) updatePayload.primary_button_label = data.primary_button_label; - - - if (data.primary_button_url !== undefined) updatePayload.primary_button_url = data.primary_button_url; - - - if (data.secondary_button_label !== undefined) updatePayload.secondary_button_label = data.secondary_button_label; - - - if (data.secondary_button_url !== undefined) updatePayload.secondary_button_url = data.secondary_button_url; - - - if (data.sort_order !== undefined) updatePayload.sort_order = data.sort_order; - - - if (data.is_visible !== undefined) updatePayload.is_visible = data.is_visible; - - - updatePayload.updatedById = currentUser.id; - - await page_sections.update(updatePayload, {transaction}); - - - - if (data.page !== undefined) { - await page_sections.setPage( - - data.page, - - { transaction } - ); - } - - - - - - - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.page_sections.getTableName(), - belongsToColumn: 'background_images', - belongsToId: page_sections.id, - }, - data.background_images, - options, - ); - - - return page_sections; - } - - static async deleteByIds(ids, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const page_sections = await db.page_sections.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); - - await db.sequelize.transaction(async (transaction) => { - for (const record of page_sections) { - await record.update( - {deletedBy: currentUser.id}, - {transaction} - ); - } - for (const record of page_sections) { - await record.destroy({transaction}); - } - }); - - - return page_sections; - } - - static async remove(id, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - const page_sections = await db.page_sections.findByPk(id, options); - - await page_sections.update({ - deletedBy: currentUser.id - }, { - transaction, - }); - - await page_sections.destroy({ - transaction - }); - - return page_sections; - } - - static async findBy(where, options) { - const transaction = (options && options.transaction) || undefined; - - const page_sections = await db.page_sections.findOne( - { where }, - { transaction }, - ); - - if (!page_sections) { - return page_sections; - } - - const output = page_sections.get({plain: true}); - - - - - - - - - - - - - - - - - output.page = await page_sections.getPage({ - transaction - }); - - - output.background_images = await page_sections.getBackground_images({ - 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.pages, - as: 'page', - - where: filter.page ? { - [Op.or]: [ - { id: { [Op.in]: filter.page.split('|').map(term => Utils.uuid(term)) } }, - { - title: { - [Op.or]: filter.page.split('|').map(term => ({ [Op.iLike]: `%${term}%` })) - } - }, - ] - } : {}, - - }, - - - - { - model: db.file, - as: 'background_images', - }, - - ]; - - if (filter) { - if (filter.id) { - where = { - ...where, - ['id']: Utils.uuid(filter.id), - }; - } - - - if (filter.section_label) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'page_sections', - 'section_label', - filter.section_label, - ), - }; - } - - if (filter.headline) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'page_sections', - 'headline', - filter.headline, - ), - }; - } - - if (filter.subheadline) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'page_sections', - 'subheadline', - filter.subheadline, - ), - }; - } - - if (filter.body) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'page_sections', - 'body', - filter.body, - ), - }; - } - - if (filter.primary_button_label) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'page_sections', - 'primary_button_label', - filter.primary_button_label, - ), - }; - } - - if (filter.primary_button_url) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'page_sections', - 'primary_button_url', - filter.primary_button_url, - ), - }; - } - - if (filter.secondary_button_label) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'page_sections', - 'secondary_button_label', - filter.secondary_button_label, - ), - }; - } - - if (filter.secondary_button_url) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'page_sections', - 'secondary_button_url', - filter.secondary_button_url, - ), - }; - } - - - - - - - if (filter.sort_orderRange) { - const [start, end] = filter.sort_orderRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - sort_order: { - ...where.sort_order, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - sort_order: { - ...where.sort_order, - [Op.lte]: end, - }, - }; - } - } - - - if (filter.active !== undefined) { - where = { - ...where, - active: filter.active === true || filter.active === 'true' - }; - } - - - if (filter.section_type) { - where = { - ...where, - section_type: filter.section_type, - }; - } - - if (filter.is_visible) { - where = { - ...where, - is_visible: filter.is_visible, - }; - } - - - - - - - - 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.page_sections.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( - 'page_sections', - 'section_label', - query, - ), - ], - }; - } - - const records = await db.page_sections.findAll({ - attributes: [ 'id', 'section_label' ], - where, - limit: limit ? Number(limit) : undefined, - offset: offset ? Number(offset) : undefined, - orderBy: [['section_label', 'ASC']], - }); - - return records.map((record) => ({ - id: record.id, - label: record.section_label, - })); - } - - -}; - diff --git a/backend/src/db/api/pages.js b/backend/src/db/api/pages.js deleted file mode 100644 index f92af7a..0000000 --- a/backend/src/db/api/pages.js +++ /dev/null @@ -1,553 +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 PagesDBApi { - - - - static async create(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const pages = await db.pages.create( - { - id: data.id || undefined, - - title: data.title - || - null - , - - slug: data.slug - || - null - , - - status: data.status - || - null - , - - sort_order: data.sort_order - || - null - , - - meta_title: data.meta_title - || - null - , - - meta_description: data.meta_description - || - null - , - - show_in_header_nav: data.show_in_header_nav - || - false - - , - - show_in_footer_nav: data.show_in_footer_nav - || - false - - , - - importHash: data.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - - await pages.setAuthor( data.author || null, { - transaction, - }); - - - - - - - return pages; - } - - - 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 pagesData = data.map((item, index) => ({ - id: item.id || undefined, - - title: item.title - || - null - , - - slug: item.slug - || - null - , - - status: item.status - || - null - , - - sort_order: item.sort_order - || - null - , - - meta_title: item.meta_title - || - null - , - - meta_description: item.meta_description - || - null - , - - show_in_header_nav: item.show_in_header_nav - || - false - - , - - show_in_footer_nav: item.show_in_footer_nav - || - false - - , - - importHash: item.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - createdAt: new Date(Date.now() + index * 1000), - })); - - // Bulk create items - const pages = await db.pages.bulkCreate(pagesData, { transaction }); - - // For each item created, replace relation files - - - return pages; - } - - static async update(id, data, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - - const pages = await db.pages.findByPk(id, {}, {transaction}); - - - - - const updatePayload = {}; - - if (data.title !== undefined) updatePayload.title = data.title; - - - if (data.slug !== undefined) updatePayload.slug = data.slug; - - - if (data.status !== undefined) updatePayload.status = data.status; - - - if (data.sort_order !== undefined) updatePayload.sort_order = data.sort_order; - - - if (data.meta_title !== undefined) updatePayload.meta_title = data.meta_title; - - - if (data.meta_description !== undefined) updatePayload.meta_description = data.meta_description; - - - if (data.show_in_header_nav !== undefined) updatePayload.show_in_header_nav = data.show_in_header_nav; - - - if (data.show_in_footer_nav !== undefined) updatePayload.show_in_footer_nav = data.show_in_footer_nav; - - - updatePayload.updatedById = currentUser.id; - - await pages.update(updatePayload, {transaction}); - - - - if (data.author !== undefined) { - await pages.setAuthor( - - data.author, - - { transaction } - ); - } - - - - - - - - return pages; - } - - static async deleteByIds(ids, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const pages = await db.pages.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); - - await db.sequelize.transaction(async (transaction) => { - for (const record of pages) { - await record.update( - {deletedBy: currentUser.id}, - {transaction} - ); - } - for (const record of pages) { - await record.destroy({transaction}); - } - }); - - - return pages; - } - - static async remove(id, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - const pages = await db.pages.findByPk(id, options); - - await pages.update({ - deletedBy: currentUser.id - }, { - transaction, - }); - - await pages.destroy({ - transaction - }); - - return pages; - } - - static async findBy(where, options) { - const transaction = (options && options.transaction) || undefined; - - const pages = await db.pages.findOne( - { where }, - { transaction }, - ); - - if (!pages) { - return pages; - } - - const output = pages.get({plain: true}); - - - - - - - - output.page_sections_page = await pages.getPage_sections_page({ - transaction - }); - - - - - - - - - - - output.author = await pages.getAuthor({ - 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.users, - as: 'author', - - where: filter.author ? { - [Op.or]: [ - { id: { [Op.in]: filter.author.split('|').map(term => Utils.uuid(term)) } }, - { - firstName: { - [Op.or]: filter.author.split('|').map(term => ({ [Op.iLike]: `%${term}%` })) - } - }, - ] - } : {}, - - }, - - - - ]; - - if (filter) { - if (filter.id) { - where = { - ...where, - ['id']: Utils.uuid(filter.id), - }; - } - - - if (filter.title) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'pages', - 'title', - filter.title, - ), - }; - } - - if (filter.slug) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'pages', - 'slug', - filter.slug, - ), - }; - } - - if (filter.meta_title) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'pages', - 'meta_title', - filter.meta_title, - ), - }; - } - - if (filter.meta_description) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'pages', - 'meta_description', - filter.meta_description, - ), - }; - } - - - - - - - if (filter.sort_orderRange) { - const [start, end] = filter.sort_orderRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - sort_order: { - ...where.sort_order, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - sort_order: { - ...where.sort_order, - [Op.lte]: end, - }, - }; - } - } - - - if (filter.active !== undefined) { - where = { - ...where, - active: filter.active === true || filter.active === 'true' - }; - } - - - if (filter.status) { - where = { - ...where, - status: filter.status, - }; - } - - if (filter.show_in_header_nav) { - where = { - ...where, - show_in_header_nav: filter.show_in_header_nav, - }; - } - - if (filter.show_in_footer_nav) { - where = { - ...where, - show_in_footer_nav: filter.show_in_footer_nav, - }; - } - - - - - - - - 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.pages.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( - 'pages', - 'title', - query, - ), - ], - }; - } - - const records = await db.pages.findAll({ - attributes: [ 'id', 'title' ], - where, - limit: limit ? Number(limit) : undefined, - offset: offset ? Number(offset) : undefined, - orderBy: [['title', 'ASC']], - }); - - return records.map((record) => ({ - id: record.id, - label: record.title, - })); - } - - -}; - diff --git a/backend/src/db/api/permissions.js b/backend/src/db/api/permissions.js deleted file mode 100644 index b5e3986..0000000 --- a/backend/src/db/api/permissions.js +++ /dev/null @@ -1,339 +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/portfolio_items.js b/backend/src/db/api/portfolio_items.js deleted file mode 100644 index 9314d2f..0000000 --- a/backend/src/db/api/portfolio_items.js +++ /dev/null @@ -1,644 +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 Portfolio_itemsDBApi { - - - - static async create(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const portfolio_items = await db.portfolio_items.create( - { - id: data.id || undefined, - - title: data.title - || - null - , - - work_type: data.work_type - || - null - , - - client_name: data.client_name - || - null - , - - summary: data.summary - || - null - , - - case_study: data.case_study - || - null - , - - external_url: data.external_url - || - null - , - - tech_stack: data.tech_stack - || - null - , - - published_on: data.published_on - || - null - , - - is_featured: data.is_featured - || - false - - , - - is_public: data.is_public - || - false - - , - - importHash: data.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - - - - - - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.portfolio_items.getTableName(), - belongsToColumn: 'screenshots', - belongsToId: portfolio_items.id, - }, - data.screenshots, - options, - ); - - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.portfolio_items.getTableName(), - belongsToColumn: 'attachments', - belongsToId: portfolio_items.id, - }, - data.attachments, - options, - ); - - - return portfolio_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 portfolio_itemsData = data.map((item, index) => ({ - id: item.id || undefined, - - title: item.title - || - null - , - - work_type: item.work_type - || - null - , - - client_name: item.client_name - || - null - , - - summary: item.summary - || - null - , - - case_study: item.case_study - || - null - , - - external_url: item.external_url - || - null - , - - tech_stack: item.tech_stack - || - null - , - - published_on: item.published_on - || - null - , - - is_featured: item.is_featured - || - false - - , - - is_public: item.is_public - || - false - - , - - importHash: item.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - createdAt: new Date(Date.now() + index * 1000), - })); - - // Bulk create items - const portfolio_items = await db.portfolio_items.bulkCreate(portfolio_itemsData, { transaction }); - - // For each item created, replace relation files - - for (let i = 0; i < portfolio_items.length; i++) { - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.portfolio_items.getTableName(), - belongsToColumn: 'screenshots', - belongsToId: portfolio_items[i].id, - }, - data[i].screenshots, - options, - ); - } - - for (let i = 0; i < portfolio_items.length; i++) { - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.portfolio_items.getTableName(), - belongsToColumn: 'attachments', - belongsToId: portfolio_items[i].id, - }, - data[i].attachments, - options, - ); - } - - - return portfolio_items; - } - - static async update(id, data, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - - const portfolio_items = await db.portfolio_items.findByPk(id, {}, {transaction}); - - - - - const updatePayload = {}; - - if (data.title !== undefined) updatePayload.title = data.title; - - - if (data.work_type !== undefined) updatePayload.work_type = data.work_type; - - - if (data.client_name !== undefined) updatePayload.client_name = data.client_name; - - - if (data.summary !== undefined) updatePayload.summary = data.summary; - - - if (data.case_study !== undefined) updatePayload.case_study = data.case_study; - - - if (data.external_url !== undefined) updatePayload.external_url = data.external_url; - - - if (data.tech_stack !== undefined) updatePayload.tech_stack = data.tech_stack; - - - if (data.published_on !== undefined) updatePayload.published_on = data.published_on; - - - if (data.is_featured !== undefined) updatePayload.is_featured = data.is_featured; - - - if (data.is_public !== undefined) updatePayload.is_public = data.is_public; - - - updatePayload.updatedById = currentUser.id; - - await portfolio_items.update(updatePayload, {transaction}); - - - - - - - - - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.portfolio_items.getTableName(), - belongsToColumn: 'screenshots', - belongsToId: portfolio_items.id, - }, - data.screenshots, - options, - ); - - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.portfolio_items.getTableName(), - belongsToColumn: 'attachments', - belongsToId: portfolio_items.id, - }, - data.attachments, - options, - ); - - - return portfolio_items; - } - - static async deleteByIds(ids, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const portfolio_items = await db.portfolio_items.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); - - await db.sequelize.transaction(async (transaction) => { - for (const record of portfolio_items) { - await record.update( - {deletedBy: currentUser.id}, - {transaction} - ); - } - for (const record of portfolio_items) { - await record.destroy({transaction}); - } - }); - - - return portfolio_items; - } - - static async remove(id, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - const portfolio_items = await db.portfolio_items.findByPk(id, options); - - await portfolio_items.update({ - deletedBy: currentUser.id - }, { - transaction, - }); - - await portfolio_items.destroy({ - transaction - }); - - return portfolio_items; - } - - static async findBy(where, options) { - const transaction = (options && options.transaction) || undefined; - - const portfolio_items = await db.portfolio_items.findOne( - { where }, - { transaction }, - ); - - if (!portfolio_items) { - return portfolio_items; - } - - const output = portfolio_items.get({plain: true}); - - - - - - - - - - - - - - - - - output.screenshots = await portfolio_items.getScreenshots({ - transaction - }); - - - output.attachments = await portfolio_items.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.file, - as: 'screenshots', - }, - - { - model: db.file, - as: 'attachments', - }, - - ]; - - if (filter) { - if (filter.id) { - where = { - ...where, - ['id']: Utils.uuid(filter.id), - }; - } - - - if (filter.title) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'portfolio_items', - 'title', - filter.title, - ), - }; - } - - if (filter.client_name) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'portfolio_items', - 'client_name', - filter.client_name, - ), - }; - } - - if (filter.summary) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'portfolio_items', - 'summary', - filter.summary, - ), - }; - } - - if (filter.case_study) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'portfolio_items', - 'case_study', - filter.case_study, - ), - }; - } - - if (filter.external_url) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'portfolio_items', - 'external_url', - filter.external_url, - ), - }; - } - - if (filter.tech_stack) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'portfolio_items', - 'tech_stack', - filter.tech_stack, - ), - }; - } - - - - - - - if (filter.published_onRange) { - const [start, end] = filter.published_onRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - published_on: { - ...where.published_on, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - published_on: { - ...where.published_on, - [Op.lte]: end, - }, - }; - } - } - - - if (filter.active !== undefined) { - where = { - ...where, - active: filter.active === true || filter.active === 'true' - }; - } - - - if (filter.work_type) { - where = { - ...where, - work_type: filter.work_type, - }; - } - - if (filter.is_featured) { - where = { - ...where, - is_featured: filter.is_featured, - }; - } - - if (filter.is_public) { - where = { - ...where, - is_public: filter.is_public, - }; - } - - - - - - 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.portfolio_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( - 'portfolio_items', - 'title', - query, - ), - ], - }; - } - - const records = await db.portfolio_items.findAll({ - attributes: [ 'id', 'title' ], - where, - limit: limit ? Number(limit) : undefined, - offset: offset ? Number(offset) : undefined, - orderBy: [['title', 'ASC']], - }); - - return records.map((record) => ({ - id: record.id, - label: record.title, - })); - } - - -}; - diff --git a/backend/src/db/api/roles.js b/backend/src/db/api/roles.js deleted file mode 100644 index 3c754ec..0000000 --- a/backend/src/db/api/roles.js +++ /dev/null @@ -1,409 +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/services.js b/backend/src/db/api/services.js deleted file mode 100644 index 1ebc33e..0000000 --- a/backend/src/db/api/services.js +++ /dev/null @@ -1,560 +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 ServicesDBApi { - - - - static async create(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const services = await db.services.create( - { - id: data.id || undefined, - - name: data.name - || - null - , - - short_description: data.short_description - || - null - , - - details: data.details - || - null - , - - category: data.category - || - null - , - - sort_order: data.sort_order - || - null - , - - is_featured: data.is_featured - || - false - - , - - is_active: data.is_active - || - false - - , - - cta_label: data.cta_label - || - null - , - - cta_url: data.cta_url - || - null - , - - icon_name: data.icon_name - || - null - , - - importHash: data.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - - - - - - - return services; - } - - - 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 servicesData = data.map((item, index) => ({ - id: item.id || undefined, - - name: item.name - || - null - , - - short_description: item.short_description - || - null - , - - details: item.details - || - null - , - - category: item.category - || - null - , - - sort_order: item.sort_order - || - null - , - - is_featured: item.is_featured - || - false - - , - - is_active: item.is_active - || - false - - , - - cta_label: item.cta_label - || - null - , - - cta_url: item.cta_url - || - null - , - - icon_name: item.icon_name - || - null - , - - importHash: item.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - createdAt: new Date(Date.now() + index * 1000), - })); - - // Bulk create items - const services = await db.services.bulkCreate(servicesData, { transaction }); - - // For each item created, replace relation files - - - return services; - } - - static async update(id, data, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - - const services = await db.services.findByPk(id, {}, {transaction}); - - - - - const updatePayload = {}; - - if (data.name !== undefined) updatePayload.name = data.name; - - - if (data.short_description !== undefined) updatePayload.short_description = data.short_description; - - - if (data.details !== undefined) updatePayload.details = data.details; - - - if (data.category !== undefined) updatePayload.category = data.category; - - - if (data.sort_order !== undefined) updatePayload.sort_order = data.sort_order; - - - if (data.is_featured !== undefined) updatePayload.is_featured = data.is_featured; - - - if (data.is_active !== undefined) updatePayload.is_active = data.is_active; - - - if (data.cta_label !== undefined) updatePayload.cta_label = data.cta_label; - - - if (data.cta_url !== undefined) updatePayload.cta_url = data.cta_url; - - - if (data.icon_name !== undefined) updatePayload.icon_name = data.icon_name; - - - updatePayload.updatedById = currentUser.id; - - await services.update(updatePayload, {transaction}); - - - - - - - - - - return services; - } - - static async deleteByIds(ids, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const services = await db.services.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); - - await db.sequelize.transaction(async (transaction) => { - for (const record of services) { - await record.update( - {deletedBy: currentUser.id}, - {transaction} - ); - } - for (const record of services) { - await record.destroy({transaction}); - } - }); - - - return services; - } - - static async remove(id, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - const services = await db.services.findByPk(id, options); - - await services.update({ - deletedBy: currentUser.id - }, { - transaction, - }); - - await services.destroy({ - transaction - }); - - return services; - } - - static async findBy(where, options) { - const transaction = (options && options.transaction) || undefined; - - const services = await db.services.findOne( - { where }, - { transaction }, - ); - - if (!services) { - return services; - } - - const output = services.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( - 'services', - 'name', - filter.name, - ), - }; - } - - if (filter.short_description) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'services', - 'short_description', - filter.short_description, - ), - }; - } - - if (filter.details) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'services', - 'details', - filter.details, - ), - }; - } - - if (filter.cta_label) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'services', - 'cta_label', - filter.cta_label, - ), - }; - } - - if (filter.cta_url) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'services', - 'cta_url', - filter.cta_url, - ), - }; - } - - if (filter.icon_name) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'services', - 'icon_name', - filter.icon_name, - ), - }; - } - - - - - - - if (filter.sort_orderRange) { - const [start, end] = filter.sort_orderRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - sort_order: { - ...where.sort_order, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - sort_order: { - ...where.sort_order, - [Op.lte]: end, - }, - }; - } - } - - - if (filter.active !== undefined) { - where = { - ...where, - active: filter.active === true || filter.active === 'true' - }; - } - - - if (filter.category) { - where = { - ...where, - category: filter.category, - }; - } - - if (filter.is_featured) { - where = { - ...where, - is_featured: filter.is_featured, - }; - } - - 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.services.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( - 'services', - 'name', - query, - ), - ], - }; - } - - const records = await db.services.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/site_settings.js b/backend/src/db/api/site_settings.js deleted file mode 100644 index 5135a1c..0000000 --- a/backend/src/db/api/site_settings.js +++ /dev/null @@ -1,663 +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 Site_settingsDBApi { - - - - static async create(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const site_settings = await db.site_settings.create( - { - id: data.id || undefined, - - site_name: data.site_name - || - null - , - - tagline: data.tagline - || - null - , - - primary_domain: data.primary_domain - || - null - , - - primary_cta_label: data.primary_cta_label - || - null - , - - primary_cta_url: data.primary_cta_url - || - null - , - - contact_email: data.contact_email - || - null - , - - contact_phone: data.contact_phone - || - null - , - - location: data.location - || - null - , - - accent_color_hex: data.accent_color_hex - || - null - , - - seo_title: data.seo_title - || - null - , - - seo_description: data.seo_description - || - null - , - - importHash: data.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - - - - - - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.site_settings.getTableName(), - belongsToColumn: 'logo_images', - belongsToId: site_settings.id, - }, - data.logo_images, - options, - ); - - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.site_settings.getTableName(), - belongsToColumn: 'favicon_images', - belongsToId: site_settings.id, - }, - data.favicon_images, - options, - ); - - - return site_settings; - } - - - 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 site_settingsData = data.map((item, index) => ({ - id: item.id || undefined, - - site_name: item.site_name - || - null - , - - tagline: item.tagline - || - null - , - - primary_domain: item.primary_domain - || - null - , - - primary_cta_label: item.primary_cta_label - || - null - , - - primary_cta_url: item.primary_cta_url - || - null - , - - contact_email: item.contact_email - || - null - , - - contact_phone: item.contact_phone - || - null - , - - location: item.location - || - null - , - - accent_color_hex: item.accent_color_hex - || - null - , - - seo_title: item.seo_title - || - null - , - - seo_description: item.seo_description - || - null - , - - importHash: item.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - createdAt: new Date(Date.now() + index * 1000), - })); - - // Bulk create items - const site_settings = await db.site_settings.bulkCreate(site_settingsData, { transaction }); - - // For each item created, replace relation files - - for (let i = 0; i < site_settings.length; i++) { - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.site_settings.getTableName(), - belongsToColumn: 'logo_images', - belongsToId: site_settings[i].id, - }, - data[i].logo_images, - options, - ); - } - - for (let i = 0; i < site_settings.length; i++) { - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.site_settings.getTableName(), - belongsToColumn: 'favicon_images', - belongsToId: site_settings[i].id, - }, - data[i].favicon_images, - options, - ); - } - - - return site_settings; - } - - static async update(id, data, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - - const site_settings = await db.site_settings.findByPk(id, {}, {transaction}); - - - - - const updatePayload = {}; - - if (data.site_name !== undefined) updatePayload.site_name = data.site_name; - - - if (data.tagline !== undefined) updatePayload.tagline = data.tagline; - - - if (data.primary_domain !== undefined) updatePayload.primary_domain = data.primary_domain; - - - if (data.primary_cta_label !== undefined) updatePayload.primary_cta_label = data.primary_cta_label; - - - if (data.primary_cta_url !== undefined) updatePayload.primary_cta_url = data.primary_cta_url; - - - if (data.contact_email !== undefined) updatePayload.contact_email = data.contact_email; - - - if (data.contact_phone !== undefined) updatePayload.contact_phone = data.contact_phone; - - - if (data.location !== undefined) updatePayload.location = data.location; - - - if (data.accent_color_hex !== undefined) updatePayload.accent_color_hex = data.accent_color_hex; - - - if (data.seo_title !== undefined) updatePayload.seo_title = data.seo_title; - - - if (data.seo_description !== undefined) updatePayload.seo_description = data.seo_description; - - - updatePayload.updatedById = currentUser.id; - - await site_settings.update(updatePayload, {transaction}); - - - - - - - - - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.site_settings.getTableName(), - belongsToColumn: 'logo_images', - belongsToId: site_settings.id, - }, - data.logo_images, - options, - ); - - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.site_settings.getTableName(), - belongsToColumn: 'favicon_images', - belongsToId: site_settings.id, - }, - data.favicon_images, - options, - ); - - - return site_settings; - } - - static async deleteByIds(ids, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const site_settings = await db.site_settings.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); - - await db.sequelize.transaction(async (transaction) => { - for (const record of site_settings) { - await record.update( - {deletedBy: currentUser.id}, - {transaction} - ); - } - for (const record of site_settings) { - await record.destroy({transaction}); - } - }); - - - return site_settings; - } - - static async remove(id, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - const site_settings = await db.site_settings.findByPk(id, options); - - await site_settings.update({ - deletedBy: currentUser.id - }, { - transaction, - }); - - await site_settings.destroy({ - transaction - }); - - return site_settings; - } - - static async findBy(where, options) { - const transaction = (options && options.transaction) || undefined; - - const site_settings = await db.site_settings.findOne( - { where }, - { transaction }, - ); - - if (!site_settings) { - return site_settings; - } - - const output = site_settings.get({plain: true}); - - - - - - - - - - - - - - - - - output.logo_images = await site_settings.getLogo_images({ - transaction - }); - - - output.favicon_images = await site_settings.getFavicon_images({ - 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.file, - as: 'logo_images', - }, - - { - model: db.file, - as: 'favicon_images', - }, - - ]; - - if (filter) { - if (filter.id) { - where = { - ...where, - ['id']: Utils.uuid(filter.id), - }; - } - - - if (filter.site_name) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'site_settings', - 'site_name', - filter.site_name, - ), - }; - } - - if (filter.tagline) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'site_settings', - 'tagline', - filter.tagline, - ), - }; - } - - if (filter.primary_domain) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'site_settings', - 'primary_domain', - filter.primary_domain, - ), - }; - } - - if (filter.primary_cta_label) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'site_settings', - 'primary_cta_label', - filter.primary_cta_label, - ), - }; - } - - if (filter.primary_cta_url) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'site_settings', - 'primary_cta_url', - filter.primary_cta_url, - ), - }; - } - - if (filter.contact_email) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'site_settings', - 'contact_email', - filter.contact_email, - ), - }; - } - - if (filter.contact_phone) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'site_settings', - 'contact_phone', - filter.contact_phone, - ), - }; - } - - if (filter.location) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'site_settings', - 'location', - filter.location, - ), - }; - } - - if (filter.accent_color_hex) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'site_settings', - 'accent_color_hex', - filter.accent_color_hex, - ), - }; - } - - if (filter.seo_title) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'site_settings', - 'seo_title', - filter.seo_title, - ), - }; - } - - if (filter.seo_description) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'site_settings', - 'seo_description', - filter.seo_description, - ), - }; - } - - - - - - - - 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.site_settings.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( - 'site_settings', - 'site_name', - query, - ), - ], - }; - } - - const records = await db.site_settings.findAll({ - attributes: [ 'id', 'site_name' ], - where, - limit: limit ? Number(limit) : undefined, - offset: offset ? Number(offset) : undefined, - orderBy: [['site_name', 'ASC']], - }); - - return records.map((record) => ({ - id: record.id, - label: record.site_name, - })); - } - - -}; - diff --git a/backend/src/db/api/skills.js b/backend/src/db/api/skills.js deleted file mode 100644 index ee2f7c0..0000000 --- a/backend/src/db/api/skills.js +++ /dev/null @@ -1,455 +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 SkillsDBApi { - - - - static async create(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const skills = await db.skills.create( - { - id: data.id || undefined, - - name: data.name - || - null - , - - category: data.category - || - null - , - - proficiency_level: data.proficiency_level - || - null - , - - sort_order: data.sort_order - || - null - , - - is_featured: data.is_featured - || - false - - , - - importHash: data.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - - - - - - - return skills; - } - - - 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 skillsData = data.map((item, index) => ({ - id: item.id || undefined, - - name: item.name - || - null - , - - category: item.category - || - null - , - - proficiency_level: item.proficiency_level - || - null - , - - sort_order: item.sort_order - || - null - , - - is_featured: item.is_featured - || - false - - , - - importHash: item.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - createdAt: new Date(Date.now() + index * 1000), - })); - - // Bulk create items - const skills = await db.skills.bulkCreate(skillsData, { transaction }); - - // For each item created, replace relation files - - - return skills; - } - - static async update(id, data, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - - const skills = await db.skills.findByPk(id, {}, {transaction}); - - - - - const updatePayload = {}; - - if (data.name !== undefined) updatePayload.name = data.name; - - - if (data.category !== undefined) updatePayload.category = data.category; - - - if (data.proficiency_level !== undefined) updatePayload.proficiency_level = data.proficiency_level; - - - if (data.sort_order !== undefined) updatePayload.sort_order = data.sort_order; - - - if (data.is_featured !== undefined) updatePayload.is_featured = data.is_featured; - - - updatePayload.updatedById = currentUser.id; - - await skills.update(updatePayload, {transaction}); - - - - - - - - - - return skills; - } - - static async deleteByIds(ids, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const skills = await db.skills.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); - - await db.sequelize.transaction(async (transaction) => { - for (const record of skills) { - await record.update( - {deletedBy: currentUser.id}, - {transaction} - ); - } - for (const record of skills) { - await record.destroy({transaction}); - } - }); - - - return skills; - } - - static async remove(id, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - const skills = await db.skills.findByPk(id, options); - - await skills.update({ - deletedBy: currentUser.id - }, { - transaction, - }); - - await skills.destroy({ - transaction - }); - - return skills; - } - - static async findBy(where, options) { - const transaction = (options && options.transaction) || undefined; - - const skills = await db.skills.findOne( - { where }, - { transaction }, - ); - - if (!skills) { - return skills; - } - - const output = skills.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( - 'skills', - 'name', - filter.name, - ), - }; - } - - - - - - - if (filter.proficiency_levelRange) { - const [start, end] = filter.proficiency_levelRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - proficiency_level: { - ...where.proficiency_level, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - proficiency_level: { - ...where.proficiency_level, - [Op.lte]: end, - }, - }; - } - } - - if (filter.sort_orderRange) { - const [start, end] = filter.sort_orderRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - sort_order: { - ...where.sort_order, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - sort_order: { - ...where.sort_order, - [Op.lte]: end, - }, - }; - } - } - - - if (filter.active !== undefined) { - where = { - ...where, - active: filter.active === true || filter.active === 'true' - }; - } - - - if (filter.category) { - where = { - ...where, - category: filter.category, - }; - } - - if (filter.is_featured) { - where = { - ...where, - is_featured: filter.is_featured, - }; - } - - - - - - 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.skills.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( - 'skills', - 'name', - query, - ), - ], - }; - } - - const records = await db.skills.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/social_links.js b/backend/src/db/api/social_links.js deleted file mode 100644 index cd94d6c..0000000 --- a/backend/src/db/api/social_links.js +++ /dev/null @@ -1,442 +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 Social_linksDBApi { - - - - static async create(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const social_links = await db.social_links.create( - { - id: data.id || undefined, - - platform: data.platform - || - null - , - - label: data.label - || - null - , - - url: data.url - || - null - , - - sort_order: data.sort_order - || - null - , - - is_active: data.is_active - || - false - - , - - importHash: data.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - - - - - - - return social_links; - } - - - 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 social_linksData = data.map((item, index) => ({ - id: item.id || undefined, - - platform: item.platform - || - null - , - - label: item.label - || - null - , - - url: item.url - || - null - , - - sort_order: item.sort_order - || - 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 social_links = await db.social_links.bulkCreate(social_linksData, { transaction }); - - // For each item created, replace relation files - - - return social_links; - } - - static async update(id, data, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - - const social_links = await db.social_links.findByPk(id, {}, {transaction}); - - - - - const updatePayload = {}; - - if (data.platform !== undefined) updatePayload.platform = data.platform; - - - if (data.label !== undefined) updatePayload.label = data.label; - - - if (data.url !== undefined) updatePayload.url = data.url; - - - if (data.sort_order !== undefined) updatePayload.sort_order = data.sort_order; - - - if (data.is_active !== undefined) updatePayload.is_active = data.is_active; - - - updatePayload.updatedById = currentUser.id; - - await social_links.update(updatePayload, {transaction}); - - - - - - - - - - return social_links; - } - - static async deleteByIds(ids, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const social_links = await db.social_links.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); - - await db.sequelize.transaction(async (transaction) => { - for (const record of social_links) { - await record.update( - {deletedBy: currentUser.id}, - {transaction} - ); - } - for (const record of social_links) { - await record.destroy({transaction}); - } - }); - - - return social_links; - } - - static async remove(id, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - const social_links = await db.social_links.findByPk(id, options); - - await social_links.update({ - deletedBy: currentUser.id - }, { - transaction, - }); - - await social_links.destroy({ - transaction - }); - - return social_links; - } - - static async findBy(where, options) { - const transaction = (options && options.transaction) || undefined; - - const social_links = await db.social_links.findOne( - { where }, - { transaction }, - ); - - if (!social_links) { - return social_links; - } - - const output = social_links.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.label) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'social_links', - 'label', - filter.label, - ), - }; - } - - if (filter.url) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'social_links', - 'url', - filter.url, - ), - }; - } - - - - - - - if (filter.sort_orderRange) { - const [start, end] = filter.sort_orderRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - sort_order: { - ...where.sort_order, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - sort_order: { - ...where.sort_order, - [Op.lte]: end, - }, - }; - } - } - - - if (filter.active !== undefined) { - where = { - ...where, - active: filter.active === true || filter.active === 'true' - }; - } - - - if (filter.platform) { - where = { - ...where, - platform: filter.platform, - }; - } - - 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.social_links.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( - 'social_links', - 'label', - query, - ), - ], - }; - } - - const records = await db.social_links.findAll({ - attributes: [ 'id', 'label' ], - where, - limit: limit ? Number(limit) : undefined, - offset: offset ? Number(offset) : undefined, - orderBy: [['label', 'ASC']], - }); - - return records.map((record) => ({ - id: record.id, - label: record.label, - })); - } - - -}; - diff --git a/backend/src/db/api/testimonials.js b/backend/src/db/api/testimonials.js deleted file mode 100644 index c9a7474..0000000 --- a/backend/src/db/api/testimonials.js +++ /dev/null @@ -1,619 +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 TestimonialsDBApi { - - - - static async create(data, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const testimonials = await db.testimonials.create( - { - id: data.id || undefined, - - client_name: data.client_name - || - null - , - - client_title: data.client_title - || - null - , - - company_name: data.company_name - || - null - , - - quote: data.quote - || - null - , - - rating: data.rating - || - null - , - - source: data.source - || - null - , - - source_url: data.source_url - || - null - , - - testimonial_date: data.testimonial_date - || - null - , - - is_featured: data.is_featured - || - false - - , - - is_public: data.is_public - || - false - - , - - importHash: data.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - }, - { transaction }, - ); - - - - - - - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.testimonials.getTableName(), - belongsToColumn: 'client_avatars', - belongsToId: testimonials.id, - }, - data.client_avatars, - options, - ); - - - return testimonials; - } - - - 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 testimonialsData = data.map((item, index) => ({ - id: item.id || undefined, - - client_name: item.client_name - || - null - , - - client_title: item.client_title - || - null - , - - company_name: item.company_name - || - null - , - - quote: item.quote - || - null - , - - rating: item.rating - || - null - , - - source: item.source - || - null - , - - source_url: item.source_url - || - null - , - - testimonial_date: item.testimonial_date - || - null - , - - is_featured: item.is_featured - || - false - - , - - is_public: item.is_public - || - false - - , - - importHash: item.importHash || null, - createdById: currentUser.id, - updatedById: currentUser.id, - createdAt: new Date(Date.now() + index * 1000), - })); - - // Bulk create items - const testimonials = await db.testimonials.bulkCreate(testimonialsData, { transaction }); - - // For each item created, replace relation files - - for (let i = 0; i < testimonials.length; i++) { - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.testimonials.getTableName(), - belongsToColumn: 'client_avatars', - belongsToId: testimonials[i].id, - }, - data[i].client_avatars, - options, - ); - } - - - return testimonials; - } - - static async update(id, data, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - - const testimonials = await db.testimonials.findByPk(id, {}, {transaction}); - - - - - const updatePayload = {}; - - if (data.client_name !== undefined) updatePayload.client_name = data.client_name; - - - if (data.client_title !== undefined) updatePayload.client_title = data.client_title; - - - if (data.company_name !== undefined) updatePayload.company_name = data.company_name; - - - if (data.quote !== undefined) updatePayload.quote = data.quote; - - - if (data.rating !== undefined) updatePayload.rating = data.rating; - - - if (data.source !== undefined) updatePayload.source = data.source; - - - if (data.source_url !== undefined) updatePayload.source_url = data.source_url; - - - if (data.testimonial_date !== undefined) updatePayload.testimonial_date = data.testimonial_date; - - - if (data.is_featured !== undefined) updatePayload.is_featured = data.is_featured; - - - if (data.is_public !== undefined) updatePayload.is_public = data.is_public; - - - updatePayload.updatedById = currentUser.id; - - await testimonials.update(updatePayload, {transaction}); - - - - - - - - - await FileDBApi.replaceRelationFiles( - { - belongsTo: db.testimonials.getTableName(), - belongsToColumn: 'client_avatars', - belongsToId: testimonials.id, - }, - data.client_avatars, - options, - ); - - - return testimonials; - } - - static async deleteByIds(ids, options) { - const currentUser = (options && options.currentUser) || { id: null }; - const transaction = (options && options.transaction) || undefined; - - const testimonials = await db.testimonials.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); - - await db.sequelize.transaction(async (transaction) => { - for (const record of testimonials) { - await record.update( - {deletedBy: currentUser.id}, - {transaction} - ); - } - for (const record of testimonials) { - await record.destroy({transaction}); - } - }); - - - return testimonials; - } - - static async remove(id, options) { - const currentUser = (options && options.currentUser) || {id: null}; - const transaction = (options && options.transaction) || undefined; - - const testimonials = await db.testimonials.findByPk(id, options); - - await testimonials.update({ - deletedBy: currentUser.id - }, { - transaction, - }); - - await testimonials.destroy({ - transaction - }); - - return testimonials; - } - - static async findBy(where, options) { - const transaction = (options && options.transaction) || undefined; - - const testimonials = await db.testimonials.findOne( - { where }, - { transaction }, - ); - - if (!testimonials) { - return testimonials; - } - - const output = testimonials.get({plain: true}); - - - - - - - - - - - - - - - - - output.client_avatars = await testimonials.getClient_avatars({ - 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.file, - as: 'client_avatars', - }, - - ]; - - if (filter) { - if (filter.id) { - where = { - ...where, - ['id']: Utils.uuid(filter.id), - }; - } - - - if (filter.client_name) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'testimonials', - 'client_name', - filter.client_name, - ), - }; - } - - if (filter.client_title) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'testimonials', - 'client_title', - filter.client_title, - ), - }; - } - - if (filter.company_name) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'testimonials', - 'company_name', - filter.company_name, - ), - }; - } - - if (filter.quote) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'testimonials', - 'quote', - filter.quote, - ), - }; - } - - if (filter.source) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'testimonials', - 'source', - filter.source, - ), - }; - } - - if (filter.source_url) { - where = { - ...where, - [Op.and]: Utils.ilike( - 'testimonials', - 'source_url', - filter.source_url, - ), - }; - } - - - - - - - if (filter.ratingRange) { - const [start, end] = filter.ratingRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - rating: { - ...where.rating, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - rating: { - ...where.rating, - [Op.lte]: end, - }, - }; - } - } - - if (filter.testimonial_dateRange) { - const [start, end] = filter.testimonial_dateRange; - - if (start !== undefined && start !== null && start !== '') { - where = { - ...where, - testimonial_date: { - ...where.testimonial_date, - [Op.gte]: start, - }, - }; - } - - if (end !== undefined && end !== null && end !== '') { - where = { - ...where, - testimonial_date: { - ...where.testimonial_date, - [Op.lte]: end, - }, - }; - } - } - - - if (filter.active !== undefined) { - where = { - ...where, - active: filter.active === true || filter.active === 'true' - }; - } - - - if (filter.is_featured) { - where = { - ...where, - is_featured: filter.is_featured, - }; - } - - if (filter.is_public) { - where = { - ...where, - is_public: filter.is_public, - }; - } - - - - - - 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.testimonials.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( - 'testimonials', - 'client_name', - query, - ), - ], - }; - } - - const records = await db.testimonials.findAll({ - attributes: [ 'id', 'client_name' ], - where, - limit: limit ? Number(limit) : undefined, - offset: offset ? Number(offset) : undefined, - orderBy: [['client_name', 'ASC']], - }); - - return records.map((record) => ({ - id: record.id, - label: record.client_name, - })); - } - - -}; - diff --git a/backend/src/db/api/users.js b/backend/src/db/api/users.js deleted file mode 100644 index 6c9d2af..0000000 --- a/backend/src/db/api/users.js +++ /dev/null @@ -1,945 +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.pages_author = await users.getPages_author({ - transaction - }); - - - - - - - - - - output.inquiries_assigned_to = await users.getInquiries_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 b39d5e8..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_blackness_studio_website', - 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/1770697522414.js b/backend/src/db/migrations/1770697522414.js deleted file mode 100644 index eef5452..0000000 --- a/backend/src/db/migrations/1770697522414.js +++ /dev/null @@ -1,3012 +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('site_settings', { - 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('pages', { - 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('page_sections', { - 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('services', { - 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('portfolio_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('testimonials', { - 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('skills', { - 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('benefits', { - 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('social_links', { - 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('inquiries', { - 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( - 'site_settings', - 'site_name', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'site_settings', - 'tagline', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'site_settings', - 'primary_domain', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'site_settings', - 'primary_cta_label', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'site_settings', - 'primary_cta_url', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'site_settings', - 'contact_email', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'site_settings', - 'contact_phone', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'site_settings', - 'location', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'site_settings', - 'accent_color_hex', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'site_settings', - 'seo_title', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'site_settings', - 'seo_description', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - - - - - await queryInterface.addColumn( - 'pages', - 'title', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'pages', - 'slug', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'pages', - 'status', - { - type: Sequelize.DataTypes.ENUM, - - - values: ['draft','published'], - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'pages', - 'sort_order', - { - type: Sequelize.DataTypes.INTEGER, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'pages', - 'meta_title', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'pages', - 'meta_description', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'pages', - 'show_in_header_nav', - { - type: Sequelize.DataTypes.BOOLEAN, - - defaultValue: false, - allowNull: false, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'pages', - 'show_in_footer_nav', - { - type: Sequelize.DataTypes.BOOLEAN, - - defaultValue: false, - allowNull: false, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'pages', - 'authorId', - { - type: Sequelize.DataTypes.UUID, - - - - references: { - model: 'users', - key: 'id', - }, - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'page_sections', - 'pageId', - { - type: Sequelize.DataTypes.UUID, - - - - references: { - model: 'pages', - key: 'id', - }, - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'page_sections', - 'section_type', - { - type: Sequelize.DataTypes.ENUM, - - - values: ['hero','about','services','portfolio','why_choose_me','testimonials','final_cta','footer'], - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'page_sections', - 'section_label', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'page_sections', - 'headline', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'page_sections', - 'subheadline', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'page_sections', - 'body', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - - - await queryInterface.addColumn( - 'page_sections', - 'primary_button_label', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'page_sections', - 'primary_button_url', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'page_sections', - 'secondary_button_label', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'page_sections', - 'secondary_button_url', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'page_sections', - 'sort_order', - { - type: Sequelize.DataTypes.INTEGER, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'page_sections', - 'is_visible', - { - type: Sequelize.DataTypes.BOOLEAN, - - defaultValue: false, - allowNull: false, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'services', - 'name', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'services', - 'short_description', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'services', - 'details', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'services', - 'category', - { - type: Sequelize.DataTypes.ENUM, - - - values: ['blog_writing','technical_documentation','tutorials','product_reviews','guides','other'], - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'services', - 'sort_order', - { - type: Sequelize.DataTypes.INTEGER, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'services', - 'is_featured', - { - type: Sequelize.DataTypes.BOOLEAN, - - defaultValue: false, - allowNull: false, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'services', - 'is_active', - { - type: Sequelize.DataTypes.BOOLEAN, - - defaultValue: false, - allowNull: false, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'services', - 'cta_label', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'services', - 'cta_url', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'services', - 'icon_name', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'portfolio_items', - 'title', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'portfolio_items', - 'work_type', - { - type: Sequelize.DataTypes.ENUM, - - - values: ['blog','documentation','tutorial','review','guide','case_study','other'], - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'portfolio_items', - 'client_name', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'portfolio_items', - 'summary', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'portfolio_items', - 'case_study', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - - - - - await queryInterface.addColumn( - 'portfolio_items', - 'external_url', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'portfolio_items', - 'tech_stack', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'portfolio_items', - 'published_on', - { - type: Sequelize.DataTypes.DATE, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'portfolio_items', - 'is_featured', - { - type: Sequelize.DataTypes.BOOLEAN, - - defaultValue: false, - allowNull: false, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'portfolio_items', - 'is_public', - { - type: Sequelize.DataTypes.BOOLEAN, - - defaultValue: false, - allowNull: false, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'testimonials', - 'client_name', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'testimonials', - 'client_title', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'testimonials', - 'company_name', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'testimonials', - 'quote', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'testimonials', - 'rating', - { - type: Sequelize.DataTypes.INTEGER, - - - - }, - { transaction } - ); - - - - - - - await queryInterface.addColumn( - 'testimonials', - 'source', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'testimonials', - 'source_url', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'testimonials', - 'testimonial_date', - { - type: Sequelize.DataTypes.DATE, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'testimonials', - 'is_featured', - { - type: Sequelize.DataTypes.BOOLEAN, - - defaultValue: false, - allowNull: false, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'testimonials', - 'is_public', - { - type: Sequelize.DataTypes.BOOLEAN, - - defaultValue: false, - allowNull: false, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'skills', - 'name', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'skills', - 'category', - { - type: Sequelize.DataTypes.ENUM, - - - values: ['writing','technical','tools','domain'], - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'skills', - 'proficiency_level', - { - type: Sequelize.DataTypes.INTEGER, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'skills', - 'sort_order', - { - type: Sequelize.DataTypes.INTEGER, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'skills', - 'is_featured', - { - type: Sequelize.DataTypes.BOOLEAN, - - defaultValue: false, - allowNull: false, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'benefits', - 'title', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'benefits', - 'description', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'benefits', - 'icon_name', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'benefits', - 'sort_order', - { - type: Sequelize.DataTypes.INTEGER, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'benefits', - 'is_active', - { - type: Sequelize.DataTypes.BOOLEAN, - - defaultValue: false, - allowNull: false, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'social_links', - 'platform', - { - type: Sequelize.DataTypes.ENUM, - - - values: ['linkedin','github','x','medium','youtube','website','other'], - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'social_links', - 'label', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'social_links', - 'url', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'social_links', - 'sort_order', - { - type: Sequelize.DataTypes.INTEGER, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'social_links', - 'is_active', - { - type: Sequelize.DataTypes.BOOLEAN, - - defaultValue: false, - allowNull: false, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'inquiries', - 'full_name', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'inquiries', - 'email', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'inquiries', - 'company_name', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'inquiries', - 'subject', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'inquiries', - 'message', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'inquiries', - 'source_page', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'inquiries', - 'status', - { - type: Sequelize.DataTypes.ENUM, - - - values: ['new','in_review','replied','archived'], - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'inquiries', - 'received_at', - { - type: Sequelize.DataTypes.DATE, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'inquiries', - 'replied_at', - { - type: Sequelize.DataTypes.DATE, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'inquiries', - 'fiverr_url', - { - type: Sequelize.DataTypes.TEXT, - - - - }, - { transaction } - ); - - - - - await queryInterface.addColumn( - 'inquiries', - 'assigned_toId', - { - type: Sequelize.DataTypes.UUID, - - - - references: { - model: 'users', - key: 'id', - }, - - }, - { 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( - 'inquiries', - 'assigned_toId', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'inquiries', - 'fiverr_url', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'inquiries', - 'replied_at', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'inquiries', - 'received_at', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'inquiries', - 'status', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'inquiries', - 'source_page', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'inquiries', - 'message', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'inquiries', - 'subject', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'inquiries', - 'company_name', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'inquiries', - 'email', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'inquiries', - 'full_name', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'social_links', - 'is_active', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'social_links', - 'sort_order', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'social_links', - 'url', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'social_links', - 'label', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'social_links', - 'platform', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'benefits', - 'is_active', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'benefits', - 'sort_order', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'benefits', - 'icon_name', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'benefits', - 'description', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'benefits', - 'title', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'skills', - 'is_featured', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'skills', - 'sort_order', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'skills', - 'proficiency_level', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'skills', - 'category', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'skills', - 'name', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'testimonials', - 'is_public', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'testimonials', - 'is_featured', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'testimonials', - 'testimonial_date', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'testimonials', - 'source_url', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'testimonials', - 'source', - { transaction } - ); - - - - - - await queryInterface.removeColumn( - 'testimonials', - 'rating', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'testimonials', - 'quote', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'testimonials', - 'company_name', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'testimonials', - 'client_title', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'testimonials', - 'client_name', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'portfolio_items', - 'is_public', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'portfolio_items', - 'is_featured', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'portfolio_items', - 'published_on', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'portfolio_items', - 'tech_stack', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'portfolio_items', - 'external_url', - { transaction } - ); - - - - - - - - await queryInterface.removeColumn( - 'portfolio_items', - 'case_study', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'portfolio_items', - 'summary', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'portfolio_items', - 'client_name', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'portfolio_items', - 'work_type', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'portfolio_items', - 'title', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'services', - 'icon_name', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'services', - 'cta_url', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'services', - 'cta_label', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'services', - 'is_active', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'services', - 'is_featured', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'services', - 'sort_order', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'services', - 'category', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'services', - 'details', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'services', - 'short_description', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'services', - 'name', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'page_sections', - 'is_visible', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'page_sections', - 'sort_order', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'page_sections', - 'secondary_button_url', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'page_sections', - 'secondary_button_label', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'page_sections', - 'primary_button_url', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'page_sections', - 'primary_button_label', - { transaction } - ); - - - - - - await queryInterface.removeColumn( - 'page_sections', - 'body', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'page_sections', - 'subheadline', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'page_sections', - 'headline', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'page_sections', - 'section_label', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'page_sections', - 'section_type', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'page_sections', - 'pageId', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'pages', - 'authorId', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'pages', - 'show_in_footer_nav', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'pages', - 'show_in_header_nav', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'pages', - 'meta_description', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'pages', - 'meta_title', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'pages', - 'sort_order', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'pages', - 'status', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'pages', - 'slug', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'pages', - 'title', - { transaction } - ); - - - - - - - - await queryInterface.removeColumn( - 'site_settings', - 'seo_description', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'site_settings', - 'seo_title', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'site_settings', - 'accent_color_hex', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'site_settings', - 'location', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'site_settings', - 'contact_phone', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'site_settings', - 'contact_email', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'site_settings', - 'primary_cta_url', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'site_settings', - 'primary_cta_label', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'site_settings', - 'primary_domain', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'site_settings', - 'tagline', - { transaction } - ); - - - - await queryInterface.removeColumn( - 'site_settings', - 'site_name', - { 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('inquiries', { transaction }); - - - - await queryInterface.dropTable('social_links', { transaction }); - - - - await queryInterface.dropTable('benefits', { transaction }); - - - - await queryInterface.dropTable('skills', { transaction }); - - - - await queryInterface.dropTable('testimonials', { transaction }); - - - - await queryInterface.dropTable('portfolio_items', { transaction }); - - - - await queryInterface.dropTable('services', { transaction }); - - - - await queryInterface.dropTable('page_sections', { transaction }); - - - - await queryInterface.dropTable('pages', { transaction }); - - - - await queryInterface.dropTable('site_settings', { 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/models/benefits.js b/backend/src/db/models/benefits.js deleted file mode 100644 index 9016700..0000000 --- a/backend/src/db/models/benefits.js +++ /dev/null @@ -1,109 +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 benefits = sequelize.define( - 'benefits', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - -title: { - type: DataTypes.TEXT, - - - - }, - -description: { - type: DataTypes.TEXT, - - - - }, - -icon_name: { - type: DataTypes.TEXT, - - - - }, - -sort_order: { - type: DataTypes.INTEGER, - - - - }, - -is_active: { - type: DataTypes.BOOLEAN, - - allowNull: false, - defaultValue: false, - - - - }, - - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { - timestamps: true, - paranoid: true, - freezeTableName: true, - }, - ); - - benefits.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.benefits.belongsTo(db.users, { - as: 'createdBy', - }); - - db.benefits.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - - - return benefits; -}; - - 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/inquiries.js b/backend/src/db/models/inquiries.js deleted file mode 100644 index 6497807..0000000 --- a/backend/src/db/models/inquiries.js +++ /dev/null @@ -1,164 +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 inquiries = sequelize.define( - 'inquiries', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - -full_name: { - type: DataTypes.TEXT, - - - - }, - -email: { - type: DataTypes.TEXT, - - - - }, - -company_name: { - type: DataTypes.TEXT, - - - - }, - -subject: { - type: DataTypes.TEXT, - - - - }, - -message: { - type: DataTypes.TEXT, - - - - }, - -source_page: { - type: DataTypes.TEXT, - - - - }, - -status: { - type: DataTypes.ENUM, - - - - values: [ - -"new", - - -"in_review", - - -"replied", - - -"archived" - - ], - - }, - -received_at: { - type: DataTypes.DATE, - - - - }, - -replied_at: { - type: DataTypes.DATE, - - - - }, - -fiverr_url: { - type: DataTypes.TEXT, - - - - }, - - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { - timestamps: true, - paranoid: true, - freezeTableName: true, - }, - ); - - inquiries.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.inquiries.belongsTo(db.users, { - as: 'assigned_to', - foreignKey: { - name: 'assigned_toId', - }, - constraints: false, - }); - - - - - db.inquiries.belongsTo(db.users, { - as: 'createdBy', - }); - - db.inquiries.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - - - return inquiries; -}; - - diff --git a/backend/src/db/models/page_sections.js b/backend/src/db/models/page_sections.js deleted file mode 100644 index 4b5cf5a..0000000 --- a/backend/src/db/models/page_sections.js +++ /dev/null @@ -1,196 +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 page_sections = sequelize.define( - 'page_sections', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - -section_type: { - type: DataTypes.ENUM, - - - - values: [ - -"hero", - - -"about", - - -"services", - - -"portfolio", - - -"why_choose_me", - - -"testimonials", - - -"final_cta", - - -"footer" - - ], - - }, - -section_label: { - type: DataTypes.TEXT, - - - - }, - -headline: { - type: DataTypes.TEXT, - - - - }, - -subheadline: { - type: DataTypes.TEXT, - - - - }, - -body: { - type: DataTypes.TEXT, - - - - }, - -primary_button_label: { - type: DataTypes.TEXT, - - - - }, - -primary_button_url: { - type: DataTypes.TEXT, - - - - }, - -secondary_button_label: { - type: DataTypes.TEXT, - - - - }, - -secondary_button_url: { - type: DataTypes.TEXT, - - - - }, - -sort_order: { - type: DataTypes.INTEGER, - - - - }, - -is_visible: { - type: DataTypes.BOOLEAN, - - allowNull: false, - defaultValue: false, - - - - }, - - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { - timestamps: true, - paranoid: true, - freezeTableName: true, - }, - ); - - page_sections.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.page_sections.belongsTo(db.pages, { - as: 'page', - foreignKey: { - name: 'pageId', - }, - constraints: false, - }); - - - - db.page_sections.hasMany(db.file, { - as: 'background_images', - foreignKey: 'belongsToId', - constraints: false, - scope: { - belongsTo: db.page_sections.getTableName(), - belongsToColumn: 'background_images', - }, - }); - - - db.page_sections.belongsTo(db.users, { - as: 'createdBy', - }); - - db.page_sections.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - - - return page_sections; -}; - - diff --git a/backend/src/db/models/pages.js b/backend/src/db/models/pages.js deleted file mode 100644 index 86513dc..0000000 --- a/backend/src/db/models/pages.js +++ /dev/null @@ -1,158 +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 pages = sequelize.define( - 'pages', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - -title: { - type: DataTypes.TEXT, - - - - }, - -slug: { - type: DataTypes.TEXT, - - - - }, - -status: { - type: DataTypes.ENUM, - - - - values: [ - -"draft", - - -"published" - - ], - - }, - -sort_order: { - type: DataTypes.INTEGER, - - - - }, - -meta_title: { - type: DataTypes.TEXT, - - - - }, - -meta_description: { - type: DataTypes.TEXT, - - - - }, - -show_in_header_nav: { - type: DataTypes.BOOLEAN, - - allowNull: false, - defaultValue: false, - - - - }, - -show_in_footer_nav: { - type: DataTypes.BOOLEAN, - - allowNull: false, - defaultValue: false, - - - - }, - - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { - timestamps: true, - paranoid: true, - freezeTableName: true, - }, - ); - - pages.associate = (db) => { - - -/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity - - - - - - - - db.pages.hasMany(db.page_sections, { - as: 'page_sections_page', - foreignKey: { - name: 'pageId', - }, - constraints: false, - }); - - - - - - - - - - -//end loop - - - - db.pages.belongsTo(db.users, { - as: 'author', - foreignKey: { - name: 'authorId', - }, - constraints: false, - }); - - - - - db.pages.belongsTo(db.users, { - as: 'createdBy', - }); - - db.pages.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - - - return pages; -}; - - diff --git a/backend/src/db/models/permissions.js b/backend/src/db/models/permissions.js deleted file mode 100644 index 2a3e71a..0000000 --- a/backend/src/db/models/permissions.js +++ /dev/null @@ -1,78 +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/portfolio_items.js b/backend/src/db/models/portfolio_items.js deleted file mode 100644 index 091d49d..0000000 --- a/backend/src/db/models/portfolio_items.js +++ /dev/null @@ -1,191 +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 portfolio_items = sequelize.define( - 'portfolio_items', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - -title: { - type: DataTypes.TEXT, - - - - }, - -work_type: { - type: DataTypes.ENUM, - - - - values: [ - -"blog", - - -"documentation", - - -"tutorial", - - -"review", - - -"guide", - - -"case_study", - - -"other" - - ], - - }, - -client_name: { - type: DataTypes.TEXT, - - - - }, - -summary: { - type: DataTypes.TEXT, - - - - }, - -case_study: { - type: DataTypes.TEXT, - - - - }, - -external_url: { - type: DataTypes.TEXT, - - - - }, - -tech_stack: { - type: DataTypes.TEXT, - - - - }, - -published_on: { - type: DataTypes.DATE, - - - - }, - -is_featured: { - type: DataTypes.BOOLEAN, - - allowNull: false, - defaultValue: false, - - - - }, - -is_public: { - type: DataTypes.BOOLEAN, - - allowNull: false, - defaultValue: false, - - - - }, - - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { - timestamps: true, - paranoid: true, - freezeTableName: true, - }, - ); - - portfolio_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.portfolio_items.hasMany(db.file, { - as: 'screenshots', - foreignKey: 'belongsToId', - constraints: false, - scope: { - belongsTo: db.portfolio_items.getTableName(), - belongsToColumn: 'screenshots', - }, - }); - - db.portfolio_items.hasMany(db.file, { - as: 'attachments', - foreignKey: 'belongsToId', - constraints: false, - scope: { - belongsTo: db.portfolio_items.getTableName(), - belongsToColumn: 'attachments', - }, - }); - - - db.portfolio_items.belongsTo(db.users, { - as: 'createdBy', - }); - - db.portfolio_items.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - - - return portfolio_items; -}; - - diff --git a/backend/src/db/models/roles.js b/backend/src/db/models/roles.js deleted file mode 100644 index e2137a2..0000000 --- a/backend/src/db/models/roles.js +++ /dev/null @@ -1,111 +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/services.js b/backend/src/db/models/services.js deleted file mode 100644 index 7d8263a..0000000 --- a/backend/src/db/models/services.js +++ /dev/null @@ -1,168 +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 services = sequelize.define( - 'services', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - -name: { - type: DataTypes.TEXT, - - - - }, - -short_description: { - type: DataTypes.TEXT, - - - - }, - -details: { - type: DataTypes.TEXT, - - - - }, - -category: { - type: DataTypes.ENUM, - - - - values: [ - -"blog_writing", - - -"technical_documentation", - - -"tutorials", - - -"product_reviews", - - -"guides", - - -"other" - - ], - - }, - -sort_order: { - type: DataTypes.INTEGER, - - - - }, - -is_featured: { - type: DataTypes.BOOLEAN, - - allowNull: false, - defaultValue: false, - - - - }, - -is_active: { - type: DataTypes.BOOLEAN, - - allowNull: false, - defaultValue: false, - - - - }, - -cta_label: { - type: DataTypes.TEXT, - - - - }, - -cta_url: { - type: DataTypes.TEXT, - - - - }, - -icon_name: { - type: DataTypes.TEXT, - - - - }, - - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { - timestamps: true, - paranoid: true, - freezeTableName: true, - }, - ); - - services.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.services.belongsTo(db.users, { - as: 'createdBy', - }); - - db.services.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - - - return services; -}; - - diff --git a/backend/src/db/models/site_settings.js b/backend/src/db/models/site_settings.js deleted file mode 100644 index cc12694..0000000 --- a/backend/src/db/models/site_settings.js +++ /dev/null @@ -1,168 +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 site_settings = sequelize.define( - 'site_settings', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - -site_name: { - type: DataTypes.TEXT, - - - - }, - -tagline: { - type: DataTypes.TEXT, - - - - }, - -primary_domain: { - type: DataTypes.TEXT, - - - - }, - -primary_cta_label: { - type: DataTypes.TEXT, - - - - }, - -primary_cta_url: { - type: DataTypes.TEXT, - - - - }, - -contact_email: { - type: DataTypes.TEXT, - - - - }, - -contact_phone: { - type: DataTypes.TEXT, - - - - }, - -location: { - type: DataTypes.TEXT, - - - - }, - -accent_color_hex: { - type: DataTypes.TEXT, - - - - }, - -seo_title: { - type: DataTypes.TEXT, - - - - }, - -seo_description: { - type: DataTypes.TEXT, - - - - }, - - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { - timestamps: true, - paranoid: true, - freezeTableName: true, - }, - ); - - site_settings.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.site_settings.hasMany(db.file, { - as: 'logo_images', - foreignKey: 'belongsToId', - constraints: false, - scope: { - belongsTo: db.site_settings.getTableName(), - belongsToColumn: 'logo_images', - }, - }); - - db.site_settings.hasMany(db.file, { - as: 'favicon_images', - foreignKey: 'belongsToId', - constraints: false, - scope: { - belongsTo: db.site_settings.getTableName(), - belongsToColumn: 'favicon_images', - }, - }); - - - db.site_settings.belongsTo(db.users, { - as: 'createdBy', - }); - - db.site_settings.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - - - return site_settings; -}; - - diff --git a/backend/src/db/models/skills.js b/backend/src/db/models/skills.js deleted file mode 100644 index 76621d1..0000000 --- a/backend/src/db/models/skills.js +++ /dev/null @@ -1,124 +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 skills = sequelize.define( - 'skills', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - -name: { - type: DataTypes.TEXT, - - - - }, - -category: { - type: DataTypes.ENUM, - - - - values: [ - -"writing", - - -"technical", - - -"tools", - - -"domain" - - ], - - }, - -proficiency_level: { - type: DataTypes.INTEGER, - - - - }, - -sort_order: { - type: DataTypes.INTEGER, - - - - }, - -is_featured: { - type: DataTypes.BOOLEAN, - - allowNull: false, - defaultValue: false, - - - - }, - - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { - timestamps: true, - paranoid: true, - freezeTableName: true, - }, - ); - - skills.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.skills.belongsTo(db.users, { - as: 'createdBy', - }); - - db.skills.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - - - return skills; -}; - - diff --git a/backend/src/db/models/social_links.js b/backend/src/db/models/social_links.js deleted file mode 100644 index 39965bc..0000000 --- a/backend/src/db/models/social_links.js +++ /dev/null @@ -1,133 +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 social_links = sequelize.define( - 'social_links', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - -platform: { - type: DataTypes.ENUM, - - - - values: [ - -"linkedin", - - -"github", - - -"x", - - -"medium", - - -"youtube", - - -"website", - - -"other" - - ], - - }, - -label: { - type: DataTypes.TEXT, - - - - }, - -url: { - type: DataTypes.TEXT, - - - - }, - -sort_order: { - type: DataTypes.INTEGER, - - - - }, - -is_active: { - type: DataTypes.BOOLEAN, - - allowNull: false, - defaultValue: false, - - - - }, - - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { - timestamps: true, - paranoid: true, - freezeTableName: true, - }, - ); - - social_links.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.social_links.belongsTo(db.users, { - as: 'createdBy', - }); - - db.social_links.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - - - return social_links; -}; - - diff --git a/backend/src/db/models/testimonials.js b/backend/src/db/models/testimonials.js deleted file mode 100644 index 65deb8e..0000000 --- a/backend/src/db/models/testimonials.js +++ /dev/null @@ -1,157 +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 testimonials = sequelize.define( - 'testimonials', - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - -client_name: { - type: DataTypes.TEXT, - - - - }, - -client_title: { - type: DataTypes.TEXT, - - - - }, - -company_name: { - type: DataTypes.TEXT, - - - - }, - -quote: { - type: DataTypes.TEXT, - - - - }, - -rating: { - type: DataTypes.INTEGER, - - - - }, - -source: { - type: DataTypes.TEXT, - - - - }, - -source_url: { - type: DataTypes.TEXT, - - - - }, - -testimonial_date: { - type: DataTypes.DATE, - - - - }, - -is_featured: { - type: DataTypes.BOOLEAN, - - allowNull: false, - defaultValue: false, - - - - }, - -is_public: { - type: DataTypes.BOOLEAN, - - allowNull: false, - defaultValue: false, - - - - }, - - importHash: { - type: DataTypes.STRING(255), - allowNull: true, - unique: true, - }, - }, - { - timestamps: true, - paranoid: true, - freezeTableName: true, - }, - ); - - testimonials.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.testimonials.hasMany(db.file, { - as: 'client_avatars', - foreignKey: 'belongsToId', - constraints: false, - scope: { - belongsTo: db.testimonials.getTableName(), - belongsToColumn: 'client_avatars', - }, - }); - - - db.testimonials.belongsTo(db.users, { - as: 'createdBy', - }); - - db.testimonials.belongsTo(db.users, { - as: 'updatedBy', - }); - }; - - - - return testimonials; -}; - - diff --git a/backend/src/db/models/users.js b/backend/src/db/models/users.js deleted file mode 100644 index 50def1f..0000000 --- a/backend/src/db/models/users.js +++ /dev/null @@ -1,252 +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.pages, { - as: 'pages_author', - foreignKey: { - name: 'authorId', - }, - constraints: false, - }); - - - - - - - - - - db.users.hasMany(db.inquiries, { - as: 'inquiries_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 7a52da6..0000000 --- a/backend/src/db/seeders/20200430130760-user-roles.js +++ /dev/null @@ -1,1060 +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("StudioOwner"), name: "Studio Owner", createdAt, updatedAt }, - - { id: getId("ContentManager"), name: "Content Manager", createdAt, updatedAt }, - - { id: getId("PortfolioCurator"), name: "Portfolio Curator", createdAt, updatedAt }, - - { id: getId("SupportSpecialist"), name: "Support Specialist", createdAt, updatedAt }, - - { id: getId("AnalyticsViewer"), name: "Analytics Viewer", 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","site_settings","pages","page_sections","services","portfolio_items","testimonials","skills","benefits","social_links","inquiries",, - ]; -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("StudioOwner"), permissionId: getId('CREATE_USERS') }, - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("StudioOwner"), permissionId: getId('CREATE_SITE_SETTINGS') }, - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("StudioOwner"), permissionId: getId('CREATE_PAGES') }, - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("ContentManager"), permissionId: getId('CREATE_PAGES') }, - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("StudioOwner"), permissionId: getId('CREATE_PAGE_SECTIONS') }, - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("ContentManager"), permissionId: getId('CREATE_PAGE_SECTIONS') }, - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("StudioOwner"), permissionId: getId('CREATE_SERVICES') }, - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("ContentManager"), permissionId: getId('CREATE_SERVICES') }, - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("StudioOwner"), permissionId: getId('CREATE_PORTFOLIO_ITEMS') }, - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("ContentManager"), permissionId: getId('CREATE_PORTFOLIO_ITEMS') }, - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("PortfolioCurator"), permissionId: getId('CREATE_PORTFOLIO_ITEMS') }, - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("StudioOwner"), permissionId: getId('CREATE_TESTIMONIALS') }, - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("ContentManager"), permissionId: getId('CREATE_TESTIMONIALS') }, - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("PortfolioCurator"), permissionId: getId('CREATE_TESTIMONIALS') }, - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("StudioOwner"), permissionId: getId('CREATE_SKILLS') }, - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("ContentManager"), permissionId: getId('CREATE_SKILLS') }, - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("StudioOwner"), permissionId: getId('CREATE_BENEFITS') }, - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("ContentManager"), permissionId: getId('CREATE_BENEFITS') }, - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("StudioOwner"), permissionId: getId('CREATE_SOCIAL_LINKS') }, - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("ContentManager"), permissionId: getId('CREATE_SOCIAL_LINKS') }, - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("StudioOwner"), permissionId: getId('CREATE_INQUIRIES') }, - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("SupportSpecialist"), permissionId: getId('CREATE_INQUIRIES') }, - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { createdAt, updatedAt, roles_permissionsId: getId("StudioOwner"), permissionId: getId('CREATE_SEARCH') }, - - { createdAt, updatedAt, roles_permissionsId: getId("ContentManager"), permissionId: getId('CREATE_SEARCH') }, - - { createdAt, updatedAt, roles_permissionsId: getId("PortfolioCurator"), permissionId: getId('CREATE_SEARCH') }, - - { createdAt, updatedAt, roles_permissionsId: getId("SupportSpecialist"), permissionId: getId('CREATE_SEARCH') }, - - { createdAt, updatedAt, roles_permissionsId: getId("AnalyticsViewer"), 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_SITE_SETTINGS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_SITE_SETTINGS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('UPDATE_SITE_SETTINGS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('DELETE_SITE_SETTINGS') }, - - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('CREATE_PAGES') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_PAGES') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('UPDATE_PAGES') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('DELETE_PAGES') }, - - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('CREATE_PAGE_SECTIONS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_PAGE_SECTIONS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('UPDATE_PAGE_SECTIONS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('DELETE_PAGE_SECTIONS') }, - - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('CREATE_SERVICES') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_SERVICES') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('UPDATE_SERVICES') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('DELETE_SERVICES') }, - - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('CREATE_PORTFOLIO_ITEMS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_PORTFOLIO_ITEMS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('UPDATE_PORTFOLIO_ITEMS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('DELETE_PORTFOLIO_ITEMS') }, - - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('CREATE_TESTIMONIALS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_TESTIMONIALS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('UPDATE_TESTIMONIALS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('DELETE_TESTIMONIALS') }, - - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('CREATE_SKILLS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_SKILLS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('UPDATE_SKILLS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('DELETE_SKILLS') }, - - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('CREATE_BENEFITS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_BENEFITS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('UPDATE_BENEFITS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('DELETE_BENEFITS') }, - - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('CREATE_SOCIAL_LINKS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_SOCIAL_LINKS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('UPDATE_SOCIAL_LINKS') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('DELETE_SOCIAL_LINKS') }, - - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('CREATE_INQUIRIES') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('READ_INQUIRIES') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('UPDATE_INQUIRIES') }, - { createdAt, updatedAt, roles_permissionsId: getId("Administrator"), permissionId: getId('DELETE_INQUIRIES') }, - - - - { 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("StudioOwner")}' WHERE "email"='client@hello.com'`); - await queryInterface.sequelize.query(`UPDATE "users" SET "app_roleId"='${getId("ContentManager")}' 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 f78dd77..0000000 --- a/backend/src/db/seeders/20231127130745-sample-data.js +++ /dev/null @@ -1,3725 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - -const db = require('../models'); -const Users = db.users; - - - - - - -const SiteSettings = db.site_settings; - -const Pages = db.pages; - -const PageSections = db.page_sections; - -const Services = db.services; - -const PortfolioItems = db.portfolio_items; - -const Testimonials = db.testimonials; - -const Skills = db.skills; - -const Benefits = db.benefits; - -const SocialLinks = db.social_links; - -const Inquiries = db.inquiries; - - - - - - - -const SiteSettingsData = [ - - { - - - - - "site_name": "Ada Lovelace", - - - - - - - "tagline": "Marie Curie", - - - - - - - "primary_domain": "Ada Lovelace", - - - - - - - "primary_cta_label": "Grace Hopper", - - - - - - - "primary_cta_url": "Ada Lovelace", - - - - - - - "contact_email": "Ada Lovelace", - - - - - - - "contact_phone": "Alan Turing", - - - - - - - "location": "Grace Hopper", - - - - - - - "accent_color_hex": "Grace Hopper", - - - - - - - "seo_title": "Grace Hopper", - - - - - - - "seo_description": "Alan Turing", - - - - - - - // type code here for "images" field - - - - - - - // type code here for "images" field - - - - }, - - { - - - - - "site_name": "Ada Lovelace", - - - - - - - "tagline": "Grace Hopper", - - - - - - - "primary_domain": "Alan Turing", - - - - - - - "primary_cta_label": "Ada Lovelace", - - - - - - - "primary_cta_url": "Alan Turing", - - - - - - - "contact_email": "Grace Hopper", - - - - - - - "contact_phone": "Marie Curie", - - - - - - - "location": "Marie Curie", - - - - - - - "accent_color_hex": "Alan Turing", - - - - - - - "seo_title": "Marie Curie", - - - - - - - "seo_description": "Marie Curie", - - - - - - - // type code here for "images" field - - - - - - - // type code here for "images" field - - - - }, - - { - - - - - "site_name": "Marie Curie", - - - - - - - "tagline": "Marie Curie", - - - - - - - "primary_domain": "Marie Curie", - - - - - - - "primary_cta_label": "Grace Hopper", - - - - - - - "primary_cta_url": "Ada Lovelace", - - - - - - - "contact_email": "Ada Lovelace", - - - - - - - "contact_phone": "Grace Hopper", - - - - - - - "location": "Marie Curie", - - - - - - - "accent_color_hex": "Grace Hopper", - - - - - - - "seo_title": "Grace Hopper", - - - - - - - "seo_description": "Alan Turing", - - - - - - - // type code here for "images" field - - - - - - - // type code here for "images" field - - - - }, - - { - - - - - "site_name": "Ada Lovelace", - - - - - - - "tagline": "Marie Curie", - - - - - - - "primary_domain": "Marie Curie", - - - - - - - "primary_cta_label": "Marie Curie", - - - - - - - "primary_cta_url": "Marie Curie", - - - - - - - "contact_email": "Ada Lovelace", - - - - - - - "contact_phone": "Ada Lovelace", - - - - - - - "location": "Marie Curie", - - - - - - - "accent_color_hex": "Grace Hopper", - - - - - - - "seo_title": "Ada Lovelace", - - - - - - - "seo_description": "Alan Turing", - - - - - - - // type code here for "images" field - - - - - - - // type code here for "images" field - - - - }, - -]; - - - -const PagesData = [ - - { - - - - - "title": "Ada Lovelace", - - - - - - - "slug": "Marie Curie", - - - - - - - "status": "draft", - - - - - - - "sort_order": 7, - - - - - - - "meta_title": "Grace Hopper", - - - - - - - "meta_description": "Grace Hopper", - - - - - - - "show_in_header_nav": false, - - - - - - - "show_in_footer_nav": true, - - - - - - - // type code here for "relation_one" field - - - - }, - - { - - - - - "title": "Grace Hopper", - - - - - - - "slug": "Ada Lovelace", - - - - - - - "status": "draft", - - - - - - - "sort_order": 3, - - - - - - - "meta_title": "Ada Lovelace", - - - - - - - "meta_description": "Alan Turing", - - - - - - - "show_in_header_nav": false, - - - - - - - "show_in_footer_nav": false, - - - - - - - // type code here for "relation_one" field - - - - }, - - { - - - - - "title": "Marie Curie", - - - - - - - "slug": "Alan Turing", - - - - - - - "status": "published", - - - - - - - "sort_order": 6, - - - - - - - "meta_title": "Alan Turing", - - - - - - - "meta_description": "Ada Lovelace", - - - - - - - "show_in_header_nav": true, - - - - - - - "show_in_footer_nav": true, - - - - - - - // type code here for "relation_one" field - - - - }, - - { - - - - - "title": "Marie Curie", - - - - - - - "slug": "Ada Lovelace", - - - - - - - "status": "published", - - - - - - - "sort_order": 4, - - - - - - - "meta_title": "Grace Hopper", - - - - - - - "meta_description": "Grace Hopper", - - - - - - - "show_in_header_nav": true, - - - - - - - "show_in_footer_nav": true, - - - - - - - // type code here for "relation_one" field - - - - }, - -]; - - - -const PageSectionsData = [ - - { - - - - - // type code here for "relation_one" field - - - - - - - "section_type": "portfolio", - - - - - - - "section_label": "Alan Turing", - - - - - - - "headline": "Grace Hopper", - - - - - - - "subheadline": "Alan Turing", - - - - - - - "body": "Grace Hopper", - - - - - - - // type code here for "images" field - - - - - - - "primary_button_label": "Marie Curie", - - - - - - - "primary_button_url": "Grace Hopper", - - - - - - - "secondary_button_label": "Grace Hopper", - - - - - - - "secondary_button_url": "Ada Lovelace", - - - - - - - "sort_order": 7, - - - - - - - "is_visible": false, - - - - }, - - { - - - - - // type code here for "relation_one" field - - - - - - - "section_type": "portfolio", - - - - - - - "section_label": "Marie Curie", - - - - - - - "headline": "Grace Hopper", - - - - - - - "subheadline": "Ada Lovelace", - - - - - - - "body": "Ada Lovelace", - - - - - - - // type code here for "images" field - - - - - - - "primary_button_label": "Alan Turing", - - - - - - - "primary_button_url": "Alan Turing", - - - - - - - "secondary_button_label": "Grace Hopper", - - - - - - - "secondary_button_url": "Marie Curie", - - - - - - - "sort_order": 6, - - - - - - - "is_visible": false, - - - - }, - - { - - - - - // type code here for "relation_one" field - - - - - - - "section_type": "services", - - - - - - - "section_label": "Alan Turing", - - - - - - - "headline": "Marie Curie", - - - - - - - "subheadline": "Grace Hopper", - - - - - - - "body": "Ada Lovelace", - - - - - - - // type code here for "images" field - - - - - - - "primary_button_label": "Alan Turing", - - - - - - - "primary_button_url": "Grace Hopper", - - - - - - - "secondary_button_label": "Ada Lovelace", - - - - - - - "secondary_button_url": "Marie Curie", - - - - - - - "sort_order": 4, - - - - - - - "is_visible": true, - - - - }, - - { - - - - - // type code here for "relation_one" field - - - - - - - "section_type": "why_choose_me", - - - - - - - "section_label": "Grace Hopper", - - - - - - - "headline": "Alan Turing", - - - - - - - "subheadline": "Alan Turing", - - - - - - - "body": "Ada Lovelace", - - - - - - - // type code here for "images" field - - - - - - - "primary_button_label": "Marie Curie", - - - - - - - "primary_button_url": "Grace Hopper", - - - - - - - "secondary_button_label": "Marie Curie", - - - - - - - "secondary_button_url": "Ada Lovelace", - - - - - - - "sort_order": 8, - - - - - - - "is_visible": true, - - - - }, - -]; - - - -const ServicesData = [ - - { - - - - - "name": "Grace Hopper", - - - - - - - "short_description": "Ada Lovelace", - - - - - - - "details": "Grace Hopper", - - - - - - - "category": "technical_documentation", - - - - - - - "sort_order": 3, - - - - - - - "is_featured": true, - - - - - - - "is_active": false, - - - - - - - "cta_label": "Alan Turing", - - - - - - - "cta_url": "Marie Curie", - - - - - - - "icon_name": "Ada Lovelace", - - - - }, - - { - - - - - "name": "Grace Hopper", - - - - - - - "short_description": "Grace Hopper", - - - - - - - "details": "Ada Lovelace", - - - - - - - "category": "guides", - - - - - - - "sort_order": 4, - - - - - - - "is_featured": true, - - - - - - - "is_active": false, - - - - - - - "cta_label": "Alan Turing", - - - - - - - "cta_url": "Ada Lovelace", - - - - - - - "icon_name": "Ada Lovelace", - - - - }, - - { - - - - - "name": "Marie Curie", - - - - - - - "short_description": "Marie Curie", - - - - - - - "details": "Alan Turing", - - - - - - - "category": "technical_documentation", - - - - - - - "sort_order": 7, - - - - - - - "is_featured": false, - - - - - - - "is_active": true, - - - - - - - "cta_label": "Alan Turing", - - - - - - - "cta_url": "Grace Hopper", - - - - - - - "icon_name": "Grace Hopper", - - - - }, - - { - - - - - "name": "Grace Hopper", - - - - - - - "short_description": "Ada Lovelace", - - - - - - - "details": "Grace Hopper", - - - - - - - "category": "technical_documentation", - - - - - - - "sort_order": 5, - - - - - - - "is_featured": false, - - - - - - - "is_active": false, - - - - - - - "cta_label": "Grace Hopper", - - - - - - - "cta_url": "Marie Curie", - - - - - - - "icon_name": "Ada Lovelace", - - - - }, - -]; - - - -const PortfolioItemsData = [ - - { - - - - - "title": "Alan Turing", - - - - - - - "work_type": "guide", - - - - - - - "client_name": "Alan Turing", - - - - - - - "summary": "Marie Curie", - - - - - - - "case_study": "Marie Curie", - - - - - - - // type code here for "images" field - - - - - - - // type code here for "files" field - - - - - - - "external_url": "Grace Hopper", - - - - - - - "tech_stack": "Marie Curie", - - - - - - - "published_on": new Date(Date.now()), - - - - - - - "is_featured": true, - - - - - - - "is_public": true, - - - - }, - - { - - - - - "title": "Marie Curie", - - - - - - - "work_type": "documentation", - - - - - - - "client_name": "Grace Hopper", - - - - - - - "summary": "Ada Lovelace", - - - - - - - "case_study": "Grace Hopper", - - - - - - - // type code here for "images" field - - - - - - - // type code here for "files" field - - - - - - - "external_url": "Marie Curie", - - - - - - - "tech_stack": "Marie Curie", - - - - - - - "published_on": new Date(Date.now()), - - - - - - - "is_featured": true, - - - - - - - "is_public": false, - - - - }, - - { - - - - - "title": "Grace Hopper", - - - - - - - "work_type": "review", - - - - - - - "client_name": "Ada Lovelace", - - - - - - - "summary": "Ada Lovelace", - - - - - - - "case_study": "Alan Turing", - - - - - - - // type code here for "images" field - - - - - - - // type code here for "files" field - - - - - - - "external_url": "Ada Lovelace", - - - - - - - "tech_stack": "Grace Hopper", - - - - - - - "published_on": new Date(Date.now()), - - - - - - - "is_featured": true, - - - - - - - "is_public": false, - - - - }, - - { - - - - - "title": "Grace Hopper", - - - - - - - "work_type": "documentation", - - - - - - - "client_name": "Alan Turing", - - - - - - - "summary": "Grace Hopper", - - - - - - - "case_study": "Alan Turing", - - - - - - - // type code here for "images" field - - - - - - - // type code here for "files" field - - - - - - - "external_url": "Marie Curie", - - - - - - - "tech_stack": "Marie Curie", - - - - - - - "published_on": new Date(Date.now()), - - - - - - - "is_featured": true, - - - - - - - "is_public": true, - - - - }, - -]; - - - -const TestimonialsData = [ - - { - - - - - "client_name": "Ada Lovelace", - - - - - - - "client_title": "Ada Lovelace", - - - - - - - "company_name": "Grace Hopper", - - - - - - - "quote": "Marie Curie", - - - - - - - "rating": 7, - - - - - - - // type code here for "images" field - - - - - - - "source": "Alan Turing", - - - - - - - "source_url": "Marie Curie", - - - - - - - "testimonial_date": new Date(Date.now()), - - - - - - - "is_featured": true, - - - - - - - "is_public": false, - - - - }, - - { - - - - - "client_name": "Grace Hopper", - - - - - - - "client_title": "Marie Curie", - - - - - - - "company_name": "Marie Curie", - - - - - - - "quote": "Ada Lovelace", - - - - - - - "rating": 6, - - - - - - - // type code here for "images" field - - - - - - - "source": "Marie Curie", - - - - - - - "source_url": "Grace Hopper", - - - - - - - "testimonial_date": new Date(Date.now()), - - - - - - - "is_featured": true, - - - - - - - "is_public": false, - - - - }, - - { - - - - - "client_name": "Ada Lovelace", - - - - - - - "client_title": "Ada Lovelace", - - - - - - - "company_name": "Marie Curie", - - - - - - - "quote": "Marie Curie", - - - - - - - "rating": 4, - - - - - - - // type code here for "images" field - - - - - - - "source": "Grace Hopper", - - - - - - - "source_url": "Grace Hopper", - - - - - - - "testimonial_date": new Date(Date.now()), - - - - - - - "is_featured": true, - - - - - - - "is_public": true, - - - - }, - - { - - - - - "client_name": "Ada Lovelace", - - - - - - - "client_title": "Marie Curie", - - - - - - - "company_name": "Grace Hopper", - - - - - - - "quote": "Ada Lovelace", - - - - - - - "rating": 8, - - - - - - - // type code here for "images" field - - - - - - - "source": "Grace Hopper", - - - - - - - "source_url": "Ada Lovelace", - - - - - - - "testimonial_date": new Date(Date.now()), - - - - - - - "is_featured": false, - - - - - - - "is_public": true, - - - - }, - -]; - - - -const SkillsData = [ - - { - - - - - "name": "Grace Hopper", - - - - - - - "category": "tools", - - - - - - - "proficiency_level": 9, - - - - - - - "sort_order": 6, - - - - - - - "is_featured": true, - - - - }, - - { - - - - - "name": "Grace Hopper", - - - - - - - "category": "domain", - - - - - - - "proficiency_level": 8, - - - - - - - "sort_order": 4, - - - - - - - "is_featured": false, - - - - }, - - { - - - - - "name": "Ada Lovelace", - - - - - - - "category": "domain", - - - - - - - "proficiency_level": 2, - - - - - - - "sort_order": 2, - - - - - - - "is_featured": false, - - - - }, - - { - - - - - "name": "Ada Lovelace", - - - - - - - "category": "tools", - - - - - - - "proficiency_level": 2, - - - - - - - "sort_order": 8, - - - - - - - "is_featured": true, - - - - }, - -]; - - - -const BenefitsData = [ - - { - - - - - "title": "Alan Turing", - - - - - - - "description": "Grace Hopper", - - - - - - - "icon_name": "Grace Hopper", - - - - - - - "sort_order": 6, - - - - - - - "is_active": true, - - - - }, - - { - - - - - "title": "Marie Curie", - - - - - - - "description": "Ada Lovelace", - - - - - - - "icon_name": "Alan Turing", - - - - - - - "sort_order": 2, - - - - - - - "is_active": true, - - - - }, - - { - - - - - "title": "Ada Lovelace", - - - - - - - "description": "Alan Turing", - - - - - - - "icon_name": "Ada Lovelace", - - - - - - - "sort_order": 5, - - - - - - - "is_active": true, - - - - }, - - { - - - - - "title": "Grace Hopper", - - - - - - - "description": "Marie Curie", - - - - - - - "icon_name": "Alan Turing", - - - - - - - "sort_order": 1, - - - - - - - "is_active": true, - - - - }, - -]; - - - -const SocialLinksData = [ - - { - - - - - "platform": "linkedin", - - - - - - - "label": "Ada Lovelace", - - - - - - - "url": "Grace Hopper", - - - - - - - "sort_order": 7, - - - - - - - "is_active": false, - - - - }, - - { - - - - - "platform": "x", - - - - - - - "label": "Alan Turing", - - - - - - - "url": "Ada Lovelace", - - - - - - - "sort_order": 2, - - - - - - - "is_active": false, - - - - }, - - { - - - - - "platform": "github", - - - - - - - "label": "Marie Curie", - - - - - - - "url": "Grace Hopper", - - - - - - - "sort_order": 2, - - - - - - - "is_active": false, - - - - }, - - { - - - - - "platform": "linkedin", - - - - - - - "label": "Ada Lovelace", - - - - - - - "url": "Ada Lovelace", - - - - - - - "sort_order": 5, - - - - - - - "is_active": true, - - - - }, - -]; - - - -const InquiriesData = [ - - { - - - - - "full_name": "Alan Turing", - - - - - - - "email": "Grace Hopper", - - - - - - - "company_name": "Ada Lovelace", - - - - - - - "subject": "Ada Lovelace", - - - - - - - "message": "Alan Turing", - - - - - - - "source_page": "Grace Hopper", - - - - - - - "status": "replied", - - - - - - - "received_at": new Date(Date.now()), - - - - - - - "replied_at": new Date(Date.now()), - - - - - - - "fiverr_url": "Marie Curie", - - - - - - - // type code here for "relation_one" field - - - - }, - - { - - - - - "full_name": "Marie Curie", - - - - - - - "email": "Grace Hopper", - - - - - - - "company_name": "Ada Lovelace", - - - - - - - "subject": "Grace Hopper", - - - - - - - "message": "Ada Lovelace", - - - - - - - "source_page": "Alan Turing", - - - - - - - "status": "replied", - - - - - - - "received_at": new Date(Date.now()), - - - - - - - "replied_at": new Date(Date.now()), - - - - - - - "fiverr_url": "Alan Turing", - - - - - - - // type code here for "relation_one" field - - - - }, - - { - - - - - "full_name": "Marie Curie", - - - - - - - "email": "Grace Hopper", - - - - - - - "company_name": "Ada Lovelace", - - - - - - - "subject": "Grace Hopper", - - - - - - - "message": "Marie Curie", - - - - - - - "source_page": "Alan Turing", - - - - - - - "status": "archived", - - - - - - - "received_at": new Date(Date.now()), - - - - - - - "replied_at": new Date(Date.now()), - - - - - - - "fiverr_url": "Alan Turing", - - - - - - - // type code here for "relation_one" field - - - - }, - - { - - - - - "full_name": "Marie Curie", - - - - - - - "email": "Grace Hopper", - - - - - - - "company_name": "Grace Hopper", - - - - - - - "subject": "Alan Turing", - - - - - - - "message": "Alan Turing", - - - - - - - "source_page": "Ada Lovelace", - - - - - - - "status": "new", - - - - - - - "received_at": new Date(Date.now()), - - - - - - - "replied_at": new Date(Date.now()), - - - - - - - "fiverr_url": "Alan Turing", - - - - - - - // type code here for "relation_one" field - - - - }, - -]; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Similar logic for "relation_many" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - async function associatePageWithAuthor() { - - const relatedAuthor0 = await Users.findOne({ - offset: Math.floor(Math.random() * (await Users.count())), - }); - const Page0 = await Pages.findOne({ - order: [['id', 'ASC']], - offset: 0 - }); - if (Page0?.setAuthor) - { - await - Page0. - setAuthor(relatedAuthor0); - } - - const relatedAuthor1 = await Users.findOne({ - offset: Math.floor(Math.random() * (await Users.count())), - }); - const Page1 = await Pages.findOne({ - order: [['id', 'ASC']], - offset: 1 - }); - if (Page1?.setAuthor) - { - await - Page1. - setAuthor(relatedAuthor1); - } - - const relatedAuthor2 = await Users.findOne({ - offset: Math.floor(Math.random() * (await Users.count())), - }); - const Page2 = await Pages.findOne({ - order: [['id', 'ASC']], - offset: 2 - }); - if (Page2?.setAuthor) - { - await - Page2. - setAuthor(relatedAuthor2); - } - - const relatedAuthor3 = await Users.findOne({ - offset: Math.floor(Math.random() * (await Users.count())), - }); - const Page3 = await Pages.findOne({ - order: [['id', 'ASC']], - offset: 3 - }); - if (Page3?.setAuthor) - { - await - Page3. - setAuthor(relatedAuthor3); - } - - } - - - - - - - - - async function associatePageSectionWithPage() { - - const relatedPage0 = await Pages.findOne({ - offset: Math.floor(Math.random() * (await Pages.count())), - }); - const PageSection0 = await PageSections.findOne({ - order: [['id', 'ASC']], - offset: 0 - }); - if (PageSection0?.setPage) - { - await - PageSection0. - setPage(relatedPage0); - } - - const relatedPage1 = await Pages.findOne({ - offset: Math.floor(Math.random() * (await Pages.count())), - }); - const PageSection1 = await PageSections.findOne({ - order: [['id', 'ASC']], - offset: 1 - }); - if (PageSection1?.setPage) - { - await - PageSection1. - setPage(relatedPage1); - } - - const relatedPage2 = await Pages.findOne({ - offset: Math.floor(Math.random() * (await Pages.count())), - }); - const PageSection2 = await PageSections.findOne({ - order: [['id', 'ASC']], - offset: 2 - }); - if (PageSection2?.setPage) - { - await - PageSection2. - setPage(relatedPage2); - } - - const relatedPage3 = await Pages.findOne({ - offset: Math.floor(Math.random() * (await Pages.count())), - }); - const PageSection3 = await PageSections.findOne({ - order: [['id', 'ASC']], - offset: 3 - }); - if (PageSection3?.setPage) - { - await - PageSection3. - setPage(relatedPage3); - } - - } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - async function associateInquiryWithAssigned_to() { - - const relatedAssigned_to0 = await Users.findOne({ - offset: Math.floor(Math.random() * (await Users.count())), - }); - const Inquiry0 = await Inquiries.findOne({ - order: [['id', 'ASC']], - offset: 0 - }); - if (Inquiry0?.setAssigned_to) - { - await - Inquiry0. - setAssigned_to(relatedAssigned_to0); - } - - const relatedAssigned_to1 = await Users.findOne({ - offset: Math.floor(Math.random() * (await Users.count())), - }); - const Inquiry1 = await Inquiries.findOne({ - order: [['id', 'ASC']], - offset: 1 - }); - if (Inquiry1?.setAssigned_to) - { - await - Inquiry1. - setAssigned_to(relatedAssigned_to1); - } - - const relatedAssigned_to2 = await Users.findOne({ - offset: Math.floor(Math.random() * (await Users.count())), - }); - const Inquiry2 = await Inquiries.findOne({ - order: [['id', 'ASC']], - offset: 2 - }); - if (Inquiry2?.setAssigned_to) - { - await - Inquiry2. - setAssigned_to(relatedAssigned_to2); - } - - const relatedAssigned_to3 = await Users.findOne({ - offset: Math.floor(Math.random() * (await Users.count())), - }); - const Inquiry3 = await Inquiries.findOne({ - order: [['id', 'ASC']], - offset: 3 - }); - if (Inquiry3?.setAssigned_to) - { - await - Inquiry3. - setAssigned_to(relatedAssigned_to3); - } - - } - - - - -module.exports = { - up: async (queryInterface, Sequelize) => { - - - - - - - - await SiteSettings.bulkCreate(SiteSettingsData); - - - - - await Pages.bulkCreate(PagesData); - - - - - await PageSections.bulkCreate(PageSectionsData); - - - - - await Services.bulkCreate(ServicesData); - - - - - await PortfolioItems.bulkCreate(PortfolioItemsData); - - - - - await Testimonials.bulkCreate(TestimonialsData); - - - - - await Skills.bulkCreate(SkillsData); - - - - - await Benefits.bulkCreate(BenefitsData); - - - - - await SocialLinks.bulkCreate(SocialLinksData); - - - - - await Inquiries.bulkCreate(InquiriesData); - - - await Promise.all([ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Similar logic for "relation_many" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - await associatePageWithAuthor(), - - - - - - - - await associatePageSectionWithPage(), - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - await associateInquiryWithAssigned_to(), - - - - ]); - - }, - - down: async (queryInterface, Sequelize) => { - - - - - - - await queryInterface.bulkDelete('site_settings', null, {}); - - - await queryInterface.bulkDelete('pages', null, {}); - - - await queryInterface.bulkDelete('page_sections', null, {}); - - - await queryInterface.bulkDelete('services', null, {}); - - - await queryInterface.bulkDelete('portfolio_items', null, {}); - - - await queryInterface.bulkDelete('testimonials', null, {}); - - - await queryInterface.bulkDelete('skills', null, {}); - - - await queryInterface.bulkDelete('benefits', null, {}); - - - await queryInterface.bulkDelete('social_links', null, {}); - - - await queryInterface.bulkDelete('inquiries', 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 ca16c77..0000000 --- a/backend/src/index.js +++ /dev/null @@ -1,178 +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 site_settingsRoutes = require('./routes/site_settings'); - -const pagesRoutes = require('./routes/pages'); - -const page_sectionsRoutes = require('./routes/page_sections'); - -const servicesRoutes = require('./routes/services'); - -const portfolio_itemsRoutes = require('./routes/portfolio_items'); - -const testimonialsRoutes = require('./routes/testimonials'); - -const skillsRoutes = require('./routes/skills'); - -const benefitsRoutes = require('./routes/benefits'); - -const social_linksRoutes = require('./routes/social_links'); - -const inquiriesRoutes = require('./routes/inquiries'); - - -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: "Blackness Studio Website", - description: "Blackness Studio Website 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/site_settings', passport.authenticate('jwt', {session: false}), site_settingsRoutes); - -app.use('/api/pages', passport.authenticate('jwt', {session: false}), pagesRoutes); - -app.use('/api/page_sections', passport.authenticate('jwt', {session: false}), page_sectionsRoutes); - -app.use('/api/services', passport.authenticate('jwt', {session: false}), servicesRoutes); - -app.use('/api/portfolio_items', passport.authenticate('jwt', {session: false}), portfolio_itemsRoutes); - -app.use('/api/testimonials', passport.authenticate('jwt', {session: false}), testimonialsRoutes); - -app.use('/api/skills', passport.authenticate('jwt', {session: false}), skillsRoutes); - -app.use('/api/benefits', passport.authenticate('jwt', {session: false}), benefitsRoutes); - -app.use('/api/social_links', passport.authenticate('jwt', {session: false}), social_linksRoutes); - -app.use('/api/inquiries', passport.authenticate('jwt', {session: false}), inquiriesRoutes); - -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; - -db.sequelize.sync().then(function () { - 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/benefits.js b/backend/src/routes/benefits.js deleted file mode 100644 index c44fcff..0000000 --- a/backend/src/routes/benefits.js +++ /dev/null @@ -1,438 +0,0 @@ - -const express = require('express'); - -const BenefitsService = require('../services/benefits'); -const BenefitsDBApi = require('../db/api/benefits'); -const wrapAsync = require('../helpers').wrapAsync; - - -const router = express.Router(); - -const { parse } = require('json2csv'); - - -const { - checkCrudPermissions, -} = require('../middlewares/check-permissions'); - -router.use(checkCrudPermissions('benefits')); - - -/** - * @swagger - * components: - * schemas: - * Benefits: - * type: object - * properties: - - * title: - * type: string - * default: title - * description: - * type: string - * default: description - * icon_name: - * type: string - * default: icon_name - - * sort_order: - * type: integer - * format: int64 - - - */ - -/** - * @swagger - * tags: - * name: Benefits - * description: The Benefits managing API - */ - -/** -* @swagger -* /api/benefits: -* post: -* security: -* - bearerAuth: [] -* tags: [Benefits] -* 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/Benefits" -* responses: -* 200: -* description: The item was successfully added -* content: -* application/json: -* schema: -* $ref: "#/components/schemas/Benefits" -* 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 BenefitsService.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: [Benefits] - * 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/Benefits" - * responses: - * 200: - * description: The items were successfully imported - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Benefits" - * 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 BenefitsService.bulkImport(req, res, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/benefits/{id}: - * put: - * security: - * - bearerAuth: [] - * tags: [Benefits] - * 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/Benefits" - * required: - * - id - * responses: - * 200: - * description: The item data was successfully updated - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Benefits" - * 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 BenefitsService.update(req.body.data, req.body.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/benefits/{id}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Benefits] - * 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/Benefits" - * 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 BenefitsService.remove(req.params.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/benefits/deleteByIds: - * post: - * security: - * - bearerAuth: [] - * tags: [Benefits] - * 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/Benefits" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Items not found - * 500: - * description: Some server error - */ -router.post('/deleteByIds', wrapAsync(async (req, res) => { - await BenefitsService.deleteByIds(req.body.data, req.currentUser); - const payload = true; - res.status(200).send(payload); - })); - -/** - * @swagger - * /api/benefits: - * get: - * security: - * - bearerAuth: [] - * tags: [Benefits] - * summary: Get all benefits - * description: Get all benefits - * responses: - * 200: - * description: Benefits list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Benefits" - * 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 BenefitsDBApi.findAll( - req.query, { currentUser } - ); - if (filetype && filetype === 'csv') { - const fields = ['id','title','description','icon_name', - 'sort_order', - - - ]; - 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/benefits/count: - * get: - * security: - * - bearerAuth: [] - * tags: [Benefits] - * summary: Count all benefits - * description: Count all benefits - * responses: - * 200: - * description: Benefits count successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Benefits" - * 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 BenefitsDBApi.findAll( - req.query, - null, - { countOnly: true, currentUser } - ); - - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/benefits/autocomplete: - * get: - * security: - * - bearerAuth: [] - * tags: [Benefits] - * summary: Find all benefits that match search criteria - * description: Find all benefits that match search criteria - * responses: - * 200: - * description: Benefits list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Benefits" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/autocomplete', async (req, res) => { - - const payload = await BenefitsDBApi.findAllAutocomplete( - req.query.query, - req.query.limit, - req.query.offset, - - ); - - res.status(200).send(payload); -}); - -/** - * @swagger - * /api/benefits/{id}: - * get: - * security: - * - bearerAuth: [] - * tags: [Benefits] - * 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/Benefits" - * 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 BenefitsDBApi.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/inquiries.js b/backend/src/routes/inquiries.js deleted file mode 100644 index ab39168..0000000 --- a/backend/src/routes/inquiries.js +++ /dev/null @@ -1,448 +0,0 @@ - -const express = require('express'); - -const InquiriesService = require('../services/inquiries'); -const InquiriesDBApi = require('../db/api/inquiries'); -const wrapAsync = require('../helpers').wrapAsync; - - -const router = express.Router(); - -const { parse } = require('json2csv'); - - -const { - checkCrudPermissions, -} = require('../middlewares/check-permissions'); - -router.use(checkCrudPermissions('inquiries')); - - -/** - * @swagger - * components: - * schemas: - * Inquiries: - * type: object - * properties: - - * full_name: - * type: string - * default: full_name - * email: - * type: string - * default: email - * company_name: - * type: string - * default: company_name - * subject: - * type: string - * default: subject - * message: - * type: string - * default: message - * source_page: - * type: string - * default: source_page - * fiverr_url: - * type: string - * default: fiverr_url - - - - * - */ - -/** - * @swagger - * tags: - * name: Inquiries - * description: The Inquiries managing API - */ - -/** -* @swagger -* /api/inquiries: -* post: -* security: -* - bearerAuth: [] -* tags: [Inquiries] -* 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/Inquiries" -* responses: -* 200: -* description: The item was successfully added -* content: -* application/json: -* schema: -* $ref: "#/components/schemas/Inquiries" -* 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 InquiriesService.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: [Inquiries] - * 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/Inquiries" - * responses: - * 200: - * description: The items were successfully imported - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Inquiries" - * 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 InquiriesService.bulkImport(req, res, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/inquiries/{id}: - * put: - * security: - * - bearerAuth: [] - * tags: [Inquiries] - * 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/Inquiries" - * required: - * - id - * responses: - * 200: - * description: The item data was successfully updated - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Inquiries" - * 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 InquiriesService.update(req.body.data, req.body.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/inquiries/{id}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Inquiries] - * 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/Inquiries" - * 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 InquiriesService.remove(req.params.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/inquiries/deleteByIds: - * post: - * security: - * - bearerAuth: [] - * tags: [Inquiries] - * 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/Inquiries" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Items not found - * 500: - * description: Some server error - */ -router.post('/deleteByIds', wrapAsync(async (req, res) => { - await InquiriesService.deleteByIds(req.body.data, req.currentUser); - const payload = true; - res.status(200).send(payload); - })); - -/** - * @swagger - * /api/inquiries: - * get: - * security: - * - bearerAuth: [] - * tags: [Inquiries] - * summary: Get all inquiries - * description: Get all inquiries - * responses: - * 200: - * description: Inquiries list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Inquiries" - * 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 InquiriesDBApi.findAll( - req.query, { currentUser } - ); - if (filetype && filetype === 'csv') { - const fields = ['id','full_name','email','company_name','subject','message','source_page','fiverr_url', - - - 'received_at','replied_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/inquiries/count: - * get: - * security: - * - bearerAuth: [] - * tags: [Inquiries] - * summary: Count all inquiries - * description: Count all inquiries - * responses: - * 200: - * description: Inquiries count successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Inquiries" - * 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 InquiriesDBApi.findAll( - req.query, - null, - { countOnly: true, currentUser } - ); - - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/inquiries/autocomplete: - * get: - * security: - * - bearerAuth: [] - * tags: [Inquiries] - * summary: Find all inquiries that match search criteria - * description: Find all inquiries that match search criteria - * responses: - * 200: - * description: Inquiries list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Inquiries" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/autocomplete', async (req, res) => { - - const payload = await InquiriesDBApi.findAllAutocomplete( - req.query.query, - req.query.limit, - req.query.offset, - - ); - - res.status(200).send(payload); -}); - -/** - * @swagger - * /api/inquiries/{id}: - * get: - * security: - * - bearerAuth: [] - * tags: [Inquiries] - * 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/Inquiries" - * 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 InquiriesDBApi.findBy( - { id: req.params.id }, - ); - - - - res.status(200).send(payload); -})); - -router.use('/', require('../helpers').commonErrorHandler); - -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/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/page_sections.js b/backend/src/routes/page_sections.js deleted file mode 100644 index b7dd6b7..0000000 --- a/backend/src/routes/page_sections.js +++ /dev/null @@ -1,454 +0,0 @@ - -const express = require('express'); - -const Page_sectionsService = require('../services/page_sections'); -const Page_sectionsDBApi = require('../db/api/page_sections'); -const wrapAsync = require('../helpers').wrapAsync; - - -const router = express.Router(); - -const { parse } = require('json2csv'); - - -const { - checkCrudPermissions, -} = require('../middlewares/check-permissions'); - -router.use(checkCrudPermissions('page_sections')); - - -/** - * @swagger - * components: - * schemas: - * Page_sections: - * type: object - * properties: - - * section_label: - * type: string - * default: section_label - * headline: - * type: string - * default: headline - * subheadline: - * type: string - * default: subheadline - * body: - * type: string - * default: body - * primary_button_label: - * type: string - * default: primary_button_label - * primary_button_url: - * type: string - * default: primary_button_url - * secondary_button_label: - * type: string - * default: secondary_button_label - * secondary_button_url: - * type: string - * default: secondary_button_url - - * sort_order: - * type: integer - * format: int64 - - - * - */ - -/** - * @swagger - * tags: - * name: Page_sections - * description: The Page_sections managing API - */ - -/** -* @swagger -* /api/page_sections: -* post: -* security: -* - bearerAuth: [] -* tags: [Page_sections] -* 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/Page_sections" -* responses: -* 200: -* description: The item was successfully added -* content: -* application/json: -* schema: -* $ref: "#/components/schemas/Page_sections" -* 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 Page_sectionsService.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: [Page_sections] - * 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/Page_sections" - * responses: - * 200: - * description: The items were successfully imported - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Page_sections" - * 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 Page_sectionsService.bulkImport(req, res, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/page_sections/{id}: - * put: - * security: - * - bearerAuth: [] - * tags: [Page_sections] - * 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/Page_sections" - * required: - * - id - * responses: - * 200: - * description: The item data was successfully updated - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Page_sections" - * 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 Page_sectionsService.update(req.body.data, req.body.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/page_sections/{id}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Page_sections] - * 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/Page_sections" - * 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 Page_sectionsService.remove(req.params.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/page_sections/deleteByIds: - * post: - * security: - * - bearerAuth: [] - * tags: [Page_sections] - * 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/Page_sections" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Items not found - * 500: - * description: Some server error - */ -router.post('/deleteByIds', wrapAsync(async (req, res) => { - await Page_sectionsService.deleteByIds(req.body.data, req.currentUser); - const payload = true; - res.status(200).send(payload); - })); - -/** - * @swagger - * /api/page_sections: - * get: - * security: - * - bearerAuth: [] - * tags: [Page_sections] - * summary: Get all page_sections - * description: Get all page_sections - * responses: - * 200: - * description: Page_sections list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Page_sections" - * 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 Page_sectionsDBApi.findAll( - req.query, { currentUser } - ); - if (filetype && filetype === 'csv') { - const fields = ['id','section_label','headline','subheadline','body','primary_button_label','primary_button_url','secondary_button_label','secondary_button_url', - 'sort_order', - - - ]; - 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/page_sections/count: - * get: - * security: - * - bearerAuth: [] - * tags: [Page_sections] - * summary: Count all page_sections - * description: Count all page_sections - * responses: - * 200: - * description: Page_sections count successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Page_sections" - * 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 Page_sectionsDBApi.findAll( - req.query, - null, - { countOnly: true, currentUser } - ); - - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/page_sections/autocomplete: - * get: - * security: - * - bearerAuth: [] - * tags: [Page_sections] - * summary: Find all page_sections that match search criteria - * description: Find all page_sections that match search criteria - * responses: - * 200: - * description: Page_sections list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Page_sections" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/autocomplete', async (req, res) => { - - const payload = await Page_sectionsDBApi.findAllAutocomplete( - req.query.query, - req.query.limit, - req.query.offset, - - ); - - res.status(200).send(payload); -}); - -/** - * @swagger - * /api/page_sections/{id}: - * get: - * security: - * - bearerAuth: [] - * tags: [Page_sections] - * 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/Page_sections" - * 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 Page_sectionsDBApi.findBy( - { id: req.params.id }, - ); - - - - res.status(200).send(payload); -})); - -router.use('/', require('../helpers').commonErrorHandler); - -module.exports = router; diff --git a/backend/src/routes/pages.js b/backend/src/routes/pages.js deleted file mode 100644 index 72fa425..0000000 --- a/backend/src/routes/pages.js +++ /dev/null @@ -1,442 +0,0 @@ - -const express = require('express'); - -const PagesService = require('../services/pages'); -const PagesDBApi = require('../db/api/pages'); -const wrapAsync = require('../helpers').wrapAsync; - - -const router = express.Router(); - -const { parse } = require('json2csv'); - - -const { - checkCrudPermissions, -} = require('../middlewares/check-permissions'); - -router.use(checkCrudPermissions('pages')); - - -/** - * @swagger - * components: - * schemas: - * Pages: - * type: object - * properties: - - * title: - * type: string - * default: title - * slug: - * type: string - * default: slug - * meta_title: - * type: string - * default: meta_title - * meta_description: - * type: string - * default: meta_description - - * sort_order: - * type: integer - * format: int64 - - - * - */ - -/** - * @swagger - * tags: - * name: Pages - * description: The Pages managing API - */ - -/** -* @swagger -* /api/pages: -* post: -* security: -* - bearerAuth: [] -* tags: [Pages] -* 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/Pages" -* responses: -* 200: -* description: The item was successfully added -* content: -* application/json: -* schema: -* $ref: "#/components/schemas/Pages" -* 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 PagesService.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: [Pages] - * 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/Pages" - * responses: - * 200: - * description: The items were successfully imported - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Pages" - * 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 PagesService.bulkImport(req, res, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/pages/{id}: - * put: - * security: - * - bearerAuth: [] - * tags: [Pages] - * 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/Pages" - * required: - * - id - * responses: - * 200: - * description: The item data was successfully updated - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Pages" - * 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 PagesService.update(req.body.data, req.body.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/pages/{id}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Pages] - * 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/Pages" - * 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 PagesService.remove(req.params.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/pages/deleteByIds: - * post: - * security: - * - bearerAuth: [] - * tags: [Pages] - * 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/Pages" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Items not found - * 500: - * description: Some server error - */ -router.post('/deleteByIds', wrapAsync(async (req, res) => { - await PagesService.deleteByIds(req.body.data, req.currentUser); - const payload = true; - res.status(200).send(payload); - })); - -/** - * @swagger - * /api/pages: - * get: - * security: - * - bearerAuth: [] - * tags: [Pages] - * summary: Get all pages - * description: Get all pages - * responses: - * 200: - * description: Pages list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Pages" - * 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 PagesDBApi.findAll( - req.query, { currentUser } - ); - if (filetype && filetype === 'csv') { - const fields = ['id','title','slug','meta_title','meta_description', - 'sort_order', - - - ]; - 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/pages/count: - * get: - * security: - * - bearerAuth: [] - * tags: [Pages] - * summary: Count all pages - * description: Count all pages - * responses: - * 200: - * description: Pages count successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Pages" - * 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 PagesDBApi.findAll( - req.query, - null, - { countOnly: true, currentUser } - ); - - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/pages/autocomplete: - * get: - * security: - * - bearerAuth: [] - * tags: [Pages] - * summary: Find all pages that match search criteria - * description: Find all pages that match search criteria - * responses: - * 200: - * description: Pages list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Pages" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/autocomplete', async (req, res) => { - - const payload = await PagesDBApi.findAllAutocomplete( - req.query.query, - req.query.limit, - req.query.offset, - - ); - - res.status(200).send(payload); -}); - -/** - * @swagger - * /api/pages/{id}: - * get: - * security: - * - bearerAuth: [] - * tags: [Pages] - * 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/Pages" - * 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 PagesDBApi.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/portfolio_items.js b/backend/src/routes/portfolio_items.js deleted file mode 100644 index 06424dc..0000000 --- a/backend/src/routes/portfolio_items.js +++ /dev/null @@ -1,445 +0,0 @@ - -const express = require('express'); - -const Portfolio_itemsService = require('../services/portfolio_items'); -const Portfolio_itemsDBApi = require('../db/api/portfolio_items'); -const wrapAsync = require('../helpers').wrapAsync; - - -const router = express.Router(); - -const { parse } = require('json2csv'); - - -const { - checkCrudPermissions, -} = require('../middlewares/check-permissions'); - -router.use(checkCrudPermissions('portfolio_items')); - - -/** - * @swagger - * components: - * schemas: - * Portfolio_items: - * type: object - * properties: - - * title: - * type: string - * default: title - * client_name: - * type: string - * default: client_name - * summary: - * type: string - * default: summary - * case_study: - * type: string - * default: case_study - * external_url: - * type: string - * default: external_url - * tech_stack: - * type: string - * default: tech_stack - - - - * - */ - -/** - * @swagger - * tags: - * name: Portfolio_items - * description: The Portfolio_items managing API - */ - -/** -* @swagger -* /api/portfolio_items: -* post: -* security: -* - bearerAuth: [] -* tags: [Portfolio_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/Portfolio_items" -* responses: -* 200: -* description: The item was successfully added -* content: -* application/json: -* schema: -* $ref: "#/components/schemas/Portfolio_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 Portfolio_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: [Portfolio_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/Portfolio_items" - * responses: - * 200: - * description: The items were successfully imported - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Portfolio_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 Portfolio_itemsService.bulkImport(req, res, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/portfolio_items/{id}: - * put: - * security: - * - bearerAuth: [] - * tags: [Portfolio_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/Portfolio_items" - * required: - * - id - * responses: - * 200: - * description: The item data was successfully updated - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Portfolio_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 Portfolio_itemsService.update(req.body.data, req.body.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/portfolio_items/{id}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Portfolio_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/Portfolio_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 Portfolio_itemsService.remove(req.params.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/portfolio_items/deleteByIds: - * post: - * security: - * - bearerAuth: [] - * tags: [Portfolio_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/Portfolio_items" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Items not found - * 500: - * description: Some server error - */ -router.post('/deleteByIds', wrapAsync(async (req, res) => { - await Portfolio_itemsService.deleteByIds(req.body.data, req.currentUser); - const payload = true; - res.status(200).send(payload); - })); - -/** - * @swagger - * /api/portfolio_items: - * get: - * security: - * - bearerAuth: [] - * tags: [Portfolio_items] - * summary: Get all portfolio_items - * description: Get all portfolio_items - * responses: - * 200: - * description: Portfolio_items list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Portfolio_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 Portfolio_itemsDBApi.findAll( - req.query, { currentUser } - ); - if (filetype && filetype === 'csv') { - const fields = ['id','title','client_name','summary','case_study','external_url','tech_stack', - - - 'published_on', - ]; - 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/portfolio_items/count: - * get: - * security: - * - bearerAuth: [] - * tags: [Portfolio_items] - * summary: Count all portfolio_items - * description: Count all portfolio_items - * responses: - * 200: - * description: Portfolio_items count successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Portfolio_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 Portfolio_itemsDBApi.findAll( - req.query, - null, - { countOnly: true, currentUser } - ); - - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/portfolio_items/autocomplete: - * get: - * security: - * - bearerAuth: [] - * tags: [Portfolio_items] - * summary: Find all portfolio_items that match search criteria - * description: Find all portfolio_items that match search criteria - * responses: - * 200: - * description: Portfolio_items list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Portfolio_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 Portfolio_itemsDBApi.findAllAutocomplete( - req.query.query, - req.query.limit, - req.query.offset, - - ); - - res.status(200).send(payload); -}); - -/** - * @swagger - * /api/portfolio_items/{id}: - * get: - * security: - * - bearerAuth: [] - * tags: [Portfolio_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/Portfolio_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 Portfolio_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/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/services.js b/backend/src/routes/services.js deleted file mode 100644 index 986b7af..0000000 --- a/backend/src/routes/services.js +++ /dev/null @@ -1,448 +0,0 @@ - -const express = require('express'); - -const ServicesService = require('../services/services'); -const ServicesDBApi = require('../db/api/services'); -const wrapAsync = require('../helpers').wrapAsync; - - -const router = express.Router(); - -const { parse } = require('json2csv'); - - -const { - checkCrudPermissions, -} = require('../middlewares/check-permissions'); - -router.use(checkCrudPermissions('services')); - - -/** - * @swagger - * components: - * schemas: - * Services: - * type: object - * properties: - - * name: - * type: string - * default: name - * short_description: - * type: string - * default: short_description - * details: - * type: string - * default: details - * cta_label: - * type: string - * default: cta_label - * cta_url: - * type: string - * default: cta_url - * icon_name: - * type: string - * default: icon_name - - * sort_order: - * type: integer - * format: int64 - - - * - */ - -/** - * @swagger - * tags: - * name: Services - * description: The Services managing API - */ - -/** -* @swagger -* /api/services: -* post: -* security: -* - bearerAuth: [] -* tags: [Services] -* 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/Services" -* responses: -* 200: -* description: The item was successfully added -* content: -* application/json: -* schema: -* $ref: "#/components/schemas/Services" -* 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 ServicesService.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: [Services] - * 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/Services" - * responses: - * 200: - * description: The items were successfully imported - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Services" - * 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 ServicesService.bulkImport(req, res, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/services/{id}: - * put: - * security: - * - bearerAuth: [] - * tags: [Services] - * 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/Services" - * required: - * - id - * responses: - * 200: - * description: The item data was successfully updated - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Services" - * 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 ServicesService.update(req.body.data, req.body.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/services/{id}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Services] - * 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/Services" - * 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 ServicesService.remove(req.params.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/services/deleteByIds: - * post: - * security: - * - bearerAuth: [] - * tags: [Services] - * 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/Services" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Items not found - * 500: - * description: Some server error - */ -router.post('/deleteByIds', wrapAsync(async (req, res) => { - await ServicesService.deleteByIds(req.body.data, req.currentUser); - const payload = true; - res.status(200).send(payload); - })); - -/** - * @swagger - * /api/services: - * get: - * security: - * - bearerAuth: [] - * tags: [Services] - * summary: Get all services - * description: Get all services - * responses: - * 200: - * description: Services list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Services" - * 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 ServicesDBApi.findAll( - req.query, { currentUser } - ); - if (filetype && filetype === 'csv') { - const fields = ['id','name','short_description','details','cta_label','cta_url','icon_name', - 'sort_order', - - - ]; - 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/services/count: - * get: - * security: - * - bearerAuth: [] - * tags: [Services] - * summary: Count all services - * description: Count all services - * responses: - * 200: - * description: Services count successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Services" - * 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 ServicesDBApi.findAll( - req.query, - null, - { countOnly: true, currentUser } - ); - - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/services/autocomplete: - * get: - * security: - * - bearerAuth: [] - * tags: [Services] - * summary: Find all services that match search criteria - * description: Find all services that match search criteria - * responses: - * 200: - * description: Services list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Services" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/autocomplete', async (req, res) => { - - const payload = await ServicesDBApi.findAllAutocomplete( - req.query.query, - req.query.limit, - req.query.offset, - - ); - - res.status(200).send(payload); -}); - -/** - * @swagger - * /api/services/{id}: - * get: - * security: - * - bearerAuth: [] - * tags: [Services] - * 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/Services" - * 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 ServicesDBApi.findBy( - { id: req.params.id }, - ); - - - - res.status(200).send(payload); -})); - -router.use('/', require('../helpers').commonErrorHandler); - -module.exports = router; diff --git a/backend/src/routes/site_settings.js b/backend/src/routes/site_settings.js deleted file mode 100644 index 5c28f40..0000000 --- a/backend/src/routes/site_settings.js +++ /dev/null @@ -1,459 +0,0 @@ - -const express = require('express'); - -const Site_settingsService = require('../services/site_settings'); -const Site_settingsDBApi = require('../db/api/site_settings'); -const wrapAsync = require('../helpers').wrapAsync; - - -const router = express.Router(); - -const { parse } = require('json2csv'); - - -const { - checkCrudPermissions, -} = require('../middlewares/check-permissions'); - -router.use(checkCrudPermissions('site_settings')); - - -/** - * @swagger - * components: - * schemas: - * Site_settings: - * type: object - * properties: - - * site_name: - * type: string - * default: site_name - * tagline: - * type: string - * default: tagline - * primary_domain: - * type: string - * default: primary_domain - * primary_cta_label: - * type: string - * default: primary_cta_label - * primary_cta_url: - * type: string - * default: primary_cta_url - * contact_email: - * type: string - * default: contact_email - * contact_phone: - * type: string - * default: contact_phone - * location: - * type: string - * default: location - * accent_color_hex: - * type: string - * default: accent_color_hex - * seo_title: - * type: string - * default: seo_title - * seo_description: - * type: string - * default: seo_description - - - - */ - -/** - * @swagger - * tags: - * name: Site_settings - * description: The Site_settings managing API - */ - -/** -* @swagger -* /api/site_settings: -* post: -* security: -* - bearerAuth: [] -* tags: [Site_settings] -* 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/Site_settings" -* responses: -* 200: -* description: The item was successfully added -* content: -* application/json: -* schema: -* $ref: "#/components/schemas/Site_settings" -* 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 Site_settingsService.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: [Site_settings] - * 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/Site_settings" - * responses: - * 200: - * description: The items were successfully imported - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Site_settings" - * 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 Site_settingsService.bulkImport(req, res, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/site_settings/{id}: - * put: - * security: - * - bearerAuth: [] - * tags: [Site_settings] - * 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/Site_settings" - * required: - * - id - * responses: - * 200: - * description: The item data was successfully updated - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Site_settings" - * 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 Site_settingsService.update(req.body.data, req.body.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/site_settings/{id}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Site_settings] - * 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/Site_settings" - * 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 Site_settingsService.remove(req.params.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/site_settings/deleteByIds: - * post: - * security: - * - bearerAuth: [] - * tags: [Site_settings] - * 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/Site_settings" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Items not found - * 500: - * description: Some server error - */ -router.post('/deleteByIds', wrapAsync(async (req, res) => { - await Site_settingsService.deleteByIds(req.body.data, req.currentUser); - const payload = true; - res.status(200).send(payload); - })); - -/** - * @swagger - * /api/site_settings: - * get: - * security: - * - bearerAuth: [] - * tags: [Site_settings] - * summary: Get all site_settings - * description: Get all site_settings - * responses: - * 200: - * description: Site_settings list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Site_settings" - * 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 Site_settingsDBApi.findAll( - req.query, { currentUser } - ); - if (filetype && filetype === 'csv') { - const fields = ['id','site_name','tagline','primary_domain','primary_cta_label','primary_cta_url','contact_email','contact_phone','location','accent_color_hex','seo_title','seo_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/site_settings/count: - * get: - * security: - * - bearerAuth: [] - * tags: [Site_settings] - * summary: Count all site_settings - * description: Count all site_settings - * responses: - * 200: - * description: Site_settings count successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Site_settings" - * 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 Site_settingsDBApi.findAll( - req.query, - null, - { countOnly: true, currentUser } - ); - - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/site_settings/autocomplete: - * get: - * security: - * - bearerAuth: [] - * tags: [Site_settings] - * summary: Find all site_settings that match search criteria - * description: Find all site_settings that match search criteria - * responses: - * 200: - * description: Site_settings list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Site_settings" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/autocomplete', async (req, res) => { - - const payload = await Site_settingsDBApi.findAllAutocomplete( - req.query.query, - req.query.limit, - req.query.offset, - - ); - - res.status(200).send(payload); -}); - -/** - * @swagger - * /api/site_settings/{id}: - * get: - * security: - * - bearerAuth: [] - * tags: [Site_settings] - * 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/Site_settings" - * 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 Site_settingsDBApi.findBy( - { id: req.params.id }, - ); - - - - res.status(200).send(payload); -})); - -router.use('/', require('../helpers').commonErrorHandler); - -module.exports = router; diff --git a/backend/src/routes/skills.js b/backend/src/routes/skills.js deleted file mode 100644 index 17e1d5d..0000000 --- a/backend/src/routes/skills.js +++ /dev/null @@ -1,436 +0,0 @@ - -const express = require('express'); - -const SkillsService = require('../services/skills'); -const SkillsDBApi = require('../db/api/skills'); -const wrapAsync = require('../helpers').wrapAsync; - - -const router = express.Router(); - -const { parse } = require('json2csv'); - - -const { - checkCrudPermissions, -} = require('../middlewares/check-permissions'); - -router.use(checkCrudPermissions('skills')); - - -/** - * @swagger - * components: - * schemas: - * Skills: - * type: object - * properties: - - * name: - * type: string - * default: name - - * proficiency_level: - * type: integer - * format: int64 - * sort_order: - * type: integer - * format: int64 - - - * - */ - -/** - * @swagger - * tags: - * name: Skills - * description: The Skills managing API - */ - -/** -* @swagger -* /api/skills: -* post: -* security: -* - bearerAuth: [] -* tags: [Skills] -* 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/Skills" -* responses: -* 200: -* description: The item was successfully added -* content: -* application/json: -* schema: -* $ref: "#/components/schemas/Skills" -* 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 SkillsService.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: [Skills] - * 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/Skills" - * responses: - * 200: - * description: The items were successfully imported - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Skills" - * 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 SkillsService.bulkImport(req, res, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/skills/{id}: - * put: - * security: - * - bearerAuth: [] - * tags: [Skills] - * 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/Skills" - * required: - * - id - * responses: - * 200: - * description: The item data was successfully updated - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Skills" - * 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 SkillsService.update(req.body.data, req.body.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/skills/{id}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Skills] - * 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/Skills" - * 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 SkillsService.remove(req.params.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/skills/deleteByIds: - * post: - * security: - * - bearerAuth: [] - * tags: [Skills] - * 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/Skills" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Items not found - * 500: - * description: Some server error - */ -router.post('/deleteByIds', wrapAsync(async (req, res) => { - await SkillsService.deleteByIds(req.body.data, req.currentUser); - const payload = true; - res.status(200).send(payload); - })); - -/** - * @swagger - * /api/skills: - * get: - * security: - * - bearerAuth: [] - * tags: [Skills] - * summary: Get all skills - * description: Get all skills - * responses: - * 200: - * description: Skills list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Skills" - * 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 SkillsDBApi.findAll( - req.query, { currentUser } - ); - if (filetype && filetype === 'csv') { - const fields = ['id','name', - 'proficiency_level','sort_order', - - - ]; - 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/skills/count: - * get: - * security: - * - bearerAuth: [] - * tags: [Skills] - * summary: Count all skills - * description: Count all skills - * responses: - * 200: - * description: Skills count successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Skills" - * 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 SkillsDBApi.findAll( - req.query, - null, - { countOnly: true, currentUser } - ); - - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/skills/autocomplete: - * get: - * security: - * - bearerAuth: [] - * tags: [Skills] - * summary: Find all skills that match search criteria - * description: Find all skills that match search criteria - * responses: - * 200: - * description: Skills list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Skills" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/autocomplete', async (req, res) => { - - const payload = await SkillsDBApi.findAllAutocomplete( - req.query.query, - req.query.limit, - req.query.offset, - - ); - - res.status(200).send(payload); -}); - -/** - * @swagger - * /api/skills/{id}: - * get: - * security: - * - bearerAuth: [] - * tags: [Skills] - * 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/Skills" - * 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 SkillsDBApi.findBy( - { id: req.params.id }, - ); - - - - res.status(200).send(payload); -})); - -router.use('/', require('../helpers').commonErrorHandler); - -module.exports = router; diff --git a/backend/src/routes/social_links.js b/backend/src/routes/social_links.js deleted file mode 100644 index 5278d4b..0000000 --- a/backend/src/routes/social_links.js +++ /dev/null @@ -1,436 +0,0 @@ - -const express = require('express'); - -const Social_linksService = require('../services/social_links'); -const Social_linksDBApi = require('../db/api/social_links'); -const wrapAsync = require('../helpers').wrapAsync; - - -const router = express.Router(); - -const { parse } = require('json2csv'); - - -const { - checkCrudPermissions, -} = require('../middlewares/check-permissions'); - -router.use(checkCrudPermissions('social_links')); - - -/** - * @swagger - * components: - * schemas: - * Social_links: - * type: object - * properties: - - * label: - * type: string - * default: label - * url: - * type: string - * default: url - - * sort_order: - * type: integer - * format: int64 - - - * - */ - -/** - * @swagger - * tags: - * name: Social_links - * description: The Social_links managing API - */ - -/** -* @swagger -* /api/social_links: -* post: -* security: -* - bearerAuth: [] -* tags: [Social_links] -* 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/Social_links" -* responses: -* 200: -* description: The item was successfully added -* content: -* application/json: -* schema: -* $ref: "#/components/schemas/Social_links" -* 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 Social_linksService.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: [Social_links] - * 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/Social_links" - * responses: - * 200: - * description: The items were successfully imported - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Social_links" - * 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 Social_linksService.bulkImport(req, res, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/social_links/{id}: - * put: - * security: - * - bearerAuth: [] - * tags: [Social_links] - * 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/Social_links" - * required: - * - id - * responses: - * 200: - * description: The item data was successfully updated - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Social_links" - * 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 Social_linksService.update(req.body.data, req.body.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/social_links/{id}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Social_links] - * 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/Social_links" - * 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 Social_linksService.remove(req.params.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/social_links/deleteByIds: - * post: - * security: - * - bearerAuth: [] - * tags: [Social_links] - * 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/Social_links" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Items not found - * 500: - * description: Some server error - */ -router.post('/deleteByIds', wrapAsync(async (req, res) => { - await Social_linksService.deleteByIds(req.body.data, req.currentUser); - const payload = true; - res.status(200).send(payload); - })); - -/** - * @swagger - * /api/social_links: - * get: - * security: - * - bearerAuth: [] - * tags: [Social_links] - * summary: Get all social_links - * description: Get all social_links - * responses: - * 200: - * description: Social_links list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Social_links" - * 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 Social_linksDBApi.findAll( - req.query, { currentUser } - ); - if (filetype && filetype === 'csv') { - const fields = ['id','label','url', - 'sort_order', - - - ]; - 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/social_links/count: - * get: - * security: - * - bearerAuth: [] - * tags: [Social_links] - * summary: Count all social_links - * description: Count all social_links - * responses: - * 200: - * description: Social_links count successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Social_links" - * 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 Social_linksDBApi.findAll( - req.query, - null, - { countOnly: true, currentUser } - ); - - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/social_links/autocomplete: - * get: - * security: - * - bearerAuth: [] - * tags: [Social_links] - * summary: Find all social_links that match search criteria - * description: Find all social_links that match search criteria - * responses: - * 200: - * description: Social_links list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Social_links" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/autocomplete', async (req, res) => { - - const payload = await Social_linksDBApi.findAllAutocomplete( - req.query.query, - req.query.limit, - req.query.offset, - - ); - - res.status(200).send(payload); -}); - -/** - * @swagger - * /api/social_links/{id}: - * get: - * security: - * - bearerAuth: [] - * tags: [Social_links] - * 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/Social_links" - * 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 Social_linksDBApi.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/testimonials.js b/backend/src/routes/testimonials.js deleted file mode 100644 index 78b5978..0000000 --- a/backend/src/routes/testimonials.js +++ /dev/null @@ -1,447 +0,0 @@ - -const express = require('express'); - -const TestimonialsService = require('../services/testimonials'); -const TestimonialsDBApi = require('../db/api/testimonials'); -const wrapAsync = require('../helpers').wrapAsync; - - -const router = express.Router(); - -const { parse } = require('json2csv'); - - -const { - checkCrudPermissions, -} = require('../middlewares/check-permissions'); - -router.use(checkCrudPermissions('testimonials')); - - -/** - * @swagger - * components: - * schemas: - * Testimonials: - * type: object - * properties: - - * client_name: - * type: string - * default: client_name - * client_title: - * type: string - * default: client_title - * company_name: - * type: string - * default: company_name - * quote: - * type: string - * default: quote - * source: - * type: string - * default: source - * source_url: - * type: string - * default: source_url - - * rating: - * type: integer - * format: int64 - - - */ - -/** - * @swagger - * tags: - * name: Testimonials - * description: The Testimonials managing API - */ - -/** -* @swagger -* /api/testimonials: -* post: -* security: -* - bearerAuth: [] -* tags: [Testimonials] -* 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/Testimonials" -* responses: -* 200: -* description: The item was successfully added -* content: -* application/json: -* schema: -* $ref: "#/components/schemas/Testimonials" -* 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 TestimonialsService.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: [Testimonials] - * 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/Testimonials" - * responses: - * 200: - * description: The items were successfully imported - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Testimonials" - * 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 TestimonialsService.bulkImport(req, res, true, link.host); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/testimonials/{id}: - * put: - * security: - * - bearerAuth: [] - * tags: [Testimonials] - * 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/Testimonials" - * required: - * - id - * responses: - * 200: - * description: The item data was successfully updated - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/Testimonials" - * 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 TestimonialsService.update(req.body.data, req.body.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/testimonials/{id}: - * delete: - * security: - * - bearerAuth: [] - * tags: [Testimonials] - * 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/Testimonials" - * 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 TestimonialsService.remove(req.params.id, req.currentUser); - const payload = true; - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/testimonials/deleteByIds: - * post: - * security: - * - bearerAuth: [] - * tags: [Testimonials] - * 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/Testimonials" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Items not found - * 500: - * description: Some server error - */ -router.post('/deleteByIds', wrapAsync(async (req, res) => { - await TestimonialsService.deleteByIds(req.body.data, req.currentUser); - const payload = true; - res.status(200).send(payload); - })); - -/** - * @swagger - * /api/testimonials: - * get: - * security: - * - bearerAuth: [] - * tags: [Testimonials] - * summary: Get all testimonials - * description: Get all testimonials - * responses: - * 200: - * description: Testimonials list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Testimonials" - * 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 TestimonialsDBApi.findAll( - req.query, { currentUser } - ); - if (filetype && filetype === 'csv') { - const fields = ['id','client_name','client_title','company_name','quote','source','source_url', - 'rating', - - 'testimonial_date', - ]; - 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/testimonials/count: - * get: - * security: - * - bearerAuth: [] - * tags: [Testimonials] - * summary: Count all testimonials - * description: Count all testimonials - * responses: - * 200: - * description: Testimonials count successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Testimonials" - * 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 TestimonialsDBApi.findAll( - req.query, - null, - { countOnly: true, currentUser } - ); - - res.status(200).send(payload); -})); - -/** - * @swagger - * /api/testimonials/autocomplete: - * get: - * security: - * - bearerAuth: [] - * tags: [Testimonials] - * summary: Find all testimonials that match search criteria - * description: Find all testimonials that match search criteria - * responses: - * 200: - * description: Testimonials list successfully received - * content: - * application/json: - * schema: - * type: array - * items: - * $ref: "#/components/schemas/Testimonials" - * 401: - * $ref: "#/components/responses/UnauthorizedError" - * 404: - * description: Data not found - * 500: - * description: Some server error - */ -router.get('/autocomplete', async (req, res) => { - - const payload = await TestimonialsDBApi.findAllAutocomplete( - req.query.query, - req.query.limit, - req.query.offset, - - ); - - res.status(200).send(payload); -}); - -/** - * @swagger - * /api/testimonials/{id}: - * get: - * security: - * - bearerAuth: [] - * tags: [Testimonials] - * 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/Testimonials" - * 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 TestimonialsDBApi.findBy( - { id: req.params.id }, - ); - - - - res.status(200).send(payload); -})); - -router.use('/', require('../helpers').commonErrorHandler); - -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/benefits.js b/backend/src/services/benefits.js deleted file mode 100644 index 672ccb3..0000000 --- a/backend/src/services/benefits.js +++ /dev/null @@ -1,138 +0,0 @@ -const db = require('../db/models'); -const BenefitsDBApi = require('../db/api/benefits'); -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 BenefitsService { - static async create(data, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - await BenefitsDBApi.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 BenefitsDBApi.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 benefits = await BenefitsDBApi.findBy( - {id}, - {transaction}, - ); - - if (!benefits) { - throw new ValidationError( - 'benefitsNotFound', - ); - } - - const updatedBenefits = await BenefitsDBApi.update( - id, - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - return updatedBenefits; - - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async deleteByIds(ids, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await BenefitsDBApi.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 BenefitsDBApi.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/inquiries.js b/backend/src/services/inquiries.js deleted file mode 100644 index 19ed836..0000000 --- a/backend/src/services/inquiries.js +++ /dev/null @@ -1,138 +0,0 @@ -const db = require('../db/models'); -const InquiriesDBApi = require('../db/api/inquiries'); -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 InquiriesService { - static async create(data, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - await InquiriesDBApi.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 InquiriesDBApi.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 inquiries = await InquiriesDBApi.findBy( - {id}, - {transaction}, - ); - - if (!inquiries) { - throw new ValidationError( - 'inquiriesNotFound', - ); - } - - const updatedInquiries = await InquiriesDBApi.update( - id, - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - return updatedInquiries; - - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async deleteByIds(ids, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await InquiriesDBApi.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 InquiriesDBApi.remove( - id, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - -}; - - 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 3d5d8fb..0000000 --- a/backend/src/services/notifications/list.js +++ /dev/null @@ -1,104 +0,0 @@ -const errors = { - app: { - title: 'Blackness Studio Website', - }, - - 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/page_sections.js b/backend/src/services/page_sections.js deleted file mode 100644 index 29d814d..0000000 --- a/backend/src/services/page_sections.js +++ /dev/null @@ -1,138 +0,0 @@ -const db = require('../db/models'); -const Page_sectionsDBApi = require('../db/api/page_sections'); -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 Page_sectionsService { - static async create(data, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - await Page_sectionsDBApi.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 Page_sectionsDBApi.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 page_sections = await Page_sectionsDBApi.findBy( - {id}, - {transaction}, - ); - - if (!page_sections) { - throw new ValidationError( - 'page_sectionsNotFound', - ); - } - - const updatedPage_sections = await Page_sectionsDBApi.update( - id, - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - return updatedPage_sections; - - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async deleteByIds(ids, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await Page_sectionsDBApi.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 Page_sectionsDBApi.remove( - id, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - -}; - - diff --git a/backend/src/services/pages.js b/backend/src/services/pages.js deleted file mode 100644 index d61afe1..0000000 --- a/backend/src/services/pages.js +++ /dev/null @@ -1,138 +0,0 @@ -const db = require('../db/models'); -const PagesDBApi = require('../db/api/pages'); -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 PagesService { - static async create(data, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - await PagesDBApi.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 PagesDBApi.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 pages = await PagesDBApi.findBy( - {id}, - {transaction}, - ); - - if (!pages) { - throw new ValidationError( - 'pagesNotFound', - ); - } - - const updatedPages = await PagesDBApi.update( - id, - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - return updatedPages; - - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async deleteByIds(ids, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await PagesDBApi.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 PagesDBApi.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/portfolio_items.js b/backend/src/services/portfolio_items.js deleted file mode 100644 index dba6bf7..0000000 --- a/backend/src/services/portfolio_items.js +++ /dev/null @@ -1,138 +0,0 @@ -const db = require('../db/models'); -const Portfolio_itemsDBApi = require('../db/api/portfolio_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 Portfolio_itemsService { - static async create(data, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - await Portfolio_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 Portfolio_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 portfolio_items = await Portfolio_itemsDBApi.findBy( - {id}, - {transaction}, - ); - - if (!portfolio_items) { - throw new ValidationError( - 'portfolio_itemsNotFound', - ); - } - - const updatedPortfolio_items = await Portfolio_itemsDBApi.update( - id, - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - return updatedPortfolio_items; - - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async deleteByIds(ids, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await Portfolio_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 Portfolio_itemsDBApi.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 64f483b..0000000 --- a/backend/src/services/search.js +++ /dev/null @@ -1,424 +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", - - ], - - - - - - - - - "site_settings": [ - - "site_name", - - "tagline", - - "primary_domain", - - "primary_cta_label", - - "primary_cta_url", - - "contact_email", - - "contact_phone", - - "location", - - "accent_color_hex", - - "seo_title", - - "seo_description", - - ], - - - - - - - "pages": [ - - "title", - - "slug", - - "meta_title", - - "meta_description", - - ], - - - - - - - "page_sections": [ - - "section_label", - - "headline", - - "subheadline", - - "body", - - "primary_button_label", - - "primary_button_url", - - "secondary_button_label", - - "secondary_button_url", - - ], - - - - - - - "services": [ - - "name", - - "short_description", - - "details", - - "cta_label", - - "cta_url", - - "icon_name", - - ], - - - - - - - "portfolio_items": [ - - "title", - - "client_name", - - "summary", - - "case_study", - - "external_url", - - "tech_stack", - - ], - - - - - - - "testimonials": [ - - "client_name", - - "client_title", - - "company_name", - - "quote", - - "source", - - "source_url", - - ], - - - - - - - "skills": [ - - "name", - - ], - - - - - - - "benefits": [ - - "title", - - "description", - - "icon_name", - - ], - - - - - - - "social_links": [ - - "label", - - "url", - - ], - - - - - - - "inquiries": [ - - "full_name", - - "email", - - "company_name", - - "subject", - - "message", - - "source_page", - - "fiverr_url", - - ], - - - }; - const columnsInt = { - - - - - - - - - - - - - - - "pages": [ - - "sort_order", - - ], - - - - - - "page_sections": [ - - "sort_order", - - ], - - - - - - "services": [ - - "sort_order", - - ], - - - - - - - - - - "testimonials": [ - - "rating", - - ], - - - - - - "skills": [ - - "proficiency_level", - - "sort_order", - - ], - - - - - - "benefits": [ - - "sort_order", - - ], - - - - - - "social_links": [ - - "sort_order", - - ], - - - - - - - }; - - 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/services.js b/backend/src/services/services.js deleted file mode 100644 index eaa56ec..0000000 --- a/backend/src/services/services.js +++ /dev/null @@ -1,138 +0,0 @@ -const db = require('../db/models'); -const ServicesDBApi = require('../db/api/services'); -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 ServicesService { - static async create(data, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - await ServicesDBApi.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 ServicesDBApi.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 services = await ServicesDBApi.findBy( - {id}, - {transaction}, - ); - - if (!services) { - throw new ValidationError( - 'servicesNotFound', - ); - } - - const updatedServices = await ServicesDBApi.update( - id, - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - return updatedServices; - - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async deleteByIds(ids, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await ServicesDBApi.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 ServicesDBApi.remove( - id, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - -}; - - diff --git a/backend/src/services/site_settings.js b/backend/src/services/site_settings.js deleted file mode 100644 index 0ad801c..0000000 --- a/backend/src/services/site_settings.js +++ /dev/null @@ -1,138 +0,0 @@ -const db = require('../db/models'); -const Site_settingsDBApi = require('../db/api/site_settings'); -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 Site_settingsService { - static async create(data, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - await Site_settingsDBApi.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 Site_settingsDBApi.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 site_settings = await Site_settingsDBApi.findBy( - {id}, - {transaction}, - ); - - if (!site_settings) { - throw new ValidationError( - 'site_settingsNotFound', - ); - } - - const updatedSite_settings = await Site_settingsDBApi.update( - id, - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - return updatedSite_settings; - - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async deleteByIds(ids, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await Site_settingsDBApi.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 Site_settingsDBApi.remove( - id, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - -}; - - diff --git a/backend/src/services/skills.js b/backend/src/services/skills.js deleted file mode 100644 index 257d064..0000000 --- a/backend/src/services/skills.js +++ /dev/null @@ -1,138 +0,0 @@ -const db = require('../db/models'); -const SkillsDBApi = require('../db/api/skills'); -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 SkillsService { - static async create(data, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - await SkillsDBApi.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 SkillsDBApi.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 skills = await SkillsDBApi.findBy( - {id}, - {transaction}, - ); - - if (!skills) { - throw new ValidationError( - 'skillsNotFound', - ); - } - - const updatedSkills = await SkillsDBApi.update( - id, - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - return updatedSkills; - - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async deleteByIds(ids, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await SkillsDBApi.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 SkillsDBApi.remove( - id, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - -}; - - diff --git a/backend/src/services/social_links.js b/backend/src/services/social_links.js deleted file mode 100644 index 15c5fee..0000000 --- a/backend/src/services/social_links.js +++ /dev/null @@ -1,138 +0,0 @@ -const db = require('../db/models'); -const Social_linksDBApi = require('../db/api/social_links'); -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 Social_linksService { - static async create(data, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - await Social_linksDBApi.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 Social_linksDBApi.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 social_links = await Social_linksDBApi.findBy( - {id}, - {transaction}, - ); - - if (!social_links) { - throw new ValidationError( - 'social_linksNotFound', - ); - } - - const updatedSocial_links = await Social_linksDBApi.update( - id, - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - return updatedSocial_links; - - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async deleteByIds(ids, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await Social_linksDBApi.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 Social_linksDBApi.remove( - id, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - } catch (error) { - await transaction.rollback(); - throw error; - } - } - - -}; - - diff --git a/backend/src/services/testimonials.js b/backend/src/services/testimonials.js deleted file mode 100644 index d98a26a..0000000 --- a/backend/src/services/testimonials.js +++ /dev/null @@ -1,138 +0,0 @@ -const db = require('../db/models'); -const TestimonialsDBApi = require('../db/api/testimonials'); -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 TestimonialsService { - static async create(data, currentUser) { - const transaction = await db.sequelize.transaction(); - try { - await TestimonialsDBApi.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 TestimonialsDBApi.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 testimonials = await TestimonialsDBApi.findBy( - {id}, - {transaction}, - ); - - if (!testimonials) { - throw new ValidationError( - 'testimonialsNotFound', - ); - } - - const updatedTestimonials = await TestimonialsDBApi.update( - id, - data, - { - currentUser, - transaction, - }, - ); - - await transaction.commit(); - return updatedTestimonials; - - } catch (error) { - await transaction.rollback(); - throw error; - } - }; - - static async deleteByIds(ids, currentUser) { - const transaction = await db.sequelize.transaction(); - - try { - await TestimonialsDBApi.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 TestimonialsDBApi.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 56ffb15..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_blackness_studio_website - 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/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 c22dd8e..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/Benefits/CardBenefits.tsx b/frontend/src/components/Benefits/CardBenefits.tsx deleted file mode 100644 index 8d1e5de..0000000 --- a/frontend/src/components/Benefits/CardBenefits.tsx +++ /dev/null @@ -1,159 +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 = { - benefits: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const CardBenefits = ({ - benefits, - 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_BENEFITS') - - - return ( -
    - {loading && } -
      - {!loading && benefits.map((item, index) => ( -
    • - -
      - - - {item.title} - - - -
      - -
      -
      -
      - - -
      -
      Title
      -
      -
      - { item.title } -
      -
      -
      - - - - -
      -
      Description
      -
      -
      - { item.description } -
      -
      -
      - - - - -
      -
      IconName
      -
      -
      - { item.icon_name } -
      -
      -
      - - - - -
      -
      SortOrder
      -
      -
      - { item.sort_order } -
      -
      -
      - - - - -
      -
      IsActive
      -
      -
      - { dataFormatter.booleanFormatter(item.is_active) } -
      -
      -
      - - - -
      -
    • - ))} - {!loading && benefits.length === 0 && ( -
      -

      No data to display

      -
      - )} -
    -
    - -
    -
    - ); -}; - -export default CardBenefits; diff --git a/frontend/src/components/Benefits/ListBenefits.tsx b/frontend/src/components/Benefits/ListBenefits.tsx deleted file mode 100644 index fb22596..0000000 --- a/frontend/src/components/Benefits/ListBenefits.tsx +++ /dev/null @@ -1,120 +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 = { - benefits: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const ListBenefits = ({ benefits, loading, onDelete, currentPage, numPages, onPageChange }: Props) => { - - const currentUser = useAppSelector((state) => state.auth.currentUser); - const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_BENEFITS') - - const corners = useAppSelector((state) => state.style.corners); - const bgColor = useAppSelector((state) => state.style.cardsColor); - - - return ( - <> -
    - {loading && } - {!loading && benefits.map((item) => ( -
    - -
    - - dark:divide-dark-700 overflow-x-auto' - } - > - - -
    -

    Title

    -

    { item.title }

    -
    - - - - -
    -

    Description

    -

    { item.description }

    -
    - - - - -
    -

    IconName

    -

    { item.icon_name }

    -
    - - - - -
    -

    SortOrder

    -

    { item.sort_order }

    -
    - - - - -
    -

    IsActive

    -

    { dataFormatter.booleanFormatter(item.is_active) }

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

    No data to display

    -
    - )} -
    -
    - -
    - - ) -}; - -export default ListBenefits \ No newline at end of file diff --git a/frontend/src/components/Benefits/TableBenefits.tsx b/frontend/src/components/Benefits/TableBenefits.tsx deleted file mode 100644 index 7429a71..0000000 --- a/frontend/src/components/Benefits/TableBenefits.tsx +++ /dev/null @@ -1,476 +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/benefits/benefitsSlice' -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 "./configureBenefitsCols"; -import _ from 'lodash'; -import dataFormatter from '../../helpers/dataFormatter' -import {dataGridStyles} from "../../styles"; - - -import CardBenefits from './CardBenefits'; - - -const perPage = 10 - -const TableSampleBenefits = ({ 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 { benefits, loading, count, notify: benefitsNotify, refetch } = useAppSelector((state) => state.benefits) - 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 (benefitsNotify.showNotification) { - notify(benefitsNotify.typeNotification, benefitsNotify.textNotification); - } - }, [benefitsNotify.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, - `benefits`, - 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={benefits ?? []} - 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?

    -
    - - - {benefits && Array.isArray(benefits) && !showGrid && ( - - )} - - - - {showGrid && dataGrid} - - - {selectedRows.length > 0 && - createPortal( - onDeleteRows(selectedRows)} - />, - document.getElementById('delete-rows-button'), - )} - - - ) -} - -export default TableSampleBenefits diff --git a/frontend/src/components/Benefits/configureBenefitsCols.tsx b/frontend/src/components/Benefits/configureBenefitsCols.tsx deleted file mode 100644 index be7fd3c..0000000 --- a/frontend/src/components/Benefits/configureBenefitsCols.tsx +++ /dev/null @@ -1,145 +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_BENEFITS') - - return [ - - { - field: 'title', - headerName: 'Title', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'description', - headerName: 'Description', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'icon_name', - headerName: 'IconName', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'sort_order', - headerName: 'SortOrder', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'number', - - }, - - { - field: 'is_active', - headerName: 'IsActive', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'boolean', - - }, - - { - field: 'actions', - type: 'actions', - minWidth: 30, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - getActions: (params: GridRowParams) => { - - return [ -
    - -
    , - ] - }, - }, - ]; -}; 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/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/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/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/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 06733d4..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/Inquiries/CardInquiries.tsx b/frontend/src/components/Inquiries/CardInquiries.tsx deleted file mode 100644 index eae6635..0000000 --- a/frontend/src/components/Inquiries/CardInquiries.tsx +++ /dev/null @@ -1,231 +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 = { - inquiries: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const CardInquiries = ({ - inquiries, - 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_INQUIRIES') - - - return ( -
    - {loading && } -
      - {!loading && inquiries.map((item, index) => ( -
    • - -
      - - - {item.subject} - - - -
      - -
      -
      -
      - - -
      -
      FullName
      -
      -
      - { item.full_name } -
      -
      -
      - - - - -
      -
      Email
      -
      -
      - { item.email } -
      -
      -
      - - - - -
      -
      CompanyName
      -
      -
      - { item.company_name } -
      -
      -
      - - - - -
      -
      Subject
      -
      -
      - { item.subject } -
      -
      -
      - - - - -
      -
      Message
      -
      -
      - { item.message } -
      -
      -
      - - - - -
      -
      SourcePage
      -
      -
      - { item.source_page } -
      -
      -
      - - - - -
      -
      Status
      -
      -
      - { item.status } -
      -
      -
      - - - - -
      -
      ReceivedAt
      -
      -
      - { dataFormatter.dateTimeFormatter(item.received_at) } -
      -
      -
      - - - - -
      -
      RepliedAt
      -
      -
      - { dataFormatter.dateTimeFormatter(item.replied_at) } -
      -
      -
      - - - - -
      -
      FiverrURL
      -
      -
      - { item.fiverr_url } -
      -
      -
      - - - - -
      -
      AssignedTo
      -
      -
      - { dataFormatter.usersOneListFormatter(item.assigned_to) } -
      -
      -
      - - - -
      -
    • - ))} - {!loading && inquiries.length === 0 && ( -
      -

      No data to display

      -
      - )} -
    -
    - -
    -
    - ); -}; - -export default CardInquiries; diff --git a/frontend/src/components/Inquiries/ListInquiries.tsx b/frontend/src/components/Inquiries/ListInquiries.tsx deleted file mode 100644 index a57bfae..0000000 --- a/frontend/src/components/Inquiries/ListInquiries.tsx +++ /dev/null @@ -1,168 +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 = { - inquiries: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const ListInquiries = ({ inquiries, loading, onDelete, currentPage, numPages, onPageChange }: Props) => { - - const currentUser = useAppSelector((state) => state.auth.currentUser); - const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_INQUIRIES') - - const corners = useAppSelector((state) => state.style.corners); - const bgColor = useAppSelector((state) => state.style.cardsColor); - - - return ( - <> -
    - {loading && } - {!loading && inquiries.map((item) => ( -
    - -
    - - dark:divide-dark-700 overflow-x-auto' - } - > - - -
    -

    FullName

    -

    { item.full_name }

    -
    - - - - -
    -

    Email

    -

    { item.email }

    -
    - - - - -
    -

    CompanyName

    -

    { item.company_name }

    -
    - - - - -
    -

    Subject

    -

    { item.subject }

    -
    - - - - -
    -

    Message

    -

    { item.message }

    -
    - - - - -
    -

    SourcePage

    -

    { item.source_page }

    -
    - - - - -
    -

    Status

    -

    { item.status }

    -
    - - - - -
    -

    ReceivedAt

    -

    { dataFormatter.dateTimeFormatter(item.received_at) }

    -
    - - - - -
    -

    RepliedAt

    -

    { dataFormatter.dateTimeFormatter(item.replied_at) }

    -
    - - - - -
    -

    FiverrURL

    -

    { item.fiverr_url }

    -
    - - - - -
    -

    AssignedTo

    -

    { dataFormatter.usersOneListFormatter(item.assigned_to) }

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

    No data to display

    -
    - )} -
    -
    - -
    - - ) -}; - -export default ListInquiries \ No newline at end of file diff --git a/frontend/src/components/Inquiries/TableInquiries.tsx b/frontend/src/components/Inquiries/TableInquiries.tsx deleted file mode 100644 index c3492fa..0000000 --- a/frontend/src/components/Inquiries/TableInquiries.tsx +++ /dev/null @@ -1,507 +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/inquiries/inquiriesSlice' -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 "./configureInquiriesCols"; -import _ from 'lodash'; -import dataFormatter from '../../helpers/dataFormatter' -import {dataGridStyles} from "../../styles"; - - -import KanbanBoard from '../KanbanBoard/KanbanBoard'; -import axios from 'axios'; - - -const perPage = 10 - -const TableSampleInquiries = ({ 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 [kanbanColumns, setKanbanColumns] = useState | null>(null); - const [kanbanFilters, setKanbanFilters] = useState(''); - - const { inquiries, loading, count, notify: inquiriesNotify, refetch } = useAppSelector((state) => state.inquiries) - 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 (inquiriesNotify.showNotification) { - notify(inquiriesNotify.typeNotification, inquiriesNotify.textNotification); - } - }, [inquiriesNotify.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) - } - - - useEffect(() => { - - - - setKanbanColumns([ - - { id: "new", label: "new" }, - - { id: "in_review", label: "in_review" }, - - { id: "replied", label: "replied" }, - - { id: "archived", label: "archived" }, - - ]); - - - }, []); - - - - - 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, ''); - - setKanbanFilters(''); - - setFilterItems(newItems); - } - }; - - const handleSubmit = () => { - loadData(0, generateFilterRequests); - - setKanbanFilters(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, ''); - - setKanbanFilters(''); - - }; - - const onPageChange = (page: number) => { - loadData(page); - setCurrentPage(page); - }; - - - useEffect(() => { - if (!currentUser) return; - - loadColumns( - handleDeleteModalAction, - `inquiries`, - 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={inquiries ?? []} - 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?

    -
    - - - - {!showGrid && kanbanColumns && ( - - )} - - - - {showGrid && dataGrid} - - - {selectedRows.length > 0 && - createPortal( - onDeleteRows(selectedRows)} - />, - document.getElementById('delete-rows-button'), - )} - - - ) -} - -export default TableSampleInquiries diff --git a/frontend/src/components/Inquiries/configureInquiriesCols.tsx b/frontend/src/components/Inquiries/configureInquiriesCols.tsx deleted file mode 100644 index 3e09103..0000000 --- a/frontend/src/components/Inquiries/configureInquiriesCols.tsx +++ /dev/null @@ -1,246 +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_INQUIRIES') - - return [ - - { - 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: 'company_name', - headerName: 'CompanyName', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'subject', - headerName: 'Subject', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'message', - headerName: 'Message', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'source_page', - headerName: 'SourcePage', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'status', - headerName: 'Status', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'received_at', - headerName: 'ReceivedAt', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'dateTime', - valueGetter: (params: GridValueGetterParams) => - new Date(params.row.received_at), - - }, - - { - field: 'replied_at', - headerName: 'RepliedAt', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'dateTime', - valueGetter: (params: GridValueGetterParams) => - new Date(params.row.replied_at), - - }, - - { - field: 'fiverr_url', - headerName: 'FiverrURL', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'assigned_to', - headerName: 'AssignedTo', - 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('users'), - valueGetter: (params: GridValueGetterParams) => - params?.value?.id ?? params?.value, - - }, - - { - field: 'actions', - type: 'actions', - minWidth: 30, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - getActions: (params: GridRowParams) => { - - return [ -
    - -
    , - ] - }, - }, - ]; -}; 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 639e479..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 db0097d..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/ListActionsPopover.tsx b/frontend/src/components/ListActionsPopover.tsx deleted file mode 100644 index 965e727..0000000 --- a/frontend/src/components/ListActionsPopover.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import React from 'react'; -import Link from 'next/link'; -import Button from '@mui/material/Button'; -import BaseIcon from './BaseIcon'; -import { - mdiDotsVertical, - mdiEye, - mdiPencilOutline, - mdiTrashCan, -} from '@mdi/js'; -import Popover from '@mui/material/Popover'; -import { IconButton } from '@mui/material'; - - -type Props = { - itemId: string; - onDelete: (id: string) => void; - hasUpdatePermission: boolean; - className?: string; - iconClassName?: string; - pathEdit: string; - pathView: string; -}; - -const ListActionsPopover = ({ - itemId, - onDelete, - hasUpdatePermission, - className, - iconClassName, - pathEdit, - pathView, - }: Props) => { - const [anchorEl, setAnchorEl] = React.useState(null); - const handleClick = (event) => { - setAnchorEl(event.currentTarget); - }; - const linkView = pathView; - const linkEdit = pathEdit; - const handleClose = () => { - setAnchorEl(null); - }; - - const open = Boolean(anchorEl); - const id = open ? 'simple-popover' : undefined; - - return ( - <> - - - - -
    - - {hasUpdatePermission && ( - - )} - {hasUpdatePermission && ( - - )} -
    -
    - - ); -}; - -export default ListActionsPopover; diff --git a/frontend/src/components/NavBar.tsx b/frontend/src/components/NavBar.tsx deleted file mode 100644 index 4ba2efa..0000000 --- a/frontend/src/components/NavBar.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import React, { ReactNode, useState, useEffect } from 'react' -import { mdiClose, mdiDotsVertical } from '@mdi/js' -import { containerMaxW } from '../config' -import BaseIcon from './BaseIcon' -import NavBarItemPlain from './NavBarItemPlain' -import NavBarMenuList from './NavBarMenuList' -import { MenuNavBarItem } from '../interfaces' -import { useAppSelector } from '../stores/hooks'; - -type Props = { - menu: MenuNavBarItem[] - className: string - children: ReactNode -} - -export default function NavBar({ menu, className = '', children }: Props) { - const [isMenuNavBarActive, setIsMenuNavBarActive] = useState(false) - const [isScrolled, setIsScrolled] = useState(false); - const bgColor = useAppSelector((state) => state.style.bgLayoutColor); - - useEffect(() => { - const handleScroll = () => { - const scrolled = window.scrollY > 0; - setIsScrolled(scrolled); - }; - window.addEventListener('scroll', handleScroll); - return () => { - window.removeEventListener('scroll', handleScroll); - }; - }, []); - - const handleMenuNavBarToggleClick = () => { - setIsMenuNavBarActive(!isMenuNavBarActive) - } - - return ( - - ) -} diff --git a/frontend/src/components/NavBarItem.tsx b/frontend/src/components/NavBarItem.tsx deleted file mode 100644 index eb155e3..0000000 --- a/frontend/src/components/NavBarItem.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import React, {useEffect, useRef} from 'react' -import Link from 'next/link' -import { useState } from 'react' -import { mdiChevronUp, mdiChevronDown } from '@mdi/js' -import BaseDivider from './BaseDivider' -import BaseIcon from './BaseIcon' -import UserAvatarCurrentUser from './UserAvatarCurrentUser' -import NavBarMenuList from './NavBarMenuList' -import { useAppDispatch, useAppSelector } from '../stores/hooks' -import { MenuNavBarItem } from '../interfaces' -import { setDarkMode } from '../stores/styleSlice' -import { logoutUser } from '../stores/authSlice' -import { useRouter } from 'next/router'; -import ClickOutside from "./ClickOutside"; - -type Props = { - item: MenuNavBarItem -} - -export default function NavBarItem({ item }: Props) { - const router = useRouter(); - const dispatch = useAppDispatch(); - const excludedRef = useRef(null); - - const navBarItemLabelActiveColorStyle = useAppSelector( - (state) => state.style.navBarItemLabelActiveColorStyle - ) - const navBarItemLabelStyle = useAppSelector((state) => state.style.navBarItemLabelStyle) - const navBarItemLabelHoverStyle = useAppSelector((state) => state.style.navBarItemLabelHoverStyle) - - const currentUser = useAppSelector((state) => state.auth.currentUser); - - const userName = `${currentUser?.firstName ? currentUser?.firstName : ""} ${currentUser?.lastName ? currentUser?.lastName : ""}`; - - const [isDropdownActive, setIsDropdownActive] = useState(false) - - useEffect(() => { - return () => setIsDropdownActive(false); - }, [router.pathname]); - - const componentClass = [ - 'block lg:flex items-center relative cursor-pointer', - isDropdownActive - ? `${navBarItemLabelActiveColorStyle} dark:text-slate-400` - : `${navBarItemLabelStyle} dark:text-white dark:hover:text-slate-400 ${navBarItemLabelHoverStyle}`, - item.menu ? 'lg:py-2 lg:px-3' : 'py-2 px-3', - item.isDesktopNoLabel ? 'lg:w-16 lg:justify-center' : '', - ].join(' ') - - const itemLabel = item.isCurrentUser ? userName : item.label - - const handleMenuClick = () => { - if (item.menu) { - setIsDropdownActive(!isDropdownActive) - } - - if (item.isToggleLightDark) { - dispatch(setDarkMode(null)) - } - - if(item.isLogout) { - dispatch(logoutUser()) - router.push('/login') - } - } - - const getItemId = (label) => { - switch (label) { - case 'Light/Dark': - return 'themeToggle'; - case 'Log out': - return 'logout'; - default: - return undefined; - } - }; - - const NavBarItemComponentContents = ( - <> -
    - {item.icon && } - - {itemLabel} - - {item.isCurrentUser && } - {item.menu && ( - - )} -
    - {item.menu && ( -
    - setIsDropdownActive(false)} excludedElements={[excludedRef]}> - - -
    - )} - - ) - - if (item.isDivider) { - return - } - - if (item.href) { - return ( - - {NavBarItemComponentContents} - - ) - } - - return
    {NavBarItemComponentContents}
    -} diff --git a/frontend/src/components/NavBarItemPlain.tsx b/frontend/src/components/NavBarItemPlain.tsx deleted file mode 100644 index 5589728..0000000 --- a/frontend/src/components/NavBarItemPlain.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import React, { ReactNode } from 'react' -import { useAppSelector } from '../stores/hooks' - -type Props = { - display?: string - useMargin?: boolean - children?: ReactNode - onClick?: (e: React.MouseEvent) => void -} - -export default function NavBarItemPlain({ - display = 'flex', - useMargin = false, - onClick, - children, -}: Props) { - const navBarItemLabelStyle = useAppSelector((state) => state.style.navBarItemLabelStyle) - const navBarItemLabelHoverStyle = useAppSelector((state) => state.style.navBarItemLabelHoverStyle) - - const classBase = 'items-center cursor-pointer dark:text-white dark:hover:text-slate-400' - const classAddon = `${display} ${navBarItemLabelStyle} ${navBarItemLabelHoverStyle} ${ - useMargin ? 'my-2 mx-3' : 'py-2 px-3' - }` - - return ( -
    - {children} -
    - ) -} diff --git a/frontend/src/components/NavBarMenuList.tsx b/frontend/src/components/NavBarMenuList.tsx deleted file mode 100644 index 0896428..0000000 --- a/frontend/src/components/NavBarMenuList.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react' -import { MenuNavBarItem } from '../interfaces' -import NavBarItem from './NavBarItem' - -type Props = { - menu: MenuNavBarItem[] -} - -export default function NavBarMenuList({ menu }: Props) { - return ( - <> - {menu.map((item, index) => ( -
    - -
    - ))} - - ) -} diff --git a/frontend/src/components/NotificationBar.tsx b/frontend/src/components/NotificationBar.tsx deleted file mode 100644 index a3ade58..0000000 --- a/frontend/src/components/NotificationBar.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { mdiClose } from '@mdi/js' -import React, { ReactNode, useState } from 'react' -import { ColorKey } from '../interfaces' -import { colorsBgLight, colorsOutline } from '../colors' -import BaseButton from './BaseButton' -import BaseIcon from './BaseIcon' - -type Props = { - color: ColorKey - icon?: string - outline?: boolean - children: ReactNode - button?: ReactNode -} - -const NotificationBar = ({ outline = false, children, ...props }: Props) => { - const componentColorClass = outline ? colorsOutline[props.color] : colorsBgLight[props.color] - - const [isDismissed, setIsDismissed] = useState(false) - - const dismiss = (e: React.MouseEvent) => { - e.preventDefault() - - setIsDismissed(true) - } - - if (isDismissed) { - return null - } - - return ( -
    -
    -
    - {props.icon && ( - - )} - {children} -
    - {props.button} - {!props.button && ( - - )} -
    -
    - ) -} - -export default NotificationBar diff --git a/frontend/src/components/OverlayLayer.tsx b/frontend/src/components/OverlayLayer.tsx deleted file mode 100644 index 4cb9e6f..0000000 --- a/frontend/src/components/OverlayLayer.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React, { ReactNode } from 'react' -import { useAppSelector } from '../stores/hooks' - -type Props = { - zIndex?: string - type?: string - children?: ReactNode - className?: string - onClick: (e: React.MouseEvent) => void -} - -export default function OverlayLayer({ - zIndex = 'z-50', - type = 'flex', - children, - className, - ...props -}: Props) { - const overlayStyle = useAppSelector((state) => state.style.overlayStyle) - - const handleClick = (e: React.MouseEvent) => { - e.preventDefault() - - if (props.onClick) { - props.onClick(e) - } - } - - return ( -
    -
    - - {children} -
    - ) -} diff --git a/frontend/src/components/Page_sections/CardPage_sections.tsx b/frontend/src/components/Page_sections/CardPage_sections.tsx deleted file mode 100644 index 726164a..0000000 --- a/frontend/src/components/Page_sections/CardPage_sections.tsx +++ /dev/null @@ -1,268 +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 = { - page_sections: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const CardPage_sections = ({ - page_sections, - 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_PAGE_SECTIONS') - - - return ( -
    - {loading && } -
      - {!loading && page_sections.map((item, index) => ( -
    • - -
      - - - -

      {item.section_label}

      - - - -
      - -
      -
      -
      - - -
      -
      Page
      -
      -
      - { dataFormatter.pagesOneListFormatter(item.page) } -
      -
      -
      - - - - -
      -
      SectionType
      -
      -
      - { item.section_type } -
      -
      -
      - - - - -
      -
      SectionLabel
      -
      -
      - { item.section_label } -
      -
      -
      - - - - -
      -
      Headline
      -
      -
      - { item.headline } -
      -
      -
      - - - - -
      -
      Subheadline
      -
      -
      - { item.subheadline } -
      -
      -
      - - - - -
      -
      Body
      -
      -
      - { item.body } -
      -
      -
      - - - - -
      -
      BackgroundImages
      -
      -
      - -
      -
      -
      - - - - -
      -
      PrimaryButtonLabel
      -
      -
      - { item.primary_button_label } -
      -
      -
      - - - - -
      -
      PrimaryButtonURL
      -
      -
      - { item.primary_button_url } -
      -
      -
      - - - - -
      -
      SecondaryButtonLabel
      -
      -
      - { item.secondary_button_label } -
      -
      -
      - - - - -
      -
      SecondaryButtonURL
      -
      -
      - { item.secondary_button_url } -
      -
      -
      - - - - -
      -
      SortOrder
      -
      -
      - { item.sort_order } -
      -
      -
      - - - - -
      -
      IsVisible
      -
      -
      - { dataFormatter.booleanFormatter(item.is_visible) } -
      -
      -
      - - - -
      -
    • - ))} - {!loading && page_sections.length === 0 && ( -
      -

      No data to display

      -
      - )} -
    -
    - -
    -
    - ); -}; - -export default CardPage_sections; diff --git a/frontend/src/components/Page_sections/ListPage_sections.tsx b/frontend/src/components/Page_sections/ListPage_sections.tsx deleted file mode 100644 index d2cb5c6..0000000 --- a/frontend/src/components/Page_sections/ListPage_sections.tsx +++ /dev/null @@ -1,195 +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 = { - page_sections: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const ListPage_sections = ({ page_sections, loading, onDelete, currentPage, numPages, onPageChange }: Props) => { - - const currentUser = useAppSelector((state) => state.auth.currentUser); - const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_PAGE_SECTIONS') - - const corners = useAppSelector((state) => state.style.corners); - const bgColor = useAppSelector((state) => state.style.cardsColor); - - - return ( - <> -
    - {loading && } - {!loading && page_sections.map((item) => ( -
    - -
    - - - - dark:divide-dark-700 overflow-x-auto' - } - > - - -
    -

    Page

    -

    { dataFormatter.pagesOneListFormatter(item.page) }

    -
    - - - - -
    -

    SectionType

    -

    { item.section_type }

    -
    - - - - -
    -

    SectionLabel

    -

    { item.section_label }

    -
    - - - - -
    -

    Headline

    -

    { item.headline }

    -
    - - - - -
    -

    Subheadline

    -

    { item.subheadline }

    -
    - - - - -
    -

    Body

    -

    { item.body }

    -
    - - - - -
    -

    BackgroundImages

    - -
    - - - - -
    -

    PrimaryButtonLabel

    -

    { item.primary_button_label }

    -
    - - - - -
    -

    PrimaryButtonURL

    -

    { item.primary_button_url }

    -
    - - - - -
    -

    SecondaryButtonLabel

    -

    { item.secondary_button_label }

    -
    - - - - -
    -

    SecondaryButtonURL

    -

    { item.secondary_button_url }

    -
    - - - - -
    -

    SortOrder

    -

    { item.sort_order }

    -
    - - - - -
    -

    IsVisible

    -

    { dataFormatter.booleanFormatter(item.is_visible) }

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

    No data to display

    -
    - )} -
    -
    - -
    - - ) -}; - -export default ListPage_sections \ No newline at end of file diff --git a/frontend/src/components/Page_sections/TablePage_sections.tsx b/frontend/src/components/Page_sections/TablePage_sections.tsx deleted file mode 100644 index ee63f80..0000000 --- a/frontend/src/components/Page_sections/TablePage_sections.tsx +++ /dev/null @@ -1,515 +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/page_sections/page_sectionsSlice' -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 "./configurePage_sectionsCols"; -import _ from 'lodash'; -import dataFormatter from '../../helpers/dataFormatter' -import {dataGridStyles} from "../../styles"; - - -import KanbanBoard from '../KanbanBoard/KanbanBoard'; -import axios from 'axios'; - - -const perPage = 10 - -const TableSamplePage_sections = ({ 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 [kanbanColumns, setKanbanColumns] = useState | null>(null); - const [kanbanFilters, setKanbanFilters] = useState(''); - - const { page_sections, loading, count, notify: page_sectionsNotify, refetch } = useAppSelector((state) => state.page_sections) - 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 (page_sectionsNotify.showNotification) { - notify(page_sectionsNotify.typeNotification, page_sectionsNotify.textNotification); - } - }, [page_sectionsNotify.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) - } - - - useEffect(() => { - - - - setKanbanColumns([ - - { id: "hero", label: "hero" }, - - { id: "about", label: "about" }, - - { id: "services", label: "services" }, - - { id: "portfolio", label: "portfolio" }, - - { id: "why_choose_me", label: "why_choose_me" }, - - { id: "testimonials", label: "testimonials" }, - - { id: "final_cta", label: "final_cta" }, - - { id: "footer", label: "footer" }, - - ]); - - - }, []); - - - - - 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, ''); - - setKanbanFilters(''); - - setFilterItems(newItems); - } - }; - - const handleSubmit = () => { - loadData(0, generateFilterRequests); - - setKanbanFilters(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, ''); - - setKanbanFilters(''); - - }; - - const onPageChange = (page: number) => { - loadData(page); - setCurrentPage(page); - }; - - - useEffect(() => { - if (!currentUser) return; - - loadColumns( - handleDeleteModalAction, - `page_sections`, - 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={page_sections ?? []} - 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?

    -
    - - - - {!showGrid && kanbanColumns && ( - - )} - - - - {showGrid && dataGrid} - - - {selectedRows.length > 0 && - createPortal( - onDeleteRows(selectedRows)} - />, - document.getElementById('delete-rows-button'), - )} - - - ) -} - -export default TableSamplePage_sections diff --git a/frontend/src/components/Page_sections/configurePage_sectionsCols.tsx b/frontend/src/components/Page_sections/configurePage_sectionsCols.tsx deleted file mode 100644 index ca24787..0000000 --- a/frontend/src/components/Page_sections/configurePage_sectionsCols.tsx +++ /dev/null @@ -1,278 +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_PAGE_SECTIONS') - - return [ - - { - field: 'page', - headerName: 'Page', - 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('pages'), - valueGetter: (params: GridValueGetterParams) => - params?.value?.id ?? params?.value, - - }, - - { - field: 'section_type', - headerName: 'SectionType', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'section_label', - headerName: 'SectionLabel', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'headline', - headerName: 'Headline', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'subheadline', - headerName: 'Subheadline', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'body', - headerName: 'Body', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'background_images', - headerName: 'BackgroundImages', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - editable: false, - sortable: false, - renderCell: (params: GridValueGetterParams) => ( - - ), - - }, - - { - field: 'primary_button_label', - headerName: 'PrimaryButtonLabel', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'primary_button_url', - headerName: 'PrimaryButtonURL', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'secondary_button_label', - headerName: 'SecondaryButtonLabel', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'secondary_button_url', - headerName: 'SecondaryButtonURL', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'sort_order', - headerName: 'SortOrder', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'number', - - }, - - { - field: 'is_visible', - headerName: 'IsVisible', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'boolean', - - }, - - { - field: 'actions', - type: 'actions', - minWidth: 30, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - getActions: (params: GridRowParams) => { - - return [ -
    - -
    , - ] - }, - }, - ]; -}; diff --git a/frontend/src/components/Pages/CardPages.tsx b/frontend/src/components/Pages/CardPages.tsx deleted file mode 100644 index 2d992b7..0000000 --- a/frontend/src/components/Pages/CardPages.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 = { - pages: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const CardPages = ({ - pages, - 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_PAGES') - - - return ( -
    - {loading && } -
      - {!loading && pages.map((item, index) => ( -
    • - -
      - - - {item.title} - - - -
      - -
      -
      -
      - - -
      -
      Title
      -
      -
      - { item.title } -
      -
      -
      - - - - -
      -
      Slug
      -
      -
      - { item.slug } -
      -
      -
      - - - - -
      -
      Status
      -
      -
      - { item.status } -
      -
      -
      - - - - -
      -
      SortOrder
      -
      -
      - { item.sort_order } -
      -
      -
      - - - - -
      -
      MetaTitle
      -
      -
      - { item.meta_title } -
      -
      -
      - - - - -
      -
      MetaDescription
      -
      -
      - { item.meta_description } -
      -
      -
      - - - - -
      -
      ShowInHeaderNav
      -
      -
      - { dataFormatter.booleanFormatter(item.show_in_header_nav) } -
      -
      -
      - - - - -
      -
      ShowInFooterNav
      -
      -
      - { dataFormatter.booleanFormatter(item.show_in_footer_nav) } -
      -
      -
      - - - - -
      -
      Author
      -
      -
      - { dataFormatter.usersOneListFormatter(item.author) } -
      -
      -
      - - - -
      -
    • - ))} - {!loading && pages.length === 0 && ( -
      -

      No data to display

      -
      - )} -
    -
    - -
    -
    - ); -}; - -export default CardPages; diff --git a/frontend/src/components/Pages/ListPages.tsx b/frontend/src/components/Pages/ListPages.tsx deleted file mode 100644 index 28b382a..0000000 --- a/frontend/src/components/Pages/ListPages.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 = { - pages: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const ListPages = ({ pages, loading, onDelete, currentPage, numPages, onPageChange }: Props) => { - - const currentUser = useAppSelector((state) => state.auth.currentUser); - const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_PAGES') - - const corners = useAppSelector((state) => state.style.corners); - const bgColor = useAppSelector((state) => state.style.cardsColor); - - - return ( - <> -
    - {loading && } - {!loading && pages.map((item) => ( -
    - -
    - - dark:divide-dark-700 overflow-x-auto' - } - > - - -
    -

    Title

    -

    { item.title }

    -
    - - - - -
    -

    Slug

    -

    { item.slug }

    -
    - - - - -
    -

    Status

    -

    { item.status }

    -
    - - - - -
    -

    SortOrder

    -

    { item.sort_order }

    -
    - - - - -
    -

    MetaTitle

    -

    { item.meta_title }

    -
    - - - - -
    -

    MetaDescription

    -

    { item.meta_description }

    -
    - - - - -
    -

    ShowInHeaderNav

    -

    { dataFormatter.booleanFormatter(item.show_in_header_nav) }

    -
    - - - - -
    -

    ShowInFooterNav

    -

    { dataFormatter.booleanFormatter(item.show_in_footer_nav) }

    -
    - - - - -
    -

    Author

    -

    { dataFormatter.usersOneListFormatter(item.author) }

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

    No data to display

    -
    - )} -
    -
    - -
    - - ) -}; - -export default ListPages \ No newline at end of file diff --git a/frontend/src/components/Pages/TablePages.tsx b/frontend/src/components/Pages/TablePages.tsx deleted file mode 100644 index af04290..0000000 --- a/frontend/src/components/Pages/TablePages.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/pages/pagesSlice' -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 "./configurePagesCols"; -import _ from 'lodash'; -import dataFormatter from '../../helpers/dataFormatter' -import {dataGridStyles} from "../../styles"; - - - -const perPage = 10 - -const TableSamplePages = ({ 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 { pages, loading, count, notify: pagesNotify, refetch } = useAppSelector((state) => state.pages) - 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 (pagesNotify.showNotification) { - notify(pagesNotify.typeNotification, pagesNotify.textNotification); - } - }, [pagesNotify.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, - `pages`, - 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={pages ?? []} - 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 TableSamplePages diff --git a/frontend/src/components/Pages/configurePagesCols.tsx b/frontend/src/components/Pages/configurePagesCols.tsx deleted file mode 100644 index a12a89c..0000000 --- a/frontend/src/components/Pages/configurePagesCols.tsx +++ /dev/null @@ -1,213 +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_PAGES') - - return [ - - { - field: 'title', - headerName: 'Title', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'slug', - headerName: 'Slug', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'status', - headerName: 'Status', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'sort_order', - headerName: 'SortOrder', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'number', - - }, - - { - field: 'meta_title', - headerName: 'MetaTitle', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'meta_description', - headerName: 'MetaDescription', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'show_in_header_nav', - headerName: 'ShowInHeaderNav', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'boolean', - - }, - - { - field: 'show_in_footer_nav', - headerName: 'ShowInFooterNav', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'boolean', - - }, - - { - field: 'author', - headerName: 'Author', - 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('users'), - valueGetter: (params: GridValueGetterParams) => - params?.value?.id ?? params?.value, - - }, - - { - field: 'actions', - type: 'actions', - minWidth: 30, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - getActions: (params: GridRowParams) => { - - return [ -
    - -
    , - ] - }, - }, - ]; -}; diff --git a/frontend/src/components/Pagination.tsx b/frontend/src/components/Pagination.tsx deleted file mode 100644 index bb6f7b3..0000000 --- a/frontend/src/components/Pagination.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import React from 'react'; -import { - mdiChevronDoubleLeft, - mdiChevronDoubleRight, - mdiChevronLeft, - mdiChevronRight, -} from '@mdi/js'; -import BaseIcon from './BaseIcon'; - -type Props = { - currentPage: number; - numPages: number; - setCurrentPage: any; -}; - -export const Pagination = ({ - currentPage, - numPages, - setCurrentPage, -}: Props) => { - return ( -
    - {currentPage === 0 && ( -
    - - -
    - )} - {currentPage !== 0 && ( -
    -
    setCurrentPage(0)}> - -
    -
    setCurrentPage(currentPage - 1)}> - -
    -
    - )} -

    - Page {currentPage + 1} of {numPages} -

    - {currentPage !== numPages - 1 && ( -
    -
    setCurrentPage(currentPage + 1)}> - -
    - -
    setCurrentPage(numPages - 1)}> - -
    -
    - )} - {currentPage === numPages - 1 && ( -
    - - -
    - )} -
    - ); -}; diff --git a/frontend/src/components/PasswordSetOrReset.tsx b/frontend/src/components/PasswordSetOrReset.tsx deleted file mode 100644 index 07749ba..0000000 --- a/frontend/src/components/PasswordSetOrReset.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import React from 'react'; -import {toast, ToastContainer} from 'react-toastify'; - -import Head from 'next/head'; -import CardBox from '../components/CardBox'; -import SectionFullScreen from '../components/SectionFullScreen'; -import {useRouter} from 'next/router'; -import {getPageTitle} from '../config'; - -import {Field, Form, Formik} from 'formik'; -import FormField from '../components/FormField'; -import BaseButtons from '../components/BaseButtons'; -import BaseButton from '../components/BaseButton'; -import { passwordReset } from '../stores/authSlice'; -import {useAppDispatch} from '../stores/hooks'; - -export default function PasswordSetOrReset() { - const [loading, setLoading] = React.useState(false); - const [isInvitation, setIsInvitation] = React.useState(false); - const router = useRouter(); - const {token, invitation} = router.query; - - const notify = (type, msg) => toast(msg, {type}); - - const dispatch = useAppDispatch(); - - React.useEffect(() => { - if (invitation) { - setIsInvitation(true); - } - }, [invitation]); - - const handleSubmit = async (value) => { - setLoading(true); - if (typeof token === 'string') { - await dispatch( - passwordReset({ - token, - password: value.password, - type: isInvitation && 'invitation', - }), - ); - await router.push('/login'); - } - - setLoading(false); - }; - - return ( - <> - - {isInvitation && {getPageTitle('Set Password')}} - {!isInvitation && {getPageTitle('Reset Password')}} - - - -
    - - {isInvitation &&

    Set Password

    } - {!isInvitation &&

    Reset Password

    } -

    Enter your new password

    - - handleSubmit(values)} - > - {({errors, touched}) => ( -
    - - - - - - - - - - -
    - )} -
    -
    -
    -
    - - - ); -} diff --git a/frontend/src/components/Permissions/CardPermissions.tsx b/frontend/src/components/Permissions/CardPermissions.tsx deleted file mode 100644 index 502de9e..0000000 --- a/frontend/src/components/Permissions/CardPermissions.tsx +++ /dev/null @@ -1,111 +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 = { - permissions: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const CardPermissions = ({ - permissions, - 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_PERMISSIONS') - - - return ( -
    - {loading && } -
      - {!loading && permissions.map((item, index) => ( -
    • - -
      - - - {item.name} - - - -
      - -
      -
      -
      - - -
      -
      Name
      -
      -
      - { item.name } -
      -
      -
      - - - -
      -
    • - ))} - {!loading && permissions.length === 0 && ( -
      -

      No data to display

      -
      - )} -
    -
    - -
    -
    - ); -}; - -export default CardPermissions; diff --git a/frontend/src/components/Permissions/ListPermissions.tsx b/frontend/src/components/Permissions/ListPermissions.tsx deleted file mode 100644 index b65ecce..0000000 --- a/frontend/src/components/Permissions/ListPermissions.tsx +++ /dev/null @@ -1,88 +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 = { - permissions: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const ListPermissions = ({ permissions, loading, onDelete, currentPage, numPages, onPageChange }: Props) => { - - const currentUser = useAppSelector((state) => state.auth.currentUser); - const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_PERMISSIONS') - - const corners = useAppSelector((state) => state.style.corners); - const bgColor = useAppSelector((state) => state.style.cardsColor); - - - return ( - <> -
    - {loading && } - {!loading && permissions.map((item) => ( -
    - -
    - - dark:divide-dark-700 overflow-x-auto' - } - > - - -
    -

    Name

    -

    { item.name }

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

    No data to display

    -
    - )} -
    -
    - -
    - - ) -}; - -export default ListPermissions \ No newline at end of file diff --git a/frontend/src/components/Permissions/TablePermissions.tsx b/frontend/src/components/Permissions/TablePermissions.tsx deleted file mode 100644 index 3bff9e6..0000000 --- a/frontend/src/components/Permissions/TablePermissions.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/permissions/permissionsSlice' -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 "./configurePermissionsCols"; -import _ from 'lodash'; -import dataFormatter from '../../helpers/dataFormatter' -import {dataGridStyles} from "../../styles"; - - - -const perPage = 10 - -const TableSamplePermissions = ({ 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 { permissions, loading, count, notify: permissionsNotify, refetch } = useAppSelector((state) => state.permissions) - 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 (permissionsNotify.showNotification) { - notify(permissionsNotify.typeNotification, permissionsNotify.textNotification); - } - }, [permissionsNotify.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, - `permissions`, - 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={permissions ?? []} - 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 TableSamplePermissions diff --git a/frontend/src/components/Permissions/configurePermissionsCols.tsx b/frontend/src/components/Permissions/configurePermissionsCols.tsx deleted file mode 100644 index b221e80..0000000 --- a/frontend/src/components/Permissions/configurePermissionsCols.tsx +++ /dev/null @@ -1,83 +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_PERMISSIONS') - - return [ - - { - field: 'name', - headerName: 'Name', - 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/Portfolio_items/CardPortfolio_items.tsx b/frontend/src/components/Portfolio_items/CardPortfolio_items.tsx deleted file mode 100644 index 2233f6d..0000000 --- a/frontend/src/components/Portfolio_items/CardPortfolio_items.tsx +++ /dev/null @@ -1,263 +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 = { - portfolio_items: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const CardPortfolio_items = ({ - portfolio_items, - 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_PORTFOLIO_ITEMS') - - - return ( -
    - {loading && } -
      - {!loading && portfolio_items.map((item, index) => ( -
    • - -
      - - - -

      {item.title}

      - - - -
      - -
      -
      -
      - - -
      -
      Title
      -
      -
      - { item.title } -
      -
      -
      - - - - -
      -
      WorkType
      -
      -
      - { item.work_type } -
      -
      -
      - - - - -
      -
      ClientName
      -
      -
      - { item.client_name } -
      -
      -
      - - - - -
      -
      Summary
      -
      -
      - { item.summary } -
      -
      -
      - - - - -
      -
      CaseStudy
      -
      -
      - { item.case_study } -
      -
      -
      - - - - -
      -
      Screenshots
      -
      -
      - -
      -
      -
      - - - - -
      -
      Attachments
      -
      -
      - {dataFormatter.filesFormatter(item.attachments).map(link => ( - - ))} -
      -
      -
      - - - - -
      -
      ExternalURL
      -
      -
      - { item.external_url } -
      -
      -
      - - - - -
      -
      TechStack
      -
      -
      - { item.tech_stack } -
      -
      -
      - - - - -
      -
      PublishedOn
      -
      -
      - { dataFormatter.dateTimeFormatter(item.published_on) } -
      -
      -
      - - - - -
      -
      IsFeatured
      -
      -
      - { dataFormatter.booleanFormatter(item.is_featured) } -
      -
      -
      - - - - -
      -
      IsPublic
      -
      -
      - { dataFormatter.booleanFormatter(item.is_public) } -
      -
      -
      - - - -
      -
    • - ))} - {!loading && portfolio_items.length === 0 && ( -
      -

      No data to display

      -
      - )} -
    -
    - -
    -
    - ); -}; - -export default CardPortfolio_items; diff --git a/frontend/src/components/Portfolio_items/ListPortfolio_items.tsx b/frontend/src/components/Portfolio_items/ListPortfolio_items.tsx deleted file mode 100644 index 5321b55..0000000 --- a/frontend/src/components/Portfolio_items/ListPortfolio_items.tsx +++ /dev/null @@ -1,194 +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 = { - portfolio_items: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const ListPortfolio_items = ({ portfolio_items, loading, onDelete, currentPage, numPages, onPageChange }: Props) => { - - const currentUser = useAppSelector((state) => state.auth.currentUser); - const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_PORTFOLIO_ITEMS') - - const corners = useAppSelector((state) => state.style.corners); - const bgColor = useAppSelector((state) => state.style.cardsColor); - - - return ( - <> -
    - {loading && } - {!loading && portfolio_items.map((item) => ( -
    - -
    - - - - dark:divide-dark-700 overflow-x-auto' - } - > - - -
    -

    Title

    -

    { item.title }

    -
    - - - - -
    -

    WorkType

    -

    { item.work_type }

    -
    - - - - -
    -

    ClientName

    -

    { item.client_name }

    -
    - - - - -
    -

    Summary

    -

    { item.summary }

    -
    - - - - -
    -

    CaseStudy

    -

    { item.case_study }

    -
    - - - - -
    -

    Screenshots

    - -
    - - - - -
    -

    Attachments

    - {dataFormatter.filesFormatter(item.attachments).map(link => ( - - ))} -
    - - - - -
    -

    ExternalURL

    -

    { item.external_url }

    -
    - - - - -
    -

    TechStack

    -

    { item.tech_stack }

    -
    - - - - -
    -

    PublishedOn

    -

    { dataFormatter.dateTimeFormatter(item.published_on) }

    -
    - - - - -
    -

    IsFeatured

    -

    { dataFormatter.booleanFormatter(item.is_featured) }

    -
    - - - - -
    -

    IsPublic

    -

    { dataFormatter.booleanFormatter(item.is_public) }

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

    No data to display

    -
    - )} -
    -
    - -
    - - ) -}; - -export default ListPortfolio_items \ No newline at end of file diff --git a/frontend/src/components/Portfolio_items/TablePortfolio_items.tsx b/frontend/src/components/Portfolio_items/TablePortfolio_items.tsx deleted file mode 100644 index 93b7e5f..0000000 --- a/frontend/src/components/Portfolio_items/TablePortfolio_items.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/portfolio_items/portfolio_itemsSlice' -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 "./configurePortfolio_itemsCols"; -import _ from 'lodash'; -import dataFormatter from '../../helpers/dataFormatter' -import {dataGridStyles} from "../../styles"; - - - -const perPage = 10 - -const TableSamplePortfolio_items = ({ 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 { portfolio_items, loading, count, notify: portfolio_itemsNotify, refetch } = useAppSelector((state) => state.portfolio_items) - 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 (portfolio_itemsNotify.showNotification) { - notify(portfolio_itemsNotify.typeNotification, portfolio_itemsNotify.textNotification); - } - }, [portfolio_itemsNotify.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, - `portfolio_items`, - 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={portfolio_items ?? []} - 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 TableSamplePortfolio_items diff --git a/frontend/src/components/Portfolio_items/configurePortfolio_itemsCols.tsx b/frontend/src/components/Portfolio_items/configurePortfolio_itemsCols.tsx deleted file mode 100644 index 8da2ef9..0000000 --- a/frontend/src/components/Portfolio_items/configurePortfolio_itemsCols.tsx +++ /dev/null @@ -1,270 +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_PORTFOLIO_ITEMS') - - return [ - - { - field: 'title', - headerName: 'Title', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'work_type', - headerName: 'WorkType', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'client_name', - headerName: 'ClientName', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'summary', - headerName: 'Summary', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'case_study', - headerName: 'CaseStudy', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'screenshots', - headerName: 'Screenshots', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - editable: false, - sortable: false, - renderCell: (params: GridValueGetterParams) => ( - - ), - - }, - - { - field: 'attachments', - headerName: 'Attachments', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - editable: false, - sortable: false, - renderCell: (params: GridValueGetterParams) => ( - <> - {dataFormatter.filesFormatter(params.row.attachments).map(link => ( - - ))} - - ), - - }, - - { - field: 'external_url', - headerName: 'ExternalURL', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'tech_stack', - headerName: 'TechStack', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'published_on', - headerName: 'PublishedOn', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'dateTime', - valueGetter: (params: GridValueGetterParams) => - new Date(params.row.published_on), - - }, - - { - field: 'is_featured', - headerName: 'IsFeatured', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'boolean', - - }, - - { - field: 'is_public', - headerName: 'IsPublic', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'boolean', - - }, - - { - field: 'actions', - type: 'actions', - minWidth: 30, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - getActions: (params: GridRowParams) => { - - return [ -
    - -
    , - ] - }, - }, - ]; -}; diff --git a/frontend/src/components/RichTextField.tsx b/frontend/src/components/RichTextField.tsx deleted file mode 100644 index 5900fa8..0000000 --- a/frontend/src/components/RichTextField.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import React, { useEffect, useId, useState } from 'react'; -import {Editor} from "@tinymce/tinymce-react"; -import { tinyKey } from '../config' -import {useAppSelector} from "../stores/hooks"; - -export const RichTextField = ({ options, field, form, itemRef, showField }) => { - const [value, setValue] = useState(null); - const darkMode = useAppSelector((state) => state.style.darkMode); - - - useEffect(() => { - if (field.value) { - setValue(field.value); - } - }, [field.value]); - - const handleChange = (value) => { - form.setFieldValue(field.name, value); - setValue(value); - }; - - return ( - - ); -}; diff --git a/frontend/src/components/Roles/CardRoles.tsx b/frontend/src/components/Roles/CardRoles.tsx deleted file mode 100644 index 5907300..0000000 --- a/frontend/src/components/Roles/CardRoles.tsx +++ /dev/null @@ -1,123 +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 = { - roles: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const CardRoles = ({ - roles, - 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_ROLES') - - - return ( -
    - {loading && } -
      - {!loading && roles.map((item, index) => ( -
    • - -
      - - - {item.name} - - - -
      - -
      -
      -
      - - -
      -
      Name
      -
      -
      - { item.name } -
      -
      -
      - - - - -
      -
      Permissions
      -
      -
      - { dataFormatter.permissionsManyListFormatter(item.permissions).join(', ')} -
      -
      -
      - - - -
      -
    • - ))} - {!loading && roles.length === 0 && ( -
      -

      No data to display

      -
      - )} -
    -
    - -
    -
    - ); -}; - -export default CardRoles; diff --git a/frontend/src/components/Roles/ListRoles.tsx b/frontend/src/components/Roles/ListRoles.tsx deleted file mode 100644 index a31c551..0000000 --- a/frontend/src/components/Roles/ListRoles.tsx +++ /dev/null @@ -1,96 +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 = { - roles: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const ListRoles = ({ roles, loading, onDelete, currentPage, numPages, onPageChange }: Props) => { - - const currentUser = useAppSelector((state) => state.auth.currentUser); - const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_ROLES') - - const corners = useAppSelector((state) => state.style.corners); - const bgColor = useAppSelector((state) => state.style.cardsColor); - - - return ( - <> -
    - {loading && } - {!loading && roles.map((item) => ( -
    - -
    - - dark:divide-dark-700 overflow-x-auto' - } - > - - -
    -

    Name

    -

    { item.name }

    -
    - - - - -
    -

    Permissions

    -

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

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

    No data to display

    -
    - )} -
    -
    - -
    - - ) -}; - -export default ListRoles \ No newline at end of file diff --git a/frontend/src/components/Roles/TableRoles.tsx b/frontend/src/components/Roles/TableRoles.tsx deleted file mode 100644 index 97a20d0..0000000 --- a/frontend/src/components/Roles/TableRoles.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/roles/rolesSlice' -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 "./configureRolesCols"; -import _ from 'lodash'; -import dataFormatter from '../../helpers/dataFormatter' -import {dataGridStyles} from "../../styles"; - - - -const perPage = 10 - -const TableSampleRoles = ({ 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 { roles, loading, count, notify: rolesNotify, refetch } = useAppSelector((state) => state.roles) - 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 (rolesNotify.showNotification) { - notify(rolesNotify.typeNotification, rolesNotify.textNotification); - } - }, [rolesNotify.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, - `roles`, - 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={roles ?? []} - 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 TableSampleRoles diff --git a/frontend/src/components/Roles/configureRolesCols.tsx b/frontend/src/components/Roles/configureRolesCols.tsx deleted file mode 100644 index 95d81ff..0000000 --- a/frontend/src/components/Roles/configureRolesCols.tsx +++ /dev/null @@ -1,103 +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_ROLES') - - return [ - - { - field: 'name', - headerName: 'Name', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'permissions', - headerName: '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/Search.tsx b/frontend/src/components/Search.tsx deleted file mode 100644 index 74590a9..0000000 --- a/frontend/src/components/Search.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import React from 'react'; -import { Field, Form, Formik } from 'formik'; -import { useRouter } from 'next/router'; -import { useAppSelector } from '../stores/hooks'; - -const Search = () => { - const router = useRouter(); - const focusRing = useAppSelector((state) => state.style.focusRingColor); - const corners = useAppSelector((state) => state.style.corners); - const cardsStyle = useAppSelector((state) => state.style.cardsStyle); - const validateSearch = (value) => { - let error; - if (!value) { - error = 'Required'; - } else if (value.length < 2) { - error = 'Minimum length: 2 characters'; - } - return error; - }; - return ( - { - router.push(`/search?query=${values.search}`); - resetForm(); - setSubmitting(false); - }} - validateOnBlur={false} - validateOnChange={false} - > - {({ errors, touched, values }) => ( -
    - - {errors.search && touched.search && values.search.length < 2 ? ( -
    {errors.search}
    - ) : null} - - )} -
    - ); -}; -export default Search; diff --git a/frontend/src/components/SearchResults.tsx b/frontend/src/components/SearchResults.tsx deleted file mode 100644 index 4a417ca..0000000 --- a/frontend/src/components/SearchResults.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import React from 'react'; -import CardBox from './CardBox'; -import { useRouter } from 'next/router'; -import { humanize } from '../helpers/humanize'; - -const SearchResults = ({ searchResults, searchQuery }) => { - const router = useRouter(); - - return ( - <> -

    Matches with: {searchQuery}

    - {Object.keys(searchResults).map((tableName) => ( - <> -

    {humanize(tableName)}

    - -
    - - - - {searchResults[tableName].length > 0 && - Object.keys(searchResults[tableName][0]).map((key) => { - if ( - key !== 'tableName' && - key !== 'id' && - key !== 'matchAttribute' - ) { - return ( - - ); - } - return null; - })} - - - - {searchResults[tableName].map((item, index) => ( - - {Object.keys(item).map((key) => { - if ( - key !== 'tableName' && - key !== 'id' && - key !== 'matchAttribute' - ) { - return ( - - ); - } - return null; - })} - - ))} - -
    - {humanize(key)} -
    - router.push( - `/${tableName}/${tableName}-view/?id=${item['id']}`, - ) - } - > - {item[key]} -
    -
    - {!Object.keys(searchResults).length && ( -
    No data
    - )} -
    - - ))} - {!Object.keys(searchResults).length && ( -
    No matches
    - )} - - ); -}; - -export default SearchResults; diff --git a/frontend/src/components/SelectField.tsx b/frontend/src/components/SelectField.tsx deleted file mode 100644 index cab0629..0000000 --- a/frontend/src/components/SelectField.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 SelectField = ({ options, field, form, itemRef, showField, disabled }) => { - - const [value, setValue] = useState(null) - const PAGE_SIZE = 100; - - useEffect(() => { - if(options?.id && field?.value?.id) { - setValue({value: field.value?.id, label: field.value[showField]}) - form.setFieldValue(field.name, field.value?.id); - } else if (!field.value) { - setValue(null); - } - }, [options?.id, field?.value?.id, field?.value]) - - const mapResponseToValuesAndLabels = (data) => ({ - value: data.id, - label: data.label, - }) - const handleChange = (option) => { - form.setFieldValue(field.name, option?.value || null) - 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} - isClearable - /> - ) -} - diff --git a/frontend/src/components/SelectFieldMany.tsx b/frontend/src/components/SelectFieldMany.tsx deleted file mode 100644 index 34268ff..0000000 --- a/frontend/src/components/SelectFieldMany.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import React, {useEffect, useId, useState} from 'react'; -import { AsyncPaginate } from 'react-select-async-paginate'; -import axios from 'axios'; - -export const SelectFieldMany = ({ options, field, form, itemRef, showField }) => { - const [value, setValue] = useState([]); - const PAGE_SIZE = 100; - - useEffect(() => { - if (field.value?.[0] && typeof field.value[0] !== 'string') { - form.setFieldValue( - field.name, - field.value.map((el) => el.id), - ); - } else if (!field.value || field.value.length === 0) { - setValue([]); - } - }, [field.name, field.value, form]); - - useEffect(() => { - if (options) { - setValue(options.map((el) => ({ value: el.id, label: el[showField] }))); - form.setFieldValue( - field.name, - options.map((el) => ({ value: el.id, label: el[showField] })), - ); - } - }, [options]); - - const mapResponseToValuesAndLabels = (data) => ({ - value: data.id, - label: data.label, - }); - - const handleChange = (data: any) => { - setValue(data) - form.setFieldValue( - field.name, - data.map(el => (el?.value || null)), - ); - }; - - 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} - isMulti - debounceTimeout={1000} - loadOptions={callApi} - onChange={handleChange} - defaultOptions - isClearable - /> - ); -}; diff --git a/frontend/src/components/Services/CardServices.tsx b/frontend/src/components/Services/CardServices.tsx deleted file mode 100644 index 59cd968..0000000 --- a/frontend/src/components/Services/CardServices.tsx +++ /dev/null @@ -1,219 +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 = { - services: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const CardServices = ({ - services, - 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_SERVICES') - - - return ( -
    - {loading && } -
      - {!loading && services.map((item, index) => ( -
    • - -
      - - - {item.name} - - - -
      - -
      -
      -
      - - -
      -
      ServiceName
      -
      -
      - { item.name } -
      -
      -
      - - - - -
      -
      ShortDescription
      -
      -
      - { item.short_description } -
      -
      -
      - - - - -
      -
      Details
      -
      -
      - { item.details } -
      -
      -
      - - - - -
      -
      Category
      -
      -
      - { item.category } -
      -
      -
      - - - - -
      -
      SortOrder
      -
      -
      - { item.sort_order } -
      -
      -
      - - - - -
      -
      IsFeatured
      -
      -
      - { dataFormatter.booleanFormatter(item.is_featured) } -
      -
      -
      - - - - -
      -
      IsActive
      -
      -
      - { dataFormatter.booleanFormatter(item.is_active) } -
      -
      -
      - - - - -
      -
      CTALabel
      -
      -
      - { item.cta_label } -
      -
      -
      - - - - -
      -
      CTAURL
      -
      -
      - { item.cta_url } -
      -
      -
      - - - - -
      -
      IconName
      -
      -
      - { item.icon_name } -
      -
      -
      - - - -
      -
    • - ))} - {!loading && services.length === 0 && ( -
      -

      No data to display

      -
      - )} -
    -
    - -
    -
    - ); -}; - -export default CardServices; diff --git a/frontend/src/components/Services/ListServices.tsx b/frontend/src/components/Services/ListServices.tsx deleted file mode 100644 index 74b8040..0000000 --- a/frontend/src/components/Services/ListServices.tsx +++ /dev/null @@ -1,160 +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 = { - services: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const ListServices = ({ services, loading, onDelete, currentPage, numPages, onPageChange }: Props) => { - - const currentUser = useAppSelector((state) => state.auth.currentUser); - const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_SERVICES') - - const corners = useAppSelector((state) => state.style.corners); - const bgColor = useAppSelector((state) => state.style.cardsColor); - - - return ( - <> -
    - {loading && } - {!loading && services.map((item) => ( -
    - -
    - - dark:divide-dark-700 overflow-x-auto' - } - > - - -
    -

    ServiceName

    -

    { item.name }

    -
    - - - - -
    -

    ShortDescription

    -

    { item.short_description }

    -
    - - - - -
    -

    Details

    -

    { item.details }

    -
    - - - - -
    -

    Category

    -

    { item.category }

    -
    - - - - -
    -

    SortOrder

    -

    { item.sort_order }

    -
    - - - - -
    -

    IsFeatured

    -

    { dataFormatter.booleanFormatter(item.is_featured) }

    -
    - - - - -
    -

    IsActive

    -

    { dataFormatter.booleanFormatter(item.is_active) }

    -
    - - - - -
    -

    CTALabel

    -

    { item.cta_label }

    -
    - - - - -
    -

    CTAURL

    -

    { item.cta_url }

    -
    - - - - -
    -

    IconName

    -

    { item.icon_name }

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

    No data to display

    -
    - )} -
    -
    - -
    - - ) -}; - -export default ListServices \ No newline at end of file diff --git a/frontend/src/components/Services/TableServices.tsx b/frontend/src/components/Services/TableServices.tsx deleted file mode 100644 index b72e6fe..0000000 --- a/frontend/src/components/Services/TableServices.tsx +++ /dev/null @@ -1,476 +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/services/servicesSlice' -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 "./configureServicesCols"; -import _ from 'lodash'; -import dataFormatter from '../../helpers/dataFormatter' -import {dataGridStyles} from "../../styles"; - - -import CardServices from './CardServices'; - - -const perPage = 10 - -const TableSampleServices = ({ 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 { services, loading, count, notify: servicesNotify, refetch } = useAppSelector((state) => state.services) - 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 (servicesNotify.showNotification) { - notify(servicesNotify.typeNotification, servicesNotify.textNotification); - } - }, [servicesNotify.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, - `services`, - 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={services ?? []} - 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?

    -
    - - - {services && Array.isArray(services) && !showGrid && ( - - )} - - - - {showGrid && dataGrid} - - - {selectedRows.length > 0 && - createPortal( - onDeleteRows(selectedRows)} - />, - document.getElementById('delete-rows-button'), - )} - - - ) -} - -export default TableSampleServices diff --git a/frontend/src/components/Services/configureServicesCols.tsx b/frontend/src/components/Services/configureServicesCols.tsx deleted file mode 100644 index ad382a6..0000000 --- a/frontend/src/components/Services/configureServicesCols.tsx +++ /dev/null @@ -1,221 +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_SERVICES') - - return [ - - { - field: 'name', - headerName: 'ServiceName', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'short_description', - headerName: 'ShortDescription', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'details', - headerName: 'Details', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'category', - headerName: 'Category', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'sort_order', - headerName: 'SortOrder', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'number', - - }, - - { - field: 'is_featured', - headerName: 'IsFeatured', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'boolean', - - }, - - { - field: 'is_active', - headerName: 'IsActive', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'boolean', - - }, - - { - field: 'cta_label', - headerName: 'CTALabel', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'cta_url', - headerName: 'CTAURL', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'icon_name', - headerName: 'IconName', - 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/Site_settings/CardSite_settings.tsx b/frontend/src/components/Site_settings/CardSite_settings.tsx deleted file mode 100644 index a84177f..0000000 --- a/frontend/src/components/Site_settings/CardSite_settings.tsx +++ /dev/null @@ -1,272 +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 = { - site_settings: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const CardSite_settings = ({ - site_settings, - 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_SITE_SETTINGS') - - - return ( -
    - {loading && } -
      - {!loading && site_settings.map((item, index) => ( -
    • - -
      - - - -

      {item.site_name}

      - - - -
      - -
      -
      -
      - - -
      -
      SiteName
      -
      -
      - { item.site_name } -
      -
      -
      - - - - -
      -
      Tagline
      -
      -
      - { item.tagline } -
      -
      -
      - - - - -
      -
      PrimaryDomain
      -
      -
      - { item.primary_domain } -
      -
      -
      - - - - -
      -
      PrimaryCTALabel
      -
      -
      - { item.primary_cta_label } -
      -
      -
      - - - - -
      -
      PrimaryCTAURL
      -
      -
      - { item.primary_cta_url } -
      -
      -
      - - - - -
      -
      ContactEmail
      -
      -
      - { item.contact_email } -
      -
      -
      - - - - -
      -
      ContactPhone
      -
      -
      - { item.contact_phone } -
      -
      -
      - - - - -
      -
      Location
      -
      -
      - { item.location } -
      -
      -
      - - - - -
      -
      AccentColorHex
      -
      -
      - { item.accent_color_hex } -
      -
      -
      - - - - -
      -
      SEOTitle
      -
      -
      - { item.seo_title } -
      -
      -
      - - - - -
      -
      SEODescription
      -
      -
      - { item.seo_description } -
      -
      -
      - - - - -
      -
      LogoImages
      -
      -
      - -
      -
      -
      - - - - -
      -
      FaviconImages
      -
      -
      - -
      -
      -
      - - - -
      -
    • - ))} - {!loading && site_settings.length === 0 && ( -
      -

      No data to display

      -
      - )} -
    -
    - -
    -
    - ); -}; - -export default CardSite_settings; diff --git a/frontend/src/components/Site_settings/ListSite_settings.tsx b/frontend/src/components/Site_settings/ListSite_settings.tsx deleted file mode 100644 index 8bff39a..0000000 --- a/frontend/src/components/Site_settings/ListSite_settings.tsx +++ /dev/null @@ -1,199 +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 = { - site_settings: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const ListSite_settings = ({ site_settings, loading, onDelete, currentPage, numPages, onPageChange }: Props) => { - - const currentUser = useAppSelector((state) => state.auth.currentUser); - const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_SITE_SETTINGS') - - const corners = useAppSelector((state) => state.style.corners); - const bgColor = useAppSelector((state) => state.style.cardsColor); - - - return ( - <> -
    - {loading && } - {!loading && site_settings.map((item) => ( -
    - -
    - - - - dark:divide-dark-700 overflow-x-auto' - } - > - - -
    -

    SiteName

    -

    { item.site_name }

    -
    - - - - -
    -

    Tagline

    -

    { item.tagline }

    -
    - - - - -
    -

    PrimaryDomain

    -

    { item.primary_domain }

    -
    - - - - -
    -

    PrimaryCTALabel

    -

    { item.primary_cta_label }

    -
    - - - - -
    -

    PrimaryCTAURL

    -

    { item.primary_cta_url }

    -
    - - - - -
    -

    ContactEmail

    -

    { item.contact_email }

    -
    - - - - -
    -

    ContactPhone

    -

    { item.contact_phone }

    -
    - - - - -
    -

    Location

    -

    { item.location }

    -
    - - - - -
    -

    AccentColorHex

    -

    { item.accent_color_hex }

    -
    - - - - -
    -

    SEOTitle

    -

    { item.seo_title }

    -
    - - - - -
    -

    SEODescription

    -

    { item.seo_description }

    -
    - - - - -
    -

    LogoImages

    - -
    - - - - -
    -

    FaviconImages

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

    No data to display

    -
    - )} -
    -
    - -
    - - ) -}; - -export default ListSite_settings \ No newline at end of file diff --git a/frontend/src/components/Site_settings/TableSite_settings.tsx b/frontend/src/components/Site_settings/TableSite_settings.tsx deleted file mode 100644 index 46a4322..0000000 --- a/frontend/src/components/Site_settings/TableSite_settings.tsx +++ /dev/null @@ -1,476 +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/site_settings/site_settingsSlice' -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 "./configureSite_settingsCols"; -import _ from 'lodash'; -import dataFormatter from '../../helpers/dataFormatter' -import {dataGridStyles} from "../../styles"; - - -import CardSite_settings from './CardSite_settings'; - - -const perPage = 10 - -const TableSampleSite_settings = ({ 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 { site_settings, loading, count, notify: site_settingsNotify, refetch } = useAppSelector((state) => state.site_settings) - 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 (site_settingsNotify.showNotification) { - notify(site_settingsNotify.typeNotification, site_settingsNotify.textNotification); - } - }, [site_settingsNotify.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, - `site_settings`, - 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={site_settings ?? []} - 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?

    -
    - - - {site_settings && Array.isArray(site_settings) && !showGrid && ( - - )} - - - - {showGrid && dataGrid} - - - {selectedRows.length > 0 && - createPortal( - onDeleteRows(selectedRows)} - />, - document.getElementById('delete-rows-button'), - )} - - - ) -} - -export default TableSampleSite_settings diff --git a/frontend/src/components/Site_settings/configureSite_settingsCols.tsx b/frontend/src/components/Site_settings/configureSite_settingsCols.tsx deleted file mode 100644 index 611846d..0000000 --- a/frontend/src/components/Site_settings/configureSite_settingsCols.tsx +++ /dev/null @@ -1,275 +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_SITE_SETTINGS') - - return [ - - { - field: 'site_name', - headerName: 'SiteName', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'tagline', - headerName: 'Tagline', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'primary_domain', - headerName: 'PrimaryDomain', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'primary_cta_label', - headerName: 'PrimaryCTALabel', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'primary_cta_url', - headerName: 'PrimaryCTAURL', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'contact_email', - headerName: 'ContactEmail', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'contact_phone', - headerName: 'ContactPhone', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'location', - headerName: 'Location', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'accent_color_hex', - headerName: 'AccentColorHex', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'seo_title', - headerName: 'SEOTitle', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'seo_description', - headerName: 'SEODescription', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'logo_images', - headerName: 'LogoImages', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - editable: false, - sortable: false, - renderCell: (params: GridValueGetterParams) => ( - - ), - - }, - - { - field: 'favicon_images', - headerName: 'FaviconImages', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - editable: false, - sortable: false, - renderCell: (params: GridValueGetterParams) => ( - - ), - - }, - - { - field: 'actions', - type: 'actions', - minWidth: 30, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - getActions: (params: GridRowParams) => { - - return [ -
    - -
    , - ] - }, - }, - ]; -}; diff --git a/frontend/src/components/Skills/CardSkills.tsx b/frontend/src/components/Skills/CardSkills.tsx deleted file mode 100644 index 6c5b266..0000000 --- a/frontend/src/components/Skills/CardSkills.tsx +++ /dev/null @@ -1,159 +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 = { - skills: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const CardSkills = ({ - skills, - 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_SKILLS') - - - return ( -
    - {loading && } -
      - {!loading && skills.map((item, index) => ( -
    • - -
      - - - {item.name} - - - -
      - -
      -
      -
      - - -
      -
      SkillName
      -
      -
      - { item.name } -
      -
      -
      - - - - -
      -
      Category
      -
      -
      - { item.category } -
      -
      -
      - - - - -
      -
      ProficiencyLevel
      -
      -
      - { item.proficiency_level } -
      -
      -
      - - - - -
      -
      SortOrder
      -
      -
      - { item.sort_order } -
      -
      -
      - - - - -
      -
      IsFeatured
      -
      -
      - { dataFormatter.booleanFormatter(item.is_featured) } -
      -
      -
      - - - -
      -
    • - ))} - {!loading && skills.length === 0 && ( -
      -

      No data to display

      -
      - )} -
    -
    - -
    -
    - ); -}; - -export default CardSkills; diff --git a/frontend/src/components/Skills/ListSkills.tsx b/frontend/src/components/Skills/ListSkills.tsx deleted file mode 100644 index 3bd1fef..0000000 --- a/frontend/src/components/Skills/ListSkills.tsx +++ /dev/null @@ -1,120 +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 = { - skills: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const ListSkills = ({ skills, loading, onDelete, currentPage, numPages, onPageChange }: Props) => { - - const currentUser = useAppSelector((state) => state.auth.currentUser); - const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_SKILLS') - - const corners = useAppSelector((state) => state.style.corners); - const bgColor = useAppSelector((state) => state.style.cardsColor); - - - return ( - <> -
    - {loading && } - {!loading && skills.map((item) => ( -
    - -
    - - dark:divide-dark-700 overflow-x-auto' - } - > - - -
    -

    SkillName

    -

    { item.name }

    -
    - - - - -
    -

    Category

    -

    { item.category }

    -
    - - - - -
    -

    ProficiencyLevel

    -

    { item.proficiency_level }

    -
    - - - - -
    -

    SortOrder

    -

    { item.sort_order }

    -
    - - - - -
    -

    IsFeatured

    -

    { dataFormatter.booleanFormatter(item.is_featured) }

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

    No data to display

    -
    - )} -
    -
    - -
    - - ) -}; - -export default ListSkills \ No newline at end of file diff --git a/frontend/src/components/Skills/TableSkills.tsx b/frontend/src/components/Skills/TableSkills.tsx deleted file mode 100644 index bbc2eaa..0000000 --- a/frontend/src/components/Skills/TableSkills.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/skills/skillsSlice' -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 "./configureSkillsCols"; -import _ from 'lodash'; -import dataFormatter from '../../helpers/dataFormatter' -import {dataGridStyles} from "../../styles"; - - - -const perPage = 10 - -const TableSampleSkills = ({ 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 { skills, loading, count, notify: skillsNotify, refetch } = useAppSelector((state) => state.skills) - 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 (skillsNotify.showNotification) { - notify(skillsNotify.typeNotification, skillsNotify.textNotification); - } - }, [skillsNotify.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, - `skills`, - 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={skills ?? []} - 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 TableSampleSkills diff --git a/frontend/src/components/Skills/configureSkillsCols.tsx b/frontend/src/components/Skills/configureSkillsCols.tsx deleted file mode 100644 index c6a41a5..0000000 --- a/frontend/src/components/Skills/configureSkillsCols.tsx +++ /dev/null @@ -1,146 +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_SKILLS') - - return [ - - { - field: 'name', - headerName: 'SkillName', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'category', - headerName: 'Category', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'proficiency_level', - headerName: 'ProficiencyLevel', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'number', - - }, - - { - field: 'sort_order', - headerName: 'SortOrder', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'number', - - }, - - { - field: 'is_featured', - headerName: 'IsFeatured', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'boolean', - - }, - - { - field: 'actions', - type: 'actions', - minWidth: 30, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - getActions: (params: GridRowParams) => { - - return [ -
    - -
    , - ] - }, - }, - ]; -}; diff --git a/frontend/src/components/SmartWidget/SmartWidget.tsx b/frontend/src/components/SmartWidget/SmartWidget.tsx deleted file mode 100644 index 6f6c0e0..0000000 --- a/frontend/src/components/SmartWidget/SmartWidget.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import React from 'react'; -import BaseButton from '../BaseButton'; -import BaseIcon from '../BaseIcon'; -import * as icons from '@mdi/js'; -import { useAppDispatch, useAppSelector } from '../../stores/hooks'; - -import { fetchWidgets, removeWidget } from '../../stores/roles/rolesSlice'; -import { WidgetChartType, WidgetType } from "./models/widget.model"; -import { BarChart } from "./components/BarChart"; -import { PieChart } from "./components/PieChart"; -import { AreaChart } from "./components/AreaChart"; -import { LineChart } from "./components/LineChart"; - -export const SmartWidget = ({ widget, userId, admin, roleId }) => { - const dispatch = useAppDispatch(); - const corners = useAppSelector((state) => state.style.corners); - const cardsStyle = useAppSelector((state) => state.style.cardsStyle); - - const deleteWidget = async () => { - await dispatch( - removeWidget({ id: userId, widgetId: widget.widget_id, roleId }), - ); - await dispatch(fetchWidgets(roleId)); - }; - - return ( -
    -
    -
    -
    - {widget.label} -
    - - {admin && ( - - )} -
    - -
    -
    - {widget.value ? ( - widget.widget_type === WidgetType.chart ? ( - widget.chart_type === WidgetChartType.bar ? ( - - ) : widget.chart_type === WidgetChartType.line ? ( - - ) : widget.chart_type === WidgetChartType.pie ? ( - - ) : widget.chart_type === WidgetChartType.area ? ( - - ) : widget.chart_type === WidgetChartType.funnel ? ( - - ) : null - ) : ( -
    - {widget.value} -
    - ) - ) : ( -
    - Something went wrong, please try again or use a different query. -
    - )} -
    - - {widget.type === WidgetType.scalar && widget.mdiIcon && ( -
    - -
    - )} -
    -
    -
    - ); -}; diff --git a/frontend/src/components/SmartWidget/components/AreaChart.tsx b/frontend/src/components/SmartWidget/components/AreaChart.tsx deleted file mode 100644 index 50bd5c7..0000000 --- a/frontend/src/components/SmartWidget/components/AreaChart.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import { WidgetLibName } from '../models/widget.model'; -import { ApexAreaChart } from './AreaChart/ApexAreaChart'; -import { ChartJSAreaChart } from './AreaChart/ChartJSAreaChart'; - -export const AreaChart = ({ widget }) => { - return ( - <> - {!widget.lib_name && } - {widget.lib_name === WidgetLibName.chartjs && ( - - )} - {widget.lib_name === WidgetLibName.apex && ( - - )} - - ); -}; diff --git a/frontend/src/components/SmartWidget/components/AreaChart/ApexAreaChart.tsx b/frontend/src/components/SmartWidget/components/AreaChart/ApexAreaChart.tsx deleted file mode 100644 index 656008a..0000000 --- a/frontend/src/components/SmartWidget/components/AreaChart/ApexAreaChart.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import React from 'react'; -import dynamic from 'next/dynamic'; -import { humanize } from '../../../../helpers/humanize'; - -const Chart = dynamic(() => import('react-apexcharts'), { ssr: false }); -type ValueType = { [key: string]: string | number }[]; - -export const ApexAreaChart = ({ widget }) => { - const dataForLineChart = (value: any[]) => { - if (!value?.length || value?.length > 10000) - return [{ name: '', data: [] }]; - - const valueKey = Object.keys(value[0])[1]; - const data = value.map((el) => +el[valueKey]); - - return [{ name: humanize(valueKey), data }]; - }; - - const optionsForLineChart = ( - value: ValueType, - chartColor: string[], - currency: boolean, - ) => { - const chartColors = Array.isArray(chartColor) - ? chartColor - : [chartColor || '#3751FF']; - const defaultOptions = { - xaxis: {}, - chart: { - toolbar: { - show: true, - offsetX: 0, - offsetY: 0, - tools: { - download: true, - selection: true, - zoom: true, - zoomin: true, - zoomout: true, - pan: true, - }, - export: { - csv: { - filename: undefined, - columnDelimiter: ',', - headerCategory: 'category', - headerValue: 'value', - }, - svg: { - filename: undefined, - }, - png: { - filename: undefined, - }, - }, - }, - }, - plotOptions: { - bar: { - distributed: false, - }, - }, - colors: [], - }; - - if (!value?.length || value?.length > 10000) return defaultOptions; - - const key = Object.keys(value[0])[0]; - const categories = value - .map((el) => el[key]) - .map((item) => - typeof item === 'string' && item?.length > 7 - ? item?.slice(0, 7) - : item || '', - ); - - if (categories.length <= 3) { - defaultOptions.plotOptions = { - bar: { - distributed: true, - }, - }; - } - - const colors = []; - for (let i = 0; i < categories.length; i++) { - colors.push(chartColors[i % chartColors.length]); - } - - return { - ...defaultOptions, - yaxis: { - labels: { - formatter: function (value) { - if (currency) { - return '$' + value; - } else { - return value; - } - }, - }, - }, - dataLabels: { - formatter: (val) => { - if (currency) { - return '$' + val; - } else { - return val; - } - }, - }, - legend: { - show: false, - }, - xaxis: { - categories, - }, - colors, - }; - }; - - return ( - - ); -}; diff --git a/frontend/src/components/SmartWidget/components/AreaChart/ChartJSAreaChart.tsx b/frontend/src/components/SmartWidget/components/AreaChart/ChartJSAreaChart.tsx deleted file mode 100644 index 5bb4cd2..0000000 --- a/frontend/src/components/SmartWidget/components/AreaChart/ChartJSAreaChart.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import React from 'react'; -import { Line } from 'react-chartjs-2'; -import chroma from 'chroma-js'; -import { humanize } from '../../../../helpers/humanize'; -import { collectOtherData, findFirstNumericKey } from '../../widgetHelpers'; -import { - Chart as ChartJS, - CategoryScale, - LinearScale, - PointElement, - LineElement, - Title, - Tooltip, - Filler, - Legend, - ChartData, -} from 'chart.js'; - -ChartJS.register( - CategoryScale, - LinearScale, - PointElement, - LineElement, - Title, - Tooltip, - Filler, - Legend, -); - -export const ChartJSAreaChart = ({ widget }) => { - const options = { - responsive: true, - maintainAspectRatio: false, - scales: { - y: { - display: true, - }, - x: { - display: true, - }, - }, - plugins: { - legend: { - display: true, - }, - }, - }; - - const dataForBarChart = ( - value: any[], - chartColors: string[], - ): ChartData<'line', number[], string> => { - if (!value?.length) return { labels: [''], datasets: [{ data: [] }] }; - const initColors = Array.isArray(chartColors) - ? chartColors - : [chartColors || '#3751FF']; - - const valueKey = findFirstNumericKey(value[0]); - const label = humanize(valueKey); - const data = value.map((el) => +el[valueKey]); - const labels = value.map((el) => - Object.keys(el).length <= 2 - ? humanize(String(el[Object.keys(el)[0]])) - : collectOtherData(el, valueKey), - ); - - const backgroundColor = - labels.length > initColors.length - ? chroma - .scale([ - chroma(initColors[0]).brighten(), - chroma(initColors.slice(-1)[0]).darken(), - ]) - .colors(labels.length) - : initColors; - - return { - labels, - datasets: [ - { - label, - data, - backgroundColor, - }, - ], - }; - }; - - return ( - - ); -}; diff --git a/frontend/src/components/SmartWidget/components/BarChart.tsx b/frontend/src/components/SmartWidget/components/BarChart.tsx deleted file mode 100644 index bf7a79b..0000000 --- a/frontend/src/components/SmartWidget/components/BarChart.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import { ChartJSBarChart } from './BarChart/ChartJSBarChart'; -import { ApexBarChart } from './BarChart/ApexBarChart'; -import { WidgetLibName } from '../models/widget.model'; - -export const BarChart = ({ widget }) => { - return ( - <> - {!widget.lib_name && } - {widget.lib_name === WidgetLibName.chartjs && ( - - )} - {widget.lib_name === WidgetLibName.apex && ( - - )} - - ); -}; diff --git a/frontend/src/components/SmartWidget/components/BarChart/ApexBarChart.tsx b/frontend/src/components/SmartWidget/components/BarChart/ApexBarChart.tsx deleted file mode 100644 index 5b3d3e7..0000000 --- a/frontend/src/components/SmartWidget/components/BarChart/ApexBarChart.tsx +++ /dev/null @@ -1,131 +0,0 @@ -import React from 'react'; -import dynamic from 'next/dynamic'; -import { humanize } from '../../../../helpers/humanize'; - -const Chart = dynamic(() => import('react-apexcharts'), { ssr: false }); -type ValueType = { [key: string]: string | number }[]; - -export const ApexBarChart = ({ widget }) => { - const dataForBarChart = (value: any[]) => { - if (!value?.length || value?.length > 10000) - return [{ name: '', data: [] }]; - - const valueKey = Object.keys(value[0])[1]; - const data = value.map((el) => +el[valueKey]); - - return [{ name: humanize(valueKey), data }]; - }; - const optionsForBarChart = ( - value: ValueType, - chartColor: string[], - currency: boolean, - ) => { - const chartColors = Array.isArray(chartColor) - ? chartColor - : [chartColor || '#3751FF']; - const defaultOptions = { - xaxis: {}, - chart: { - toolbar: { - show: true, - offsetX: 0, - offsetY: 0, - tools: { - download: true, - selection: true, - zoom: true, - }, - export: { - csv: { - filename: undefined, - columnDelimiter: ',', - headerCategory: 'category', - headerValue: 'value', - }, - svg: { - filename: undefined, - }, - png: { - filename: undefined, - }, - }, - }, - }, - plotOptions: { - bar: { - distributed: false, - }, - }, - colors: [], - }; - - if (!value?.length || value?.length > 10000) return defaultOptions; - - const key = Object.keys(value[0])[0]; - const categories = value - .map((el) => el[key]) - .map((item) => - typeof item === 'string' && item?.length > 20 - ? item?.slice(0, 15) - : item || '', - ); - - if (categories.length <= 3) { - defaultOptions.plotOptions = { - bar: { - distributed: true, - }, - }; - } - - const colors = []; - for (let i = 0; i < categories.length; i++) { - colors.push(chartColors[i % chartColors.length]); - } - - return { - ...defaultOptions, - yaxis: { - labels: { - formatter: function (value) { - if (currency) { - return '$' + value; - } else { - return value; - } - }, - }, - }, - dataLabels: { - formatter: (val) => { - if (currency) { - return '$' + val; - } else { - return val; - } - }, - }, - legend: { - show: true, - }, - xaxis: { - categories, - }, - colors, - }; - }; - - return ( - - ); -}; diff --git a/frontend/src/components/SmartWidget/components/BarChart/ChartJSBarChart.tsx b/frontend/src/components/SmartWidget/components/BarChart/ChartJSBarChart.tsx deleted file mode 100644 index d6b802c..0000000 --- a/frontend/src/components/SmartWidget/components/BarChart/ChartJSBarChart.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import React from 'react'; -import { humanize } from '../../../../helpers/humanize'; -import { Bar } from 'react-chartjs-2'; -import { collectOtherData, findFirstNumericKey } from '../../widgetHelpers'; -import { - BarElement, - CategoryScale, - Chart as ChartJS, - ChartData, - Legend, - LinearScale, - Title, - Tooltip, -} from 'chart.js'; -import chroma from 'chroma-js'; - -ChartJS.register( - CategoryScale, - LinearScale, - BarElement, - Title, - Tooltip, - Legend, -); - -export const ChartJSBarChart = ({ widget }) => { - console.log(widget) - const options = () => { - return { - responsive: true, - maintainAspectRatio: false, - plugins: { - legend: { - position: 'top' as const, - }, - title: { - display: true, - text: widget.label, - }, - }, - }; - }; - - const dataForBarChart = ( - value: any[], - chartColors: string[], - ): ChartData<'bar', number[], string> => { - if (!value?.length) return { labels: [''], datasets: [{ data: [] }] }; - - const initColors = Array.isArray(chartColors) - ? chartColors - : [chartColors || '#3751FF']; - - const valueKey = findFirstNumericKey(value[0]); - const label = humanize(valueKey); - const data = value.map((el) => +el[valueKey]); - const labels = value.map((el) => - Object.keys(el).length <= 2 - ? humanize(String(el[Object.keys(el)[0]])) - : collectOtherData(el, valueKey), - ); - - const backgroundColor = - labels.length > initColors.length - ? chroma - .scale([ - chroma(initColors[0]).brighten(), - chroma(initColors.slice(-1)[0]).darken(), - ]) - .colors(labels.length) - : initColors; - - return { - labels, - datasets: [ - { - label, - data, - backgroundColor, - }, - ], - }; - }; - - return ( - - ); -}; diff --git a/frontend/src/components/SmartWidget/components/FunnelChart.tsx b/frontend/src/components/SmartWidget/components/FunnelChart.tsx deleted file mode 100644 index 3d91280..0000000 --- a/frontend/src/components/SmartWidget/components/FunnelChart.tsx +++ /dev/null @@ -1,134 +0,0 @@ -import React from 'react'; -import dynamic from 'next/dynamic'; -import { humanize } from '../../../helpers/humanize'; - -const Chart = dynamic(() => import('react-apexcharts'), { ssr: false }); -type ValueType = { [key: string]: string | number }[]; - -export const FunnelChart = ({ widget }) => { - const dataForBarChart = (value: any[]) => { - if (!value?.length || value?.length > 10000) - return [{ name: '', data: [] }]; - const valueKey = Object.keys(value[0])[1]; - const data = value.map((el) => +el[valueKey]); - - return [{ name: humanize(valueKey), data }]; - }; - const optionsForBarChart = ( - value: ValueType, - chartColor: string[], - currency: boolean, - ) => { - const chartColors = Array.isArray(chartColor) - ? chartColor - : [chartColor || '#3751FF']; - const defaultOptions = { - xaxis: {}, - chart: { - toolbar: { - show: true, - offsetX: 0, - offsetY: 0, - tools: { - download: true, - selection: true, - zoom: true, - }, - export: { - csv: { - filename: undefined, - columnDelimiter: ',', - headerCategory: 'category', - headerValue: 'value', - }, - svg: { - filename: undefined, - }, - png: { - filename: undefined, - }, - }, - }, - }, - plotOptions: { - bar: { - distributed: false, - horizontal: true, - isFunnel: true, - }, - }, - colors: [], - }; - - if (!value?.length || value?.length > 10000) return defaultOptions; - - const key = Object.keys(value[0])[0]; - const categories = value - .map((el) => el[key]) - .map((item) => - typeof item === 'string' && item?.length > 20 - ? item?.slice(0, 15) - : item || '', - ); - - if (categories.length <= 3) { - defaultOptions.plotOptions = { - bar: { - distributed: true, - horizontal: true, - isFunnel: true, - }, - }; - } - - const colors = []; - for (let i = 0; i < categories.length; i++) { - colors.push(chartColors[i % chartColors.length]); - } - - return { - ...defaultOptions, - yaxis: { - labels: { - formatter: function (value) { - if (currency) { - return '$' + value; - } else { - return value; - } - }, - }, - }, - dataLabels: { - formatter: (val) => { - if (currency) { - return '$' + val; - } else { - return val; - } - }, - }, - legend: { - show: true, - }, - xaxis: { - categories, - }, - colors, - }; - }; - - return ( - - ); -}; diff --git a/frontend/src/components/SmartWidget/components/LineChart.tsx b/frontend/src/components/SmartWidget/components/LineChart.tsx deleted file mode 100644 index 3b9e7b0..0000000 --- a/frontend/src/components/SmartWidget/components/LineChart.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import { WidgetLibName } from '../models/widget.model'; -import { ApexLineChart } from './LineChart/ApexLineChart'; -import { ChartJSLineChart } from './LineChart/ChartJSLineChart'; - -export const LineChart = ({ widget }) => { - return ( - <> - {!widget.lib_name && } - {widget.lib_name === WidgetLibName.chartjs && ( - - )} - {widget.lib_name === WidgetLibName.apex && ( - - )} - - ); -}; diff --git a/frontend/src/components/SmartWidget/components/LineChart/ApexLineChart.tsx b/frontend/src/components/SmartWidget/components/LineChart/ApexLineChart.tsx deleted file mode 100644 index aa77a76..0000000 --- a/frontend/src/components/SmartWidget/components/LineChart/ApexLineChart.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import React from 'react'; -import dynamic from 'next/dynamic'; -import { humanize } from '../../../../helpers/humanize'; - -const Chart = dynamic(() => import('react-apexcharts'), { ssr: false }); -type ValueType = { [key: string]: string | number }[]; - -export const ApexLineChart = ({ widget }) => { - const dataForLineChart = (value: any[]) => { - if (!value?.length || value?.length > 10000) - return [{ name: '', data: [] }]; - - const valueKey = Object.keys(value[0])[1]; - const data = value.map((el) => +el[valueKey]); - - return [{ name: humanize(valueKey), data }]; - }; - - const optionsForLineChart = ( - value: ValueType, - chartColor: string[], - currency: boolean, - ) => { - const chartColors = Array.isArray(chartColor) - ? chartColor - : [chartColor || '#3751FF']; - const defaultOptions = { - xaxis: {}, - chart: { - toolbar: { - show: true, - offsetX: 0, - offsetY: 0, - tools: { - download: true, - selection: true, - zoom: true, - zoomin: true, - zoomout: true, - pan: true, - }, - export: { - csv: { - filename: undefined, - columnDelimiter: ',', - headerCategory: 'category', - headerValue: 'value', - }, - svg: { - filename: undefined, - }, - png: { - filename: undefined, - }, - }, - }, - }, - plotOptions: { - bar: { - distributed: false, - }, - }, - colors: [], - }; - - if (!value?.length || value?.length > 10000) return defaultOptions; - - const key = Object.keys(value[0])[0]; - const categories = value - .map((el) => el[key]) - .map((item) => - typeof item === 'string' && item?.length > 7 - ? item?.slice(0, 7) - : item || '', - ); - - if (categories.length <= 3) { - defaultOptions.plotOptions = { - bar: { - distributed: true, - }, - }; - } - - const colors = []; - for (let i = 0; i < categories.length; i++) { - colors.push(chartColors[i % chartColors.length]); - } - - return { - ...defaultOptions, - yaxis: { - labels: { - formatter: function (value) { - if (currency) { - return '$' + value; - } else { - return value; - } - }, - }, - }, - dataLabels: { - formatter: (val) => { - if (currency) { - return '$' + val; - } else { - return val; - } - }, - }, - legend: { - show: false, - }, - xaxis: { - categories, - }, - colors, - }; - }; - - return ( - - ); -}; diff --git a/frontend/src/components/SmartWidget/components/LineChart/ChartJSLineChart.tsx b/frontend/src/components/SmartWidget/components/LineChart/ChartJSLineChart.tsx deleted file mode 100644 index a2fe5ba..0000000 --- a/frontend/src/components/SmartWidget/components/LineChart/ChartJSLineChart.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import React from 'react'; -import { humanize } from '../../../../helpers/humanize'; -import { Line } from 'react-chartjs-2'; -import chroma from 'chroma-js'; -import { collectOtherData, findFirstNumericKey } from '../../widgetHelpers'; -import { Widget } from '../../models/widget.model'; -import { - Chart, - LineElement, - PointElement, - LineController, - LinearScale, - CategoryScale, - Tooltip, - ChartData, -} from 'chart.js'; - -Chart.register( - LineElement, - PointElement, - LineController, - LinearScale, - CategoryScale, - Tooltip, -); - -interface Props { - widget: Widget; -} - -export const ChartJSLineChart = (props: Props) => { - const options = { - responsive: true, - maintainAspectRatio: false, - scales: { - y: { - display: true, - }, - x: { - display: true, - }, - }, - plugins: { - legend: { - display: true, - }, - }, - }; - - const dataForBarChart = ( - value: any[], - chartColors: string[], - ): ChartData<'line', number[], string> => { - if (!value?.length) return { labels: [''], datasets: [{ data: [] }] }; - const initColors = Array.isArray(chartColors) - ? chartColors - : [chartColors || '#3751FF']; - - const valueKey = findFirstNumericKey(value[0]); - const label = humanize(valueKey); - const data = value.map((el) => +el[valueKey]); - const labels = value.map((el) => - Object.keys(el).length <= 2 - ? humanize(String(el[Object.keys(el)[0]])) - : collectOtherData(el, valueKey), - ); - - const backgroundColor = - labels.length > initColors.length - ? chroma - .scale([ - chroma(initColors[0]).brighten(), - chroma(initColors.slice(-1)[0]).darken(), - ]) - .colors(labels.length) - : initColors; - - return { - labels, - datasets: [ - { - label, - data, - backgroundColor, - }, - ], - }; - }; - - return ( - - ); -}; diff --git a/frontend/src/components/SmartWidget/components/PieChart.tsx b/frontend/src/components/SmartWidget/components/PieChart.tsx deleted file mode 100644 index f6f0fd3..0000000 --- a/frontend/src/components/SmartWidget/components/PieChart.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import { WidgetLibName } from '../models/widget.model'; -import { ApexPieChart } from './PieChart/ApexPieChart'; -import { ChartJSPieChart } from './PieChart/ChartJSPieChart'; - -export const PieChart = ({ widget }) => { - return ( - <> - {!widget.lib_name && } - {widget.lib_name === WidgetLibName.chartjs && ( - - )} - {widget.lib_name === WidgetLibName.apex && ( - - )} - - ); -}; diff --git a/frontend/src/components/SmartWidget/components/PieChart/ApexPieChart.tsx b/frontend/src/components/SmartWidget/components/PieChart/ApexPieChart.tsx deleted file mode 100644 index dfe5572..0000000 --- a/frontend/src/components/SmartWidget/components/PieChart/ApexPieChart.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import React from 'react'; -import dynamic from 'next/dynamic'; -import chroma from 'chroma-js'; - -const Chart = dynamic(() => import('react-apexcharts'), { ssr: false }); -type ValueType = { [key: string]: string | number }[]; - -export const ApexPieChart = ({ widget }) => { - const optionsForPieChart = (value: ValueType, chartColor: string) => { - const chartColors = Array.isArray(chartColor) - ? chartColor - : [chartColor || '#3751FF']; - const defaultOptions = { - xaxis: {}, - toolbar: { - show: true, - offsetX: 0, - offsetY: 0, - tools: { - download: true, - selection: true, - zoom: true, - zoomin: true, - zoomout: true, - pan: true, - customIcons: [], - }, - export: { - csv: { - filename: undefined, - columnDelimiter: ',', - headerCategory: 'category', - headerValue: 'value', - }, - svg: { - filename: undefined, - }, - png: { - filename: undefined, - }, - }, - autoSelected: 'zoom', - }, - colors: [], - }; - - if (!value?.length || value?.length > 10000) return defaultOptions; - - if ( - !isNaN(Number(value[0][Object.keys(value[0])[1]])) && - isFinite(Number(value[0][Object.keys(value[0])[1]])) - ) { - const labels = value - .map((el) => String(el[Object.keys(value[0])[0]])) - .reverse(); - - let colors: string[] | (string & any[]); - if (labels.length > chartColors.length) { - colors = chroma - .scale([ - chroma(chartColors.at(0)).brighten(), - chroma(chartColors.at(-1)).darken(), - ]) - .colors(labels.length); - } else { - colors = chartColors; - } - - return { - ...defaultOptions, - colors, - labels, - }; - } - const key = Object.keys(value[0])[1]; - const categories = value.map((el) => String(el[key])).reverse(); - - return { - ...defaultOptions, - labels: categories, - }; - }; - const dataForPieChart = (value: any[]) => { - if (!value?.length || value?.length > 10000) - return [{ name: '', data: [] }]; - - if ( - !isNaN(parseFloat(value[0][Object.keys(value[0])[1]])) && - isFinite(value[0][Object.keys(value[0])[1]]) - ) { - return value.map((el) => +el[Object.keys(value[0])[1]]).reverse(); - } - const valueKey = Object.keys(value[0])[0]; - return value.map((el) => +el[valueKey]).reverse(); - }; - - return ( - - ); -}; diff --git a/frontend/src/components/SmartWidget/components/PieChart/ChartJSPieChart.tsx b/frontend/src/components/SmartWidget/components/PieChart/ChartJSPieChart.tsx deleted file mode 100644 index 2a20155..0000000 --- a/frontend/src/components/SmartWidget/components/PieChart/ChartJSPieChart.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import React from 'react'; -import { humanize } from '../../../../helpers/humanize'; -import { Pie } from 'react-chartjs-2'; -import chroma from 'chroma-js'; -import { collectOtherData, findFirstNumericKey } from '../../widgetHelpers'; - -import { - Chart as ChartJS, - ArcElement, - Tooltip, - Legend, - ChartData, -} from 'chart.js'; - -ChartJS.register(ArcElement, Tooltip, Legend); - -export const ChartJSPieChart = ({ widget }) => { - const options = () => { - return { - responsive: true, - maintainAspectRatio: false, - plugins: { - legend: { - position: 'right' as const, - }, - title: { - display: true, - text: widget.label, - }, - }, - }; - }; - - const dataForBarChart = ( - value: any[], - chartColors: string[], - ): ChartData<'pie', number[], string> => { - if (!value?.length) return { labels: [''], datasets: [{ data: [] }] }; - const initColors = Array.isArray(chartColors) - ? chartColors - : [chartColors || '#3751FF']; - - const valueKey = findFirstNumericKey(value[0]); - const label = humanize(valueKey); - const data = value.map((el) => +el[valueKey]); - const labels = value.map((el) => - Object.keys(el).length <= 2 - ? humanize(String(el[Object.keys(el)[0]])) - : collectOtherData(el, valueKey), - ); - - const backgroundColor = - labels.length > initColors.length - ? chroma - .scale([ - chroma(initColors[0]).brighten(), - chroma(initColors.slice(-1)[0]).darken(), - ]) - .colors(labels.length) - : initColors; - - return { - labels, - datasets: [ - { - label, - data, - backgroundColor, - }, - ], - }; - }; - - return ( - - ); -}; diff --git a/frontend/src/components/SmartWidget/models/widget.model.ts b/frontend/src/components/SmartWidget/models/widget.model.ts deleted file mode 100644 index 362d65c..0000000 --- a/frontend/src/components/SmartWidget/models/widget.model.ts +++ /dev/null @@ -1,35 +0,0 @@ -export enum WidgetLibName { - apex = 'apex', - chartjs = 'chartjs', -} - -export enum WidgetChartType { - scalar = 'scalar', - bar = 'bar', - line = 'line', - pie = 'pie', - area = 'area', - funnel = 'funnel', -} - -export enum WidgetType { - chart = 'chart', - scalar = 'scalar', -} - -export interface Widget { - type: WidgetType; - chartType: WidgetChartType; - query: string; - mdiIcon: string; - iconColor: string; - label: string; - id: string; - lib?: WidgetLibName; - value: any[]; - chartColors: string[]; - options?: any; - prompt: string; - color: string; - color_array: string[]; -} diff --git a/frontend/src/components/SmartWidget/widgetHelpers.tsx b/frontend/src/components/SmartWidget/widgetHelpers.tsx deleted file mode 100644 index baf7969..0000000 --- a/frontend/src/components/SmartWidget/widgetHelpers.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { humanize } from '../../helpers/humanize'; - -interface DataObject { - [key: string]: any; -} - -export const findFirstNumericKey = (obj: Record): string | undefined => { - for (const [key, value] of Object.entries(obj)) { - if (typeof value === 'string') { - const trimmedValue = value.trim(); - - // Only allow numbers, and optionally a single decimal point - const isNumeric = /^-?\d+(\.\d+)?$/.test(trimmedValue); - - if (isNumeric) { - // Check if the number is the same as the trimmed value - // This is to avoid cases like '1.0' being treated as a number - const numberValue = parseFloat(trimmedValue); - if (numberValue.toString() === trimmedValue) { - return key; - } - } - } - } - return undefined; -}; - -export const collectOtherData = ( - obj: DataObject, - excludeKey: string, -): string => { - return Object.entries(obj) - .filter(([key, _]) => key !== excludeKey) - .map(([_, value]) => humanize(value)) - .join(' / '); -}; diff --git a/frontend/src/components/Social_links/CardSocial_links.tsx b/frontend/src/components/Social_links/CardSocial_links.tsx deleted file mode 100644 index 58009be..0000000 --- a/frontend/src/components/Social_links/CardSocial_links.tsx +++ /dev/null @@ -1,159 +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 = { - social_links: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const CardSocial_links = ({ - social_links, - 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_SOCIAL_LINKS') - - - return ( -
    - {loading && } -
      - {!loading && social_links.map((item, index) => ( -
    • - -
      - - - {item.label} - - - -
      - -
      -
      -
      - - -
      -
      Platform
      -
      -
      - { item.platform } -
      -
      -
      - - - - -
      -
      Label
      -
      -
      - { item.label } -
      -
      -
      - - - - -
      -
      URL
      -
      -
      - { item.url } -
      -
      -
      - - - - -
      -
      SortOrder
      -
      -
      - { item.sort_order } -
      -
      -
      - - - - -
      -
      IsActive
      -
      -
      - { dataFormatter.booleanFormatter(item.is_active) } -
      -
      -
      - - - -
      -
    • - ))} - {!loading && social_links.length === 0 && ( -
      -

      No data to display

      -
      - )} -
    -
    - -
    -
    - ); -}; - -export default CardSocial_links; diff --git a/frontend/src/components/Social_links/ListSocial_links.tsx b/frontend/src/components/Social_links/ListSocial_links.tsx deleted file mode 100644 index 9c594e0..0000000 --- a/frontend/src/components/Social_links/ListSocial_links.tsx +++ /dev/null @@ -1,120 +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 = { - social_links: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const ListSocial_links = ({ social_links, loading, onDelete, currentPage, numPages, onPageChange }: Props) => { - - const currentUser = useAppSelector((state) => state.auth.currentUser); - const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_SOCIAL_LINKS') - - const corners = useAppSelector((state) => state.style.corners); - const bgColor = useAppSelector((state) => state.style.cardsColor); - - - return ( - <> -
    - {loading && } - {!loading && social_links.map((item) => ( -
    - -
    - - dark:divide-dark-700 overflow-x-auto' - } - > - - -
    -

    Platform

    -

    { item.platform }

    -
    - - - - -
    -

    Label

    -

    { item.label }

    -
    - - - - -
    -

    URL

    -

    { item.url }

    -
    - - - - -
    -

    SortOrder

    -

    { item.sort_order }

    -
    - - - - -
    -

    IsActive

    -

    { dataFormatter.booleanFormatter(item.is_active) }

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

    No data to display

    -
    - )} -
    -
    - -
    - - ) -}; - -export default ListSocial_links \ No newline at end of file diff --git a/frontend/src/components/Social_links/TableSocial_links.tsx b/frontend/src/components/Social_links/TableSocial_links.tsx deleted file mode 100644 index 345cd90..0000000 --- a/frontend/src/components/Social_links/TableSocial_links.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/social_links/social_linksSlice' -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 "./configureSocial_linksCols"; -import _ from 'lodash'; -import dataFormatter from '../../helpers/dataFormatter' -import {dataGridStyles} from "../../styles"; - - - -const perPage = 10 - -const TableSampleSocial_links = ({ 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 { social_links, loading, count, notify: social_linksNotify, refetch } = useAppSelector((state) => state.social_links) - 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 (social_linksNotify.showNotification) { - notify(social_linksNotify.typeNotification, social_linksNotify.textNotification); - } - }, [social_linksNotify.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, - `social_links`, - 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={social_links ?? []} - 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 TableSampleSocial_links diff --git a/frontend/src/components/Social_links/configureSocial_linksCols.tsx b/frontend/src/components/Social_links/configureSocial_linksCols.tsx deleted file mode 100644 index 75848b2..0000000 --- a/frontend/src/components/Social_links/configureSocial_linksCols.tsx +++ /dev/null @@ -1,145 +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_SOCIAL_LINKS') - - return [ - - { - field: 'platform', - headerName: 'Platform', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'label', - headerName: 'Label', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'url', - headerName: 'URL', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'sort_order', - headerName: 'SortOrder', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'number', - - }, - - { - field: 'is_active', - headerName: 'IsActive', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'boolean', - - }, - - { - field: 'actions', - type: 'actions', - minWidth: 30, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - getActions: (params: GridRowParams) => { - - return [ -
    - -
    , - ] - }, - }, - ]; -}; diff --git a/frontend/src/components/SwitchField.tsx b/frontend/src/components/SwitchField.tsx deleted file mode 100644 index e2186ea..0000000 --- a/frontend/src/components/SwitchField.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React, { useEffect, useId, useState } from 'react'; -import Switch from "react-switch"; - -import resolveConfig from 'tailwindcss/resolveConfig' -import tailwindConfig from '../../tailwind.config.js'; -const fullConfig = resolveConfig(tailwindConfig as any); - - - -export const SwitchField = ({ - field, - form, - disabled - }) => { - const handleChange = (data: any) => { - form.setFieldValue( - field.name, - data, - ); - }; - - -const buttonColor = fullConfig.theme.accentColor.midnightBlueTheme?.buttonColor; -const cardColor = fullConfig.theme.accentColor.midnightBlueTheme?.cardColor; - - return ( - - ); -}; diff --git a/frontend/src/components/TableSampleClients.tsx b/frontend/src/components/TableSampleClients.tsx deleted file mode 100644 index 3fb3411..0000000 --- a/frontend/src/components/TableSampleClients.tsx +++ /dev/null @@ -1,141 +0,0 @@ -import { mdiEye, mdiTrashCan } from '@mdi/js' -import React, { useState } from 'react' -import { useSampleClients } from '../hooks/sampleData' -import { Client } from '../interfaces' -import BaseButton from './BaseButton' -import BaseButtons from './BaseButtons' -import CardBoxModal from './CardBoxModal' -import UserAvatar from './UserAvatar' - -const TableSampleClients = () => { - const { clients } = useSampleClients() - - const perPage = 5 - - const [currentPage, setCurrentPage] = useState(0) - - const clientsPaginated = clients.slice(perPage * currentPage, perPage * (currentPage + 1)) - - const numPages = clients.length / perPage - - const pagesList = [] - - for (let i = 0; i < numPages; i++) { - pagesList.push(i) - } - - const [isModalInfoActive, setIsModalInfoActive] = useState(false) - const [isModalTrashActive, setIsModalTrashActive] = useState(false) - - const handleModalAction = () => { - setIsModalInfoActive(false) - setIsModalTrashActive(false) - } - - return ( - <> - -

    - Lorem ipsum dolor sit amet adipiscing elit -

    -

    This is sample modal

    -
    - - -

    - Lorem ipsum dolor sit amet adipiscing elit -

    -

    This is sample modal

    -
    - - - - - - - - - - - - - {clientsPaginated.map((client: Client) => ( - - - - - - - - - - ))} - -
    - NameCompanyCityProgressCreated -
    - - {client.name}{client.company}{client.city} - - {client.progress} - - - {client.created} - - - setIsModalInfoActive(true)} - small - /> - setIsModalTrashActive(true)} - small - /> - -
    -
    -
    - - {pagesList.map((page) => ( - setCurrentPage(page)} - /> - ))} - - - Page {currentPage + 1} of {numPages} - -
    -
    - - ) -} - -export default TableSampleClients diff --git a/frontend/src/components/Testimonials/CardTestimonials.tsx b/frontend/src/components/Testimonials/CardTestimonials.tsx deleted file mode 100644 index 8b0ac50..0000000 --- a/frontend/src/components/Testimonials/CardTestimonials.tsx +++ /dev/null @@ -1,244 +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 = { - testimonials: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const CardTestimonials = ({ - testimonials, - 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_TESTIMONIALS') - - - return ( -
    - {loading && } -
      - {!loading && testimonials.map((item, index) => ( -
    • - -
      - - - -

      {item.client_name}

      - - - -
      - -
      -
      -
      - - -
      -
      ClientName
      -
      -
      - { item.client_name } -
      -
      -
      - - - - -
      -
      ClientTitle
      -
      -
      - { item.client_title } -
      -
      -
      - - - - -
      -
      CompanyName
      -
      -
      - { item.company_name } -
      -
      -
      - - - - -
      -
      Quote
      -
      -
      - { item.quote } -
      -
      -
      - - - - -
      -
      Rating
      -
      -
      - { item.rating } -
      -
      -
      - - - - -
      -
      ClientAvatars
      -
      -
      - -
      -
      -
      - - - - -
      -
      Source
      -
      -
      - { item.source } -
      -
      -
      - - - - -
      -
      SourceURL
      -
      -
      - { item.source_url } -
      -
      -
      - - - - -
      -
      TestimonialDate
      -
      -
      - { dataFormatter.dateTimeFormatter(item.testimonial_date) } -
      -
      -
      - - - - -
      -
      IsFeatured
      -
      -
      - { dataFormatter.booleanFormatter(item.is_featured) } -
      -
      -
      - - - - -
      -
      IsPublic
      -
      -
      - { dataFormatter.booleanFormatter(item.is_public) } -
      -
      -
      - - - -
      -
    • - ))} - {!loading && testimonials.length === 0 && ( -
      -

      No data to display

      -
      - )} -
    -
    - -
    -
    - ); -}; - -export default CardTestimonials; diff --git a/frontend/src/components/Testimonials/ListTestimonials.tsx b/frontend/src/components/Testimonials/ListTestimonials.tsx deleted file mode 100644 index 31fdef0..0000000 --- a/frontend/src/components/Testimonials/ListTestimonials.tsx +++ /dev/null @@ -1,179 +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 = { - testimonials: any[]; - loading: boolean; - onDelete: (id: string) => void; - currentPage: number; - numPages: number; - onPageChange: (page: number) => void; -}; - -const ListTestimonials = ({ testimonials, loading, onDelete, currentPage, numPages, onPageChange }: Props) => { - - const currentUser = useAppSelector((state) => state.auth.currentUser); - const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_TESTIMONIALS') - - const corners = useAppSelector((state) => state.style.corners); - const bgColor = useAppSelector((state) => state.style.cardsColor); - - - return ( - <> -
    - {loading && } - {!loading && testimonials.map((item) => ( -
    - -
    - - - - dark:divide-dark-700 overflow-x-auto' - } - > - - -
    -

    ClientName

    -

    { item.client_name }

    -
    - - - - -
    -

    ClientTitle

    -

    { item.client_title }

    -
    - - - - -
    -

    CompanyName

    -

    { item.company_name }

    -
    - - - - -
    -

    Quote

    -

    { item.quote }

    -
    - - - - -
    -

    Rating

    -

    { item.rating }

    -
    - - - - -
    -

    ClientAvatars

    - -
    - - - - -
    -

    Source

    -

    { item.source }

    -
    - - - - -
    -

    SourceURL

    -

    { item.source_url }

    -
    - - - - -
    -

    TestimonialDate

    -

    { dataFormatter.dateTimeFormatter(item.testimonial_date) }

    -
    - - - - -
    -

    IsFeatured

    -

    { dataFormatter.booleanFormatter(item.is_featured) }

    -
    - - - - -
    -

    IsPublic

    -

    { dataFormatter.booleanFormatter(item.is_public) }

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

    No data to display

    -
    - )} -
    -
    - -
    - - ) -}; - -export default ListTestimonials \ No newline at end of file diff --git a/frontend/src/components/Testimonials/TableTestimonials.tsx b/frontend/src/components/Testimonials/TableTestimonials.tsx deleted file mode 100644 index b64b83b..0000000 --- a/frontend/src/components/Testimonials/TableTestimonials.tsx +++ /dev/null @@ -1,476 +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/testimonials/testimonialsSlice' -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 "./configureTestimonialsCols"; -import _ from 'lodash'; -import dataFormatter from '../../helpers/dataFormatter' -import {dataGridStyles} from "../../styles"; - - -import CardTestimonials from './CardTestimonials'; - - -const perPage = 10 - -const TableSampleTestimonials = ({ 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 { testimonials, loading, count, notify: testimonialsNotify, refetch } = useAppSelector((state) => state.testimonials) - 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 (testimonialsNotify.showNotification) { - notify(testimonialsNotify.typeNotification, testimonialsNotify.textNotification); - } - }, [testimonialsNotify.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, - `testimonials`, - 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={testimonials ?? []} - 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?

    -
    - - - {testimonials && Array.isArray(testimonials) && !showGrid && ( - - )} - - - - {showGrid && dataGrid} - - - {selectedRows.length > 0 && - createPortal( - onDeleteRows(selectedRows)} - />, - document.getElementById('delete-rows-button'), - )} - - - ) -} - -export default TableSampleTestimonials diff --git a/frontend/src/components/Testimonials/configureTestimonialsCols.tsx b/frontend/src/components/Testimonials/configureTestimonialsCols.tsx deleted file mode 100644 index f704c27..0000000 --- a/frontend/src/components/Testimonials/configureTestimonialsCols.tsx +++ /dev/null @@ -1,245 +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_TESTIMONIALS') - - return [ - - { - field: 'client_name', - headerName: 'ClientName', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'client_title', - headerName: 'ClientTitle', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'company_name', - headerName: 'CompanyName', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'quote', - headerName: 'Quote', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'rating', - headerName: 'Rating', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'number', - - }, - - { - field: 'client_avatars', - headerName: 'ClientAvatars', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - editable: false, - sortable: false, - renderCell: (params: GridValueGetterParams) => ( - - ), - - }, - - { - field: 'source', - headerName: 'Source', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'source_url', - headerName: 'SourceURL', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, - - { - field: 'testimonial_date', - headerName: 'TestimonialDate', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'dateTime', - valueGetter: (params: GridValueGetterParams) => - new Date(params.row.testimonial_date), - - }, - - { - field: 'is_featured', - headerName: 'IsFeatured', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'boolean', - - }, - - { - field: 'is_public', - headerName: 'IsPublic', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'boolean', - - }, - - { - field: 'actions', - type: 'actions', - minWidth: 30, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - getActions: (params: GridRowParams) => { - - return [ -
    - -
    , - ] - }, - }, - ]; -}; 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 ef8396d..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 62dae69..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 5de5cd9..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 index a9783c8..f83f68d 100644 --- a/frontend/src/config.ts +++ b/frontend/src/config.ts @@ -1,15 +1,9 @@ -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 appTitle = 'Blackness Studio' export const getPageTitle = (currentPageTitle: string) => `${currentPageTitle} — ${appTitle}` - -export const tinyKey = process.env.NEXT_PUBLIC_TINY_KEY || '' diff --git a/frontend/src/css/main.css b/frontend/src/css/main.css index a2d6067..d17ae3a 100644 --- a/frontend/src/css/main.css +++ b/frontend/src/css/main.css @@ -14,6 +14,9 @@ @import url('https://fonts.googleapis.com/css2?family=Ubuntu:wght@300;400;500;700&display=swap'); +html { + scroll-behavior: smooth; +} body { @apply font-sans text-primaryText !important; @@ -61,4 +64,4 @@ body { } .introjs-prevbutton{ @apply bg-transparent border border-midnightBlueTheme-buttonColor text-midnightBlueTheme-buttonColor !important; -} +} \ 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/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/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/menuAside.ts b/frontend/src/menuAside.ts index f1c4ab8..84a836f 100644 --- a/frontend/src/menuAside.ts +++ b/frontend/src/menuAside.ts @@ -1,131 +1,3 @@ -import * as icon from '@mdi/js'; -import { MenuAsideItem } from './interfaces' +const menuAside: any[] = [] -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: '/site_settings/site_settings-list', - label: 'Site settings', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiCog' in icon ? icon['mdiCog' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_SITE_SETTINGS' - }, - { - href: '/pages/pages-list', - label: 'Pages', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiFileDocumentOutline' in icon ? icon['mdiFileDocumentOutline' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_PAGES' - }, - { - href: '/page_sections/page_sections-list', - label: 'Page sections', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiViewSequentialOutline' in icon ? icon['mdiViewSequentialOutline' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_PAGE_SECTIONS' - }, - { - href: '/services/services-list', - label: 'Services', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiBriefcaseOutline' in icon ? icon['mdiBriefcaseOutline' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_SERVICES' - }, - { - href: '/portfolio_items/portfolio_items-list', - label: 'Portfolio items', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiFolderMultipleOutline' in icon ? icon['mdiFolderMultipleOutline' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_PORTFOLIO_ITEMS' - }, - { - href: '/testimonials/testimonials-list', - label: 'Testimonials', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiCommentQuoteOutline' in icon ? icon['mdiCommentQuoteOutline' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_TESTIMONIALS' - }, - { - href: '/skills/skills-list', - label: 'Skills', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiStarOutline' in icon ? icon['mdiStarOutline' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_SKILLS' - }, - { - href: '/benefits/benefits-list', - label: 'Benefits', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiShieldCheckOutline' in icon ? icon['mdiShieldCheckOutline' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_BENEFITS' - }, - { - href: '/social_links/social_links-list', - label: 'Social links', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiLinkVariant' in icon ? icon['mdiLinkVariant' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_SOCIAL_LINKS' - }, - { - href: '/inquiries/inquiries-list', - label: 'Inquiries', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiEmailOutline' in icon ? icon['mdiEmailOutline' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_INQUIRIES' - }, - { - 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 +export default menuAside \ No newline at end of file diff --git a/frontend/src/menuNavBar.ts b/frontend/src/menuNavBar.ts index a5dd956..c727518 100644 --- a/frontend/src/menuNavBar.ts +++ b/frontend/src/menuNavBar.ts @@ -1,53 +1,5 @@ -import { - mdiMenu, - mdiClockOutline, - mdiCloud, - mdiCrop, - mdiAccount, - mdiCogOutline, - mdiEmail, - mdiLogout, - mdiThemeLightDark, - mdiGithub, - mdiVuejs, -} from '@mdi/js' -import { MenuNavBarItem } from './interfaces' +const menuNavBar: any[] = [] -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: any[] = [] -export const webPagesNavBar = [ - -]; - -export default menuNavBar +export default menuNavBar \ No newline at end of file diff --git a/frontend/src/pages/_app.tsx b/frontend/src/pages/_app.tsx index 0994d3a..80bb8a5 100644 --- a/frontend/src/pages/_app.tsx +++ b/frontend/src/pages/_app.tsx @@ -6,23 +6,10 @@ 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 @@ -33,121 +20,7 @@ type AppPropsWithLayout = AppProps & { } 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 = 'Blackness Studio Website' const description = "Premium minimalist website to showcase Blackness Studio writing services and drive clients to Fiverr." @@ -185,17 +58,11 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) { - - {(process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'dev_stage') && } + {(process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'dev_stage') && } )} ) } -export default appWithTranslation(MyApp); +export default appWithTranslation(MyApp); \ No newline at end of file diff --git a/frontend/src/pages/benefits/[benefitsId].tsx b/frontend/src/pages/benefits/[benefitsId].tsx deleted file mode 100644 index 9a8796c..0000000 --- a/frontend/src/pages/benefits/[benefitsId].tsx +++ /dev/null @@ -1,442 +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/benefits/benefitsSlice' -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 EditBenefits = () => { - const router = useRouter() - const dispatch = useAppDispatch() - const initVals = { - - - 'title': '', - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - description: '', - - - - - - - - - - - - - - - - - - - - - - - - - - 'icon_name': '', - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - sort_order: '', - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - is_active: false, - - - - - - - - - - - - - - - - } - const [initialValues, setInitialValues] = useState(initVals) - - const { benefits } = useAppSelector((state) => state.benefits) - - - const { benefitsId } = router.query - - useEffect(() => { - dispatch(fetch({ id: benefitsId })) - }, [benefitsId]) - - useEffect(() => { - if (typeof benefits === 'object') { - setInitialValues(benefits) - } - }, [benefits]) - - useEffect(() => { - if (typeof benefits === 'object') { - - const newInitialVal = {...initVals}; - - Object.keys(initVals).forEach(el => newInitialVal[el] = (benefits)[el]) - - setInitialValues(newInitialVal); - } - }, [benefits]) - - const handleSubmit = async (data) => { - await dispatch(update({ id: benefitsId, data })) - await router.push('/benefits/benefits-list') - } - - return ( - <> - - {getPageTitle('Edit benefits')} - - - - {''} - - - handleSubmit(values)} - > -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - router.push('/benefits/benefits-list')}/> - - - - - - - ) -} - -EditBenefits.getLayout = function getLayout(page: ReactElement) { - return ( - - {page} - - ) -} - -export default EditBenefits diff --git a/frontend/src/pages/benefits/benefits-edit.tsx b/frontend/src/pages/benefits/benefits-edit.tsx deleted file mode 100644 index e3ca466..0000000 --- a/frontend/src/pages/benefits/benefits-edit.tsx +++ /dev/null @@ -1,439 +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/benefits/benefitsSlice' -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 EditBenefitsPage = () => { - const router = useRouter() - const dispatch = useAppDispatch() - const initVals = { - - - 'title': '', - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - description: '', - - - - - - - - - - - - - - - - - - - - - - - - - - 'icon_name': '', - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - sort_order: '', - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - is_active: false, - - - - - - - - - - - - - - - - } - const [initialValues, setInitialValues] = useState(initVals) - - const { benefits } = useAppSelector((state) => state.benefits) - - - const { id } = router.query - - useEffect(() => { - dispatch(fetch({ id: id })) - }, [id]) - - useEffect(() => { - if (typeof benefits === 'object') { - setInitialValues(benefits) - } - }, [benefits]) - - useEffect(() => { - if (typeof benefits === 'object') { - const newInitialVal = {...initVals}; - Object.keys(initVals).forEach(el => newInitialVal[el] = (benefits)[el]) - setInitialValues(newInitialVal); - } - }, [benefits]) - - const handleSubmit = async (data) => { - await dispatch(update({ id: id, data })) - await router.push('/benefits/benefits-list') - } - - return ( - <> - - {getPageTitle('Edit benefits')} - - - - {''} - - - handleSubmit(values)} - > -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - router.push('/benefits/benefits-list')}/> - - -
    -
    -
    - - ) -} - -EditBenefitsPage.getLayout = function getLayout(page: ReactElement) { - return ( - - {page} - - ) -} - -export default EditBenefitsPage diff --git a/frontend/src/pages/benefits/benefits-list.tsx b/frontend/src/pages/benefits/benefits-list.tsx deleted file mode 100644 index 251a77c..0000000 --- a/frontend/src/pages/benefits/benefits-list.tsx +++ /dev/null @@ -1,166 +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 TableBenefits from '../../components/Benefits/TableBenefits' -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/benefits/benefitsSlice'; - - -import {hasPermission} from "../../helpers/userPermissions"; - - - -const BenefitsTablesPage = () => { - 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: 'Title', title: 'title'},{label: 'Description', title: 'description'},{label: 'IconName', title: 'icon_name'}, - {label: 'SortOrder', title: 'sort_order', number: 'true'}, - - - - - - ]); - - const hasCreatePermission = currentUser && hasPermission(currentUser, 'CREATE_BENEFITS'); - - - const addFilter = () => { - const newItem = { - id: uniqueId(), - fields: { - filterValue: '', - filterValueFrom: '', - filterValueTo: '', - selectedField: '', - }, - }; - newItem.fields.selectedField = filters[0].title; - setFilterItems([...filterItems, newItem]); - }; - - const getBenefitsCSV = async () => { - const response = await axios({url: '/benefits?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 = 'benefitsCSV.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('Benefits')} - - - - {''} - - - - {hasCreatePermission && } - - - - - {hasCreatePermission && ( - setIsModalActive(true)} - /> - )} - -
    -
    -
    - -
    - Switch to Table -
    - -
    - - - - - -
    - - - - - ) -} - -BenefitsTablesPage.getLayout = function getLayout(page: ReactElement) { - return ( - - {page} - - ) -} - -export default BenefitsTablesPage diff --git a/frontend/src/pages/benefits/benefits-new.tsx b/frontend/src/pages/benefits/benefits-new.tsx deleted file mode 100644 index 3027fdd..0000000 --- a/frontend/src/pages/benefits/benefits-new.tsx +++ /dev/null @@ -1,342 +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/benefits/benefitsSlice' -import { useAppDispatch } from '../../stores/hooks' -import { useRouter } from 'next/router' -import moment from 'moment'; - -const initialValues = { - - - title: '', - - - - - - - - - - - - - - - - - description: '', - - - - - - - - - - - - - - - icon_name: '', - - - - - - - - - - - - - - - - - - - sort_order: '', - - - - - - - - - - - - - - - - - - - is_active: false, - - - - - - - - -} - - -const BenefitsNew = () => { - const router = useRouter() - const dispatch = useAppDispatch() - - - - - const handleSubmit = async (data) => { - await dispatch(create(data)) - await router.push('/benefits/benefits-list') - } - return ( - <> - - {getPageTitle('New Item')} - - - - {''} - - - handleSubmit(values)} - > -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - router.push('/benefits/benefits-list')}/> - - -
    -
    -
    - - ) -} - -BenefitsNew.getLayout = function getLayout(page: ReactElement) { - return ( - - {page} - - ) -} - -export default BenefitsNew diff --git a/frontend/src/pages/benefits/benefits-table.tsx b/frontend/src/pages/benefits/benefits-table.tsx deleted file mode 100644 index 8673dc8..0000000 --- a/frontend/src/pages/benefits/benefits-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 TableBenefits from '../../components/Benefits/TableBenefits' -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/benefits/benefitsSlice'; - - -import {hasPermission} from "../../helpers/userPermissions"; - - - -const BenefitsTablesPage = () => { - 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: 'Title', title: 'title'},{label: 'Description', title: 'description'},{label: 'IconName', title: 'icon_name'}, - {label: 'SortOrder', title: 'sort_order', number: 'true'}, - - - - - - ]); - - const hasCreatePermission = currentUser && hasPermission(currentUser, 'CREATE_BENEFITS'); - - - const addFilter = () => { - const newItem = { - id: uniqueId(), - fields: { - filterValue: '', - filterValueFrom: '', - filterValueTo: '', - selectedField: '', - }, - }; - newItem.fields.selectedField = filters[0].title; - setFilterItems([...filterItems, newItem]); - }; - - const getBenefitsCSV = async () => { - const response = await axios({url: '/benefits?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 = 'benefitsCSV.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('Benefits')} - - - - {''} - - - - {hasCreatePermission && } - - - - - {hasCreatePermission && ( - setIsModalActive(true)} - /> - )} - -
    -
    - - - Back to card - - -
    -
    - - - -
    - - - - - ) -} - -BenefitsTablesPage.getLayout = function getLayout(page: ReactElement) { - return ( - - {page} - - ) -} - -export default BenefitsTablesPage diff --git a/frontend/src/pages/benefits/benefits-view.tsx b/frontend/src/pages/benefits/benefits-view.tsx deleted file mode 100644 index 931ee91..0000000 --- a/frontend/src/pages/benefits/benefits-view.tsx +++ /dev/null @@ -1,260 +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/benefits/benefitsSlice' -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 BenefitsView = () => { - const router = useRouter() - const dispatch = useAppDispatch() - const { benefits } = useAppSelector((state) => state.benefits) - - - 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 benefits')} - - - - - - - - - -
    -

    Title

    -

    {benefits?.title}

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