├── .gitignore ├── 1-Project ├── .dockerignore ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── backend-mongodb │ ├── .gitignore │ ├── .prettierrc │ ├── .vscode │ │ ├── launch.json │ │ └── settings.json │ ├── config │ │ ├── index.js │ │ ├── localhost.js │ │ ├── production.js │ │ └── test.js │ ├── package-lock.json │ ├── package.json │ ├── server.js │ └── src │ │ ├── __fixtures__ │ │ ├── bookFixture.js │ │ ├── genericFixture.js │ │ ├── index.js │ │ ├── loanFixture.js │ │ └── userFixture.js │ │ ├── __mocks__ │ │ └── nodemailer.js │ │ ├── api │ │ ├── auditLog │ │ │ ├── auditLogList.js │ │ │ └── index.js │ │ ├── auth │ │ │ ├── authIsEmailConfigured.js │ │ │ ├── authMe.js │ │ │ ├── authPasswordReset.js │ │ │ ├── authSendEmailAddressVerificationEmail.js │ │ │ ├── authSendPasswordResetEmail.js │ │ │ ├── authSignIn.js │ │ │ ├── authSignUp.js │ │ │ ├── authUpdateProfile.js │ │ │ ├── authVerifyEmail.js │ │ │ └── index.js │ │ ├── book │ │ │ ├── bookAutocomplete.js │ │ │ ├── bookCreate.js │ │ │ ├── bookDestroy.js │ │ │ ├── bookFind.js │ │ │ ├── bookImport.js │ │ │ ├── bookList.js │ │ │ ├── bookUpdate.js │ │ │ └── index.js │ │ ├── file │ │ │ ├── download.js │ │ │ ├── index.js │ │ │ └── upload.js │ │ ├── iam │ │ │ ├── iamChangeStatus.js │ │ │ ├── iamCreate.js │ │ │ ├── iamEdit.js │ │ │ ├── iamFind.js │ │ │ ├── iamImport.js │ │ │ ├── iamListRoles.js │ │ │ ├── iamListUsers.js │ │ │ ├── iamRemove.js │ │ │ ├── iamUserAutocomplete.js │ │ │ └── index.js │ │ ├── index.js │ │ ├── loan │ │ │ ├── index.js │ │ │ ├── loanAutocomplete.js │ │ │ ├── loanCreate.js │ │ │ ├── loanDestroy.js │ │ │ ├── loanFind.js │ │ │ ├── loanImport.js │ │ │ ├── loanList.js │ │ │ └── loanUpdate.js │ │ └── settings │ │ │ ├── index.js │ │ │ ├── settingsFind.js │ │ │ └── settingsSave.js │ │ ├── auth │ │ └── authMiddleware.js │ │ ├── database │ │ ├── database.js │ │ ├── databaseInit.js │ │ ├── models │ │ │ ├── auditLog.js │ │ │ ├── book.js │ │ │ ├── file.js │ │ │ ├── loan.js │ │ │ ├── settings.js │ │ │ └── user.js │ │ ├── repositories │ │ │ ├── abstractEntityRepository.js │ │ │ ├── abstractRepository.js │ │ │ ├── auditLogRepository.js │ │ │ ├── bookRepository.js │ │ │ ├── loanRepository.js │ │ │ ├── settingsRepository.js │ │ │ ├── userRepository.js │ │ │ └── userRoleRepository.js │ │ └── utils │ │ │ └── mongooseQuery.js │ │ ├── emails │ │ ├── emailAddressVerificationEmail.js │ │ ├── invitationEmail.js │ │ └── passwordResetEmail.js │ │ ├── errors │ │ ├── forbiddenError.js │ │ └── validationError.js │ │ ├── external │ │ └── nodemailer.js │ │ ├── i18n │ │ ├── en.js │ │ ├── index.js │ │ └── pt-BR.js │ │ ├── security │ │ ├── permissions.js │ │ └── roles.js │ │ └── services │ │ ├── auth │ │ ├── authProfileEditor.js │ │ └── authService.js │ │ ├── bookService.js │ │ ├── iam │ │ ├── iamCreator.js │ │ ├── iamEditor.js │ │ ├── iamImporter.js │ │ ├── iamRemover.js │ │ ├── iamStatusChanger.js │ │ └── permissionChecker.js │ │ ├── loanService.js │ │ ├── settingsService.js │ │ └── shared │ │ └── email │ │ └── emailSender.js ├── backend-sql │ ├── .gitignore │ ├── .prettierrc │ ├── .vscode │ │ ├── launch.json │ │ └── settings.json │ ├── config │ │ ├── index.js │ │ ├── localhost.js │ │ ├── production.js │ │ └── test.js │ ├── migrations │ │ └── reset.js │ ├── package-lock.json │ ├── package.json │ ├── server.js │ └── src │ │ ├── __fixtures__ │ │ ├── bookFixture.js │ │ ├── genericFixture.js │ │ ├── index.js │ │ ├── loanFixture.js │ │ └── userFixture.js │ │ ├── __mocks__ │ │ └── nodemailer.js │ │ ├── api │ │ ├── auditLog │ │ │ ├── auditLogList.js │ │ │ └── index.js │ │ ├── auth │ │ │ ├── authIsEmailConfigured.js │ │ │ ├── authMe.js │ │ │ ├── authPasswordReset.js │ │ │ ├── authSendEmailAddressVerificationEmail.js │ │ │ ├── authSendPasswordResetEmail.js │ │ │ ├── authSignIn.js │ │ │ ├── authSignUp.js │ │ │ ├── authUpdateProfile.js │ │ │ ├── authVerifyEmail.js │ │ │ └── index.js │ │ ├── book │ │ │ ├── bookAutocomplete.js │ │ │ ├── bookCreate.js │ │ │ ├── bookDestroy.js │ │ │ ├── bookFind.js │ │ │ ├── bookImport.js │ │ │ ├── bookList.js │ │ │ ├── bookUpdate.js │ │ │ └── index.js │ │ ├── file │ │ │ ├── download.js │ │ │ ├── index.js │ │ │ └── upload.js │ │ ├── iam │ │ │ ├── iamChangeStatus.js │ │ │ ├── iamCreate.js │ │ │ ├── iamEdit.js │ │ │ ├── iamFind.js │ │ │ ├── iamImport.js │ │ │ ├── iamListRoles.js │ │ │ ├── iamListUsers.js │ │ │ ├── iamRemove.js │ │ │ ├── iamUserAutocomplete.js │ │ │ └── index.js │ │ ├── index.js │ │ ├── loan │ │ │ ├── index.js │ │ │ ├── loanAutocomplete.js │ │ │ ├── loanCreate.js │ │ │ ├── loanDestroy.js │ │ │ ├── loanFind.js │ │ │ ├── loanImport.js │ │ │ ├── loanList.js │ │ │ └── loanUpdate.js │ │ └── settings │ │ │ ├── index.js │ │ │ ├── settingsFind.js │ │ │ └── settingsSave.js │ │ ├── auth │ │ └── authMiddleware.js │ │ ├── database │ │ ├── database.js │ │ ├── databaseInit.js │ │ ├── models │ │ │ ├── auditLog.js │ │ │ ├── book.js │ │ │ ├── file.js │ │ │ ├── index.js │ │ │ ├── loan.js │ │ │ ├── settings.js │ │ │ ├── user.js │ │ │ └── userRole.js │ │ ├── repositories │ │ │ ├── abstractRepository.js │ │ │ ├── auditLogRepository.js │ │ │ ├── bookRepository.js │ │ │ ├── fileRepository.js │ │ │ ├── loanRepository.js │ │ │ ├── settingsRepository.js │ │ │ ├── userRepository.js │ │ │ └── userRoleRepository.js │ │ └── utils │ │ │ ├── sequelizeAutocompleteFilter.js │ │ │ └── sequelizeFilter.js │ │ ├── emails │ │ ├── emailAddressVerificationEmail.js │ │ ├── invitationEmail.js │ │ └── passwordResetEmail.js │ │ ├── errors │ │ ├── forbiddenError.js │ │ └── validationError.js │ │ ├── external │ │ └── nodemailer.js │ │ ├── i18n │ │ ├── en.js │ │ ├── index.js │ │ └── pt-BR.js │ │ ├── security │ │ ├── permissions.js │ │ └── roles.js │ │ └── services │ │ ├── auth │ │ ├── authProfileEditor.js │ │ └── authService.js │ │ ├── bookService.js │ │ ├── iam │ │ ├── iamCreator.js │ │ ├── iamEditor.js │ │ ├── iamImporter.js │ │ ├── iamRemover.js │ │ ├── iamStatusChanger.js │ │ └── permissionChecker.js │ │ ├── loanService.js │ │ ├── settingsService.js │ │ └── shared │ │ └── email │ │ └── emailSender.js ├── docker-compose.yml ├── frontend │ ├── .browserslistrc │ ├── .env.localhost │ ├── .env.production │ ├── .eslintrc.js │ ├── .gitignore │ ├── .prettierrc │ ├── .vscode │ │ └── settings.json │ ├── babel.config.js │ ├── jsconfig.json │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── public │ │ ├── favicon.ico │ │ ├── images │ │ │ ├── 403.svg │ │ │ ├── 404.svg │ │ │ ├── 500.svg │ │ │ ├── emailUnverified.jpg │ │ │ ├── emptyPermissions.jpg │ │ │ ├── flags │ │ │ │ ├── 16 │ │ │ │ │ ├── Brazil.png │ │ │ │ │ └── United-States.png │ │ │ │ ├── 24 │ │ │ │ │ ├── Brazil.png │ │ │ │ │ └── United-States.png │ │ │ │ └── README.md │ │ │ ├── forgotPassword.jpg │ │ │ ├── signin.jpg │ │ │ └── signup.jpg │ │ ├── index.html │ │ ├── styles │ │ │ ├── css │ │ │ │ ├── auth.css │ │ │ │ ├── colors.css │ │ │ │ ├── errors.css │ │ │ │ ├── filter.css │ │ │ │ ├── font-awesome.custom.css │ │ │ │ ├── form.css │ │ │ │ ├── index.css │ │ │ │ ├── layout.css │ │ │ │ ├── settings.css │ │ │ │ ├── table.css │ │ │ │ └── view.css │ │ │ └── fonts │ │ │ │ ├── FontAwesome.otf │ │ │ │ ├── fontawesome-webfont.eot │ │ │ │ ├── fontawesome-webfont.svg │ │ │ │ ├── fontawesome-webfont.ttf │ │ │ │ ├── fontawesome-webfont.woff │ │ │ │ └── fontawesome-webfont.woff2 │ │ └── theme │ │ │ ├── cyan.css │ │ │ ├── default.css │ │ │ ├── fonts │ │ │ ├── element-icons.ttf │ │ │ └── element-icons.woff │ │ │ ├── geek-blue.css │ │ │ ├── gold.css │ │ │ ├── lime.css │ │ │ ├── magenta.css │ │ │ ├── orange.css │ │ │ ├── polar-green.css │ │ │ ├── purple.css │ │ │ ├── red.css │ │ │ ├── volcano.css │ │ │ └── yellow.css │ └── src │ │ ├── app-module.js │ │ ├── app.vue │ │ ├── config │ │ ├── index.js │ │ ├── localhost.js │ │ ├── production.js │ │ └── testenv.js │ │ ├── i18n │ │ ├── en.js │ │ ├── index.js │ │ └── pt-BR.js │ │ ├── main.js │ │ ├── modules │ │ ├── audit-log │ │ │ ├── audit-log-exporter-fields.js │ │ │ ├── audit-log-model.js │ │ │ ├── audit-log-module.js │ │ │ ├── audit-log-permissions.js │ │ │ ├── audit-log-routes.js │ │ │ ├── audit-log-service.js │ │ │ ├── audit-log-store.js │ │ │ └── components │ │ │ │ ├── audit-log-filter.vue │ │ │ │ ├── audit-log-page.vue │ │ │ │ ├── audit-log-table.vue │ │ │ │ └── audit-log-toolbar.vue │ │ ├── auth │ │ │ ├── auth-module.js │ │ │ ├── auth-routes.js │ │ │ ├── auth-service.js │ │ │ ├── auth-store.js │ │ │ ├── auth-token.js │ │ │ ├── components │ │ │ │ ├── email-unverified-page.vue │ │ │ │ ├── empty-permissions-page.vue │ │ │ │ ├── forgot-password-page.vue │ │ │ │ ├── password-reset-page.vue │ │ │ │ ├── profile-form-page.vue │ │ │ │ ├── signin-page.vue │ │ │ │ ├── signup-page.vue │ │ │ │ └── verify-email-page.vue │ │ │ ├── guards │ │ │ │ ├── auth-guard-mixin.js │ │ │ │ ├── email-already-verified-guard-mixin.js │ │ │ │ ├── not-empty-permissions-guard-mixin.js │ │ │ │ ├── permission-guard-mixin.js │ │ │ │ └── unauth-guard-mixin.js │ │ │ ├── user-field.js │ │ │ └── user-model.js │ │ ├── book │ │ │ ├── book-destroy-store.js │ │ │ ├── book-field.js │ │ │ ├── book-form-store.js │ │ │ ├── book-importer-fields.js │ │ │ ├── book-importer-store.js │ │ │ ├── book-list-exporter-fields.js │ │ │ ├── book-list-store.js │ │ │ ├── book-model.js │ │ │ ├── book-module.js │ │ │ ├── book-permissions.js │ │ │ ├── book-routes.js │ │ │ ├── book-service.js │ │ │ ├── book-store.js │ │ │ ├── book-view-store.js │ │ │ └── components │ │ │ │ ├── book-form-page.vue │ │ │ │ ├── book-importer-page.vue │ │ │ │ ├── book-list-filter.vue │ │ │ │ ├── book-list-page.vue │ │ │ │ ├── book-list-table.vue │ │ │ │ ├── book-list-toolbar.vue │ │ │ │ ├── book-view-page.vue │ │ │ │ └── book-view-toolbar.vue │ │ ├── home │ │ │ ├── components │ │ │ │ ├── home-chart.vue │ │ │ │ └── home-page.vue │ │ │ ├── home-module.js │ │ │ └── home-routes.js │ │ ├── iam │ │ │ ├── components │ │ │ │ ├── iam-edit-page.vue │ │ │ │ ├── iam-importer-page.vue │ │ │ │ ├── iam-list-filter.vue │ │ │ │ ├── iam-list-page.vue │ │ │ │ ├── iam-list-table.vue │ │ │ │ ├── iam-list-toolbar.vue │ │ │ │ ├── iam-new-page.vue │ │ │ │ ├── iam-view-page.vue │ │ │ │ └── iam-view-toolbar.vue │ │ │ ├── iam-form-store.js │ │ │ ├── iam-importer-fields.js │ │ │ ├── iam-importer-store.js │ │ │ ├── iam-list-exporter-fields.js │ │ │ ├── iam-list-store.js │ │ │ ├── iam-module.js │ │ │ ├── iam-permissions.js │ │ │ ├── iam-routes.js │ │ │ ├── iam-service.js │ │ │ ├── iam-store.js │ │ │ ├── iam-view-store.js │ │ │ └── permission-checker.js │ │ ├── layout │ │ │ ├── components │ │ │ │ ├── error-403-page.vue │ │ │ │ ├── error-404-page.vue │ │ │ │ ├── error-500-page.vue │ │ │ │ ├── header.vue │ │ │ │ ├── layout.vue │ │ │ │ └── menu.vue │ │ │ ├── layout-module.js │ │ │ ├── layout-routes.js │ │ │ └── layout-store.js │ │ ├── loan │ │ │ ├── components │ │ │ │ ├── loan-form-page.vue │ │ │ │ ├── loan-importer-page.vue │ │ │ │ ├── loan-list-filter.vue │ │ │ │ ├── loan-list-page.vue │ │ │ │ ├── loan-list-table.vue │ │ │ │ ├── loan-list-toolbar.vue │ │ │ │ ├── loan-view-page.vue │ │ │ │ └── loan-view-toolbar.vue │ │ │ ├── loan-destroy-store.js │ │ │ ├── loan-field.js │ │ │ ├── loan-form-store.js │ │ │ ├── loan-importer-fields.js │ │ │ ├── loan-importer-store.js │ │ │ ├── loan-list-exporter-fields.js │ │ │ ├── loan-list-store.js │ │ │ ├── loan-model.js │ │ │ ├── loan-module.js │ │ │ ├── loan-permissions.js │ │ │ ├── loan-routes.js │ │ │ ├── loan-service.js │ │ │ ├── loan-store.js │ │ │ └── loan-view-store.js │ │ └── settings │ │ │ ├── components │ │ │ ├── settings-page.vue │ │ │ └── settings-toolbar.vue │ │ │ ├── settings-model.js │ │ │ ├── settings-module.js │ │ │ ├── settings-permissions.js │ │ │ ├── settings-routes.js │ │ │ ├── settings-service.js │ │ │ └── settings-store.js │ │ ├── security │ │ ├── permissions.js │ │ └── roles.js │ │ └── shared │ │ ├── axios │ │ └── auth-axios.js │ │ ├── error │ │ └── errors.js │ │ ├── excel │ │ └── excel.js │ │ ├── exporter │ │ ├── exporter-schema.js │ │ └── exporter.js │ │ ├── fields │ │ ├── boolean-field.js │ │ ├── date-field.js │ │ ├── date-range-field.js │ │ ├── date-time-field.js │ │ ├── date-time-range-field.js │ │ ├── decimal-field.js │ │ ├── decimal-range-field.js │ │ ├── enumerator-field.js │ │ ├── files-field.js │ │ ├── generic-field.js │ │ ├── id-field.js │ │ ├── images-field.js │ │ ├── integer-field.js │ │ ├── integer-range-field.js │ │ ├── json-field.js │ │ ├── relation-to-many-field.js │ │ ├── relation-to-one-field.js │ │ ├── string-array-field.js │ │ └── string-field.js │ │ ├── file-upload │ │ └── file-uploader.js │ │ ├── filters │ │ ├── format-date-filter.js │ │ └── format-datetime-filter.js │ │ ├── form │ │ ├── autocomplete-many-input.vue │ │ ├── autocomplete-one-input.vue │ │ ├── file-upload.vue │ │ ├── filter-schema.js │ │ ├── form-schema.js │ │ ├── image-upload.vue │ │ ├── number-range-input.vue │ │ └── validators.js │ │ ├── i18n │ │ ├── i18n-flags.vue │ │ ├── i18n-select.vue │ │ ├── i18n-util.js │ │ └── i18n.vue │ │ ├── importer │ │ ├── components │ │ │ ├── importer-form.vue │ │ │ ├── importer-list.vue │ │ │ ├── importer-status-row.vue │ │ │ ├── importer-status.vue │ │ │ ├── importer-toolbar.vue │ │ │ └── importer.vue │ │ ├── importer-pager.js │ │ ├── importer-schema.js │ │ ├── importer-statuses.js │ │ ├── importer-store.js │ │ └── importer.js │ │ ├── list │ │ ├── list-item-file.vue │ │ ├── list-item-image.vue │ │ ├── list-item-relation-to-many.vue │ │ └── list-item-relation-to-one.vue │ │ ├── message │ │ └── message.js │ │ ├── mixins │ │ └── autofocus-mixin.js │ │ ├── model │ │ └── generic-model.js │ │ ├── plugins │ │ └── element.js │ │ ├── progress-bar │ │ └── progress-bar.js │ │ ├── shared-module.js │ │ └── view │ │ ├── image-carousel.vue │ │ ├── view-item-custom.vue │ │ ├── view-item-file.vue │ │ ├── view-item-image.vue │ │ ├── view-item-relation-to-many.vue │ │ ├── view-item-relation-to-one.vue │ │ └── view-item-text.vue └── package.json ├── 2-Basics ├── 1 - NodeJS and Javascript │ ├── 1-basics.js │ ├── 2-functions-and-classes.js │ ├── 3-callbacks-and-arrow-functions.js │ ├── 4-spread-deconstruct-objects.js │ ├── 5-spread-deconstruct-arrays.js │ ├── 6-npm-modules.js │ ├── 7-async-await.js │ ├── package-lock.json │ └── package.json ├── 2 - Vue │ ├── backend │ │ ├── .gitignore │ │ ├── db.json │ │ ├── package-lock.json │ │ └── package.json │ └── frontend │ │ ├── .gitignore │ │ ├── README.md │ │ ├── babel.config.js │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── public │ │ ├── favicon.ico │ │ └── index.html │ │ └── src │ │ ├── App.vue │ │ ├── main.js │ │ └── todo │ │ ├── components │ │ ├── TodoForm.vue │ │ ├── TodoList.vue │ │ └── TodoPage.vue │ │ └── todoService.js ├── 3 - Vue Router │ └── link.txt ├── 4 - Element UI │ ├── backend │ │ ├── .gitignore │ │ ├── db.json │ │ ├── package-lock.json │ │ └── package.json │ └── frontend │ │ ├── .gitignore │ │ ├── README.md │ │ ├── babel.config.js │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── public │ │ ├── favicon.ico │ │ └── index.html │ │ └── src │ │ ├── App.vue │ │ ├── main.js │ │ ├── plugins │ │ └── element.js │ │ └── todo │ │ ├── components │ │ ├── TodoForm.vue │ │ ├── TodoList.vue │ │ └── TodoPage.vue │ │ └── todoService.js ├── 5 - Vuex │ ├── backend │ │ ├── .gitignore │ │ ├── db.json │ │ ├── package-lock.json │ │ └── package.json │ └── frontend │ │ ├── .gitignore │ │ ├── README.md │ │ ├── babel.config.js │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── public │ │ ├── favicon.ico │ │ └── index.html │ │ └── src │ │ ├── App.vue │ │ ├── main.js │ │ ├── plugins │ │ └── element.js │ │ ├── store.js │ │ └── todo │ │ ├── components │ │ ├── TodoForm.vue │ │ ├── TodoList.vue │ │ └── TodoPage.vue │ │ ├── todoService.js │ │ └── todoStore.js ├── 6 - ExpressJS │ └── backend │ │ ├── index.js │ │ ├── package-lock.json │ │ └── package.json ├── 7 - SQL and Sequelize │ └── backend │ │ ├── config.js │ │ ├── index.js │ │ ├── models │ │ ├── index.js │ │ └── todo.js │ │ ├── package-lock.json │ │ └── package.json └── 8 - MongoDB and Mongoose │ └── backend │ ├── index.js │ ├── models │ └── todo.js │ ├── package-lock.json │ └── package.json ├── 3-Customization ├── backend-mongodb │ ├── config │ │ ├── localhost.js │ │ └── production.js │ └── src │ │ ├── api │ │ └── loan │ │ │ ├── index.js │ │ │ └── loanEmail.js │ │ ├── database │ │ ├── models │ │ │ ├── book.js │ │ │ ├── loan.js │ │ │ └── settings.js │ │ ├── repositories │ │ │ ├── bookRepository.js │ │ │ └── loanRepository.js │ │ └── utils │ │ │ └── mongooseQuery.js │ │ ├── emails │ │ ├── loanInProgressEmail.js │ │ └── loanOverdueEmail.js │ │ ├── i18n │ │ ├── en.js │ │ └── pt-BR.js │ │ ├── security │ │ ├── permissions.js │ │ └── roles.js │ │ └── services │ │ ├── auth │ │ └── authService.js │ │ ├── bookService.js │ │ ├── iam │ │ ├── iamEditor.js │ │ └── iamRemover.js │ │ └── loanService.js ├── backend-sql │ ├── config │ │ ├── localhost.js │ │ └── production.js │ ├── migrations │ │ └── 201907021900-add-loan-period-in-days-to-settings.sql │ └── src │ │ ├── api │ │ └── loan │ │ │ ├── index.js │ │ │ └── loanEmail.js │ │ ├── database │ │ ├── models │ │ │ ├── book.js │ │ │ ├── loan.js │ │ │ └── settings.js │ │ ├── repositories │ │ │ ├── bookRepository.js │ │ │ └── loanRepository.js │ │ └── utils │ │ │ └── sequelizeFilter.js │ │ ├── emails │ │ ├── loanInProgressEmail.js │ │ └── loanOverdueEmail.js │ │ ├── i18n │ │ ├── en.js │ │ └── pt-BR.js │ │ ├── security │ │ ├── permissions.js │ │ └── roles.js │ │ └── services │ │ ├── auth │ │ └── authService.js │ │ ├── bookService.js │ │ ├── iam │ │ ├── iamEditor.js │ │ └── iamRemover.js │ │ └── loanService.js └── frontend │ ├── public │ └── images │ │ ├── signin.jpg │ │ └── signup.jpg │ └── src │ ├── app-module.js │ ├── i18n │ ├── en.js │ └── pt-BR.js │ ├── modules │ ├── auth │ │ └── auth-store.js │ ├── book │ │ ├── book-field.js │ │ ├── book-importer-fields.js │ │ ├── book-list-exporter-fields.js │ │ └── components │ │ │ ├── book-form-page.vue │ │ │ ├── book-list-filter.vue │ │ │ ├── book-list-table.vue │ │ │ ├── book-status-tag.vue │ │ │ └── book-view-page.vue │ ├── layout │ │ └── components │ │ │ └── menu.vue │ ├── loan │ │ ├── components │ │ │ ├── loan-form-page.vue │ │ │ ├── loan-list-filter.vue │ │ │ ├── loan-list-table.vue │ │ │ ├── loan-list-toolbar.vue │ │ │ ├── loan-status-tag.vue │ │ │ └── loan-view-page.vue │ │ ├── loan-email-store.js │ │ ├── loan-importer-fields.js │ │ ├── loan-model.js │ │ ├── loan-permissions.js │ │ ├── loan-service.js │ │ └── loan-store.js │ └── settings │ │ ├── components │ │ └── settings-page.vue │ │ ├── settings-model.js │ │ └── settings-store.js │ └── security │ ├── permissions.js │ └── roles.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /1-Project/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | backend/node_modules 3 | frontend/node_modules 4 | npm-debug.log 5 | Dockerfile* 6 | docker-compose* 7 | .dockerignore 8 | .git 9 | .gitignore 10 | .env 11 | */bin 12 | */obj 13 | README.md 14 | LICENSE 15 | .vscode 16 | -------------------------------------------------------------------------------- /1-Project/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | node_modules/ 6 | 7 | # testing 8 | /coverage 9 | 10 | # production 11 | /build 12 | 13 | # misc 14 | .DS_Store 15 | .env.local 16 | .env.development.local 17 | .env.test.local 18 | .env.production.local 19 | 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* -------------------------------------------------------------------------------- /1-Project/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:8 2 | WORKDIR /app 3 | COPY . /app 4 | RUN npm run build:production 5 | CMD npm run start:production 6 | -------------------------------------------------------------------------------- /1-Project/LICENSE: -------------------------------------------------------------------------------- 1 | https://scaffoldhub.io/terms-of-service 2 | 3 | This code can only be used for academic and learning purposes. -------------------------------------------------------------------------------- /1-Project/README.md: -------------------------------------------------------------------------------- 1 | Version 1.2.1. 2 | https://scaffoldhub.io 3 | 4 | This code can only be used for academic and learning purposes. 5 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | /service-accounts/*.json 3 | /data -------------------------------------------------------------------------------- /1-Project/backend-mongodb/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "arrowParens": "always", 4 | "printWidth": 60, 5 | "trailingComma": "all" 6 | } 7 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "env": { "NODE_ENV": "localhost" }, 12 | "program": "${workspaceFolder}/server.js" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.colorCustomizations": { 3 | "titleBar.activeForeground": "#000", 4 | "titleBar.inactiveForeground": "#000000CC", 5 | "titleBar.activeBackground": "#eb2568", 6 | "titleBar.inactiveBackground": "#eb2568CC" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/config/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function get() { 2 | const isMigration = !!process.env.MIGRATION_ENV; 3 | 4 | if (isMigration) { 5 | const config = require(`./${ 6 | process.env.MIGRATION_ENV 7 | }`); 8 | 9 | return config; 10 | } 11 | 12 | return require(`./${process.env.NODE_ENV}`); 13 | }; 14 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/config/localhost.js: -------------------------------------------------------------------------------- 1 | const os = require('os'); 2 | 3 | module.exports = { 4 | env: 'localhost', 5 | 6 | database: { 7 | // connection: 8 | // 'mongodb://localhost:27017,localhost:27018,localhost:27019/development?replicaSet=rs', 9 | // transactions: true, 10 | connection: 'mongodb://localhost:27017/development', 11 | transactions: false, 12 | }, 13 | 14 | email: { 15 | comment: 'See https://nodemailer.com', 16 | from: '', 17 | host: null, 18 | auth: { 19 | user: null, 20 | pass: null, 21 | }, 22 | }, 23 | 24 | graphiql: true, 25 | 26 | clientUrl: 27 | '', 28 | 29 | defaultUser: '', 30 | 31 | uploadDir: os.tmpdir(), 32 | 33 | authJwtSecret: '', 34 | }; 35 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/config/production.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: 'production', 3 | 4 | database: { 5 | connection: 'mongodb://mongo:27017/production', 6 | transactions: false, 7 | }, 8 | 9 | email: { 10 | comment: 'See https://nodemailer.com', 11 | from: '', 12 | host: null, 13 | auth: { 14 | user: null, 15 | pass: null, 16 | }, 17 | }, 18 | 19 | graphiql: false, 20 | 21 | clientUrl: 22 | '', 23 | 24 | defaultUser: null, 25 | 26 | uploadDir: '/storage', 27 | 28 | authJwtSecret: '', 29 | }; 30 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/config/test.js: -------------------------------------------------------------------------------- 1 | const os = require('os'); 2 | 3 | module.exports = { 4 | env: 'test', 5 | 6 | database: { 7 | // connection: 8 | // 'mongodb://localhost:27017,localhost:27018,localhost:27019/test?replicaSet=rs', 9 | // transactions: true, 10 | connection: 'mongodb://localhost:27017/test', 11 | transactions: false, 12 | }, 13 | 14 | email: { 15 | auth: { 16 | user: 'mock', 17 | }, 18 | }, 19 | 20 | graphiql: false, 21 | 22 | clientUrl: '', 23 | 24 | defaultUser: '', 25 | 26 | uploadDir: os.tmpdir(), 27 | 28 | authJwtSecret: '', 29 | }; 30 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/server.js: -------------------------------------------------------------------------------- 1 | const api = require('./src/api'); 2 | 3 | const PORT = process.env.PORT || 8080; 4 | 5 | api.listen(PORT, () => { 6 | console.log(`Listening on port ${PORT}`); 7 | }); 8 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/__fixtures__/bookFixture.js: -------------------------------------------------------------------------------- 1 | const genericFixture = require('./genericFixture'); 2 | const BookRepository = require('../database/repositories/bookRepository'); 3 | 4 | const bookFixture = genericFixture({ 5 | idField: 'id', 6 | createFn: (data) => new BookRepository().create(data), 7 | data: [ 8 | { 9 | id: '1', 10 | // Add attributes here 11 | }, 12 | ], 13 | }); 14 | 15 | module.exports = bookFixture; 16 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/__fixtures__/genericFixture.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ createFn, data, idField = 'id' }) => ({ 2 | buildAll() { 3 | return JSON.parse(JSON.stringify(data)); 4 | }, 5 | 6 | build(id, overrides) { 7 | const item = this.buildAll().find( 8 | (item) => item[idField] === id, 9 | ); 10 | 11 | if (!item) { 12 | throw new Error(`Not found fixture with id: ${id}.`); 13 | } 14 | 15 | return { 16 | ...item, 17 | ...overrides, 18 | }; 19 | }, 20 | 21 | async createAll() { 22 | const items = []; 23 | 24 | for (let item of this.buildAll()) { 25 | items.push(await this.create(item.id)); 26 | } 27 | 28 | return items; 29 | }, 30 | 31 | async create(id, overrides) { 32 | const item = this.build(id, overrides); 33 | 34 | if (!createFn) { 35 | return item; 36 | } 37 | 38 | return createFn(item); 39 | }, 40 | }); 41 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/__fixtures__/index.js: -------------------------------------------------------------------------------- 1 | const userFixture = require('./userFixture'); 2 | const loanFixture = require('./loanFixture'); 3 | const bookFixture = require('./bookFixture'); 4 | const AbstractRepository = require('../database/repositories/abstractRepository'); 5 | 6 | module.exports = { 7 | user: userFixture, 8 | loan: loanFixture, 9 | book: bookFixture, 10 | 11 | async cleanDatabase() { 12 | await AbstractRepository.cleanDatabase(); 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/__fixtures__/loanFixture.js: -------------------------------------------------------------------------------- 1 | const genericFixture = require('./genericFixture'); 2 | const LoanRepository = require('../database/repositories/loanRepository'); 3 | 4 | const loanFixture = genericFixture({ 5 | idField: 'id', 6 | createFn: (data) => new LoanRepository().create(data), 7 | data: [ 8 | { 9 | id: '1', 10 | // Add attributes here 11 | }, 12 | ], 13 | }); 14 | 15 | module.exports = loanFixture; 16 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/__mocks__/nodemailer.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | createTransport() { 3 | return { 4 | sendMail: () => {}, 5 | }; 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/auditLog/auditLogList.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const AuditLogRepository = require('../../database/repositories/auditLogRepository'); 3 | const permissions = require('../../security/permissions') 4 | .values; 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.auditLogRead, 10 | ); 11 | 12 | const payload = await AuditLogRepository.findAndCountAll( 13 | req.query, 14 | ); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/auditLog/index.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | app.get(`/auditLog`, require('./auditLogList')); 3 | }; 4 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/auth/authIsEmailConfigured.js: -------------------------------------------------------------------------------- 1 | const EmailSender = require('../../services/shared/email/emailSender'); 2 | 3 | module.exports = (req, res) => { 4 | try { 5 | const payload = EmailSender.isConfigured; 6 | 7 | res.status(200).send(payload); 8 | } catch (error) { 9 | if ([400, 403, 404].includes(error.code)) { 10 | return res.status(error.code).send(error.message); 11 | } 12 | 13 | console.error(error); 14 | return res.status(500).send(error.message); 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/auth/authMe.js: -------------------------------------------------------------------------------- 1 | const ForbiddenError = require('../../errors/forbiddenError'); 2 | 3 | module.exports = (req, res) => { 4 | try { 5 | if (!req.currentUser || !req.currentUser.id) { 6 | throw new ForbiddenError(req.language); 7 | } 8 | 9 | const payload = req.currentUser; 10 | 11 | res.status(200).send(payload); 12 | } catch (error) { 13 | if ([400, 403, 404].includes(error.code)) { 14 | return res.status(error.code).send(error.message); 15 | } 16 | 17 | console.error(error); 18 | return res.status(500).send(error.message); 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/auth/authPasswordReset.js: -------------------------------------------------------------------------------- 1 | const AuthService = require('../../services/auth/authService'); 2 | 3 | module.exports = async (req, res) => { 4 | try { 5 | const payload = await AuthService.passwordReset( 6 | req.body.token, 7 | req.body.password, 8 | req, 9 | ); 10 | 11 | res.status(200).send(payload); 12 | } catch (error) { 13 | if ([400, 403, 404].includes(error.code)) { 14 | return res.status(error.code).send(error.message); 15 | } 16 | 17 | console.error(error); 18 | return res.status(500).send(error.message); 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/auth/authSendEmailAddressVerificationEmail.js: -------------------------------------------------------------------------------- 1 | const ForbiddenError = require('../../errors/forbiddenError'); 2 | const AuthService = require('../../services/auth/authService'); 3 | 4 | module.exports = async (req, res) => { 5 | try { 6 | if (!req.currentUser) { 7 | throw new ForbiddenError(req.language); 8 | } 9 | 10 | await AuthService.sendEmailAddressVerificationEmail( 11 | req.language, 12 | req.currentUser.email, 13 | ); 14 | 15 | const payload = true; 16 | 17 | res.status(200).send(payload); 18 | } catch (error) { 19 | if ([400, 403, 404].includes(error.code)) { 20 | return res.status(error.code).send(error.message); 21 | } 22 | 23 | console.error(error); 24 | return res.status(500).send(error.message); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/auth/authSendPasswordResetEmail.js: -------------------------------------------------------------------------------- 1 | const AuthService = require('../../services/auth/authService'); 2 | 3 | module.exports = async (req, res) => { 4 | try { 5 | await AuthService.sendPasswordResetEmail( 6 | req.language, 7 | req.body.email, 8 | ); 9 | 10 | const payload = true; 11 | 12 | res.status(200).send(payload); 13 | } catch (error) { 14 | if ([400, 403, 404].includes(error.code)) { 15 | return res.status(error.code).send(error.message); 16 | } 17 | 18 | console.error(error); 19 | return res.status(500).send(error.message); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/auth/authSignIn.js: -------------------------------------------------------------------------------- 1 | const AuthService = require('../../services/auth/authService'); 2 | 3 | module.exports = async (req, res) => { 4 | try { 5 | const payload = await AuthService.signin( 6 | req.body.email, 7 | req.body.password, 8 | req, 9 | ); 10 | 11 | res.status(200).send(payload); 12 | } catch (error) { 13 | if ([400, 403, 404].includes(error.code)) { 14 | return res.status(error.code).send(error.message); 15 | } 16 | 17 | console.error(error); 18 | return res.status(500).send(error.message); 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/auth/authSignUp.js: -------------------------------------------------------------------------------- 1 | const AuthService = require('../../services/auth/authService'); 2 | 3 | module.exports = async (req, res) => { 4 | try { 5 | const payload = await AuthService.signup( 6 | req.body.email, 7 | req.body.password, 8 | req, 9 | ); 10 | 11 | res.status(200).send(payload); 12 | } catch (error) { 13 | if ([400, 403, 404].includes(error.code)) { 14 | return res.status(error.code).send(error.message); 15 | } 16 | 17 | console.error(error); 18 | return res.status(500).send(error.message); 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/auth/authUpdateProfile.js: -------------------------------------------------------------------------------- 1 | const AuthProfileEditor = require('../../services/auth/authProfileEditor'); 2 | const ForbiddenError = require('../../errors/forbiddenError'); 3 | 4 | module.exports = async (req, res) => { 5 | try { 6 | if (!req.currentUser || !req.currentUser.id) { 7 | throw new ForbiddenError(req.language); 8 | } 9 | 10 | let editor = new AuthProfileEditor( 11 | req.currentUser, 12 | req.language, 13 | ); 14 | 15 | await editor.execute(req.body.profile); 16 | 17 | const payload = true; 18 | 19 | res.status(200).send(payload); 20 | } catch (error) { 21 | if ([400, 403, 404].includes(error.code)) { 22 | return res.status(error.code).send(error.message); 23 | } 24 | 25 | console.error(error); 26 | return res.status(500).send(error.message); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/auth/authVerifyEmail.js: -------------------------------------------------------------------------------- 1 | const AuthService = require('../../services/auth/authService'); 2 | 3 | module.exports = async (req, res) => { 4 | try { 5 | const payload = await AuthService.verifyEmail( 6 | req.body.token, 7 | req, 8 | ); 9 | 10 | res.status(200).send(payload); 11 | } catch (error) { 12 | if ([400, 403, 404].includes(error.code)) { 13 | return res.status(error.code).send(error.message); 14 | } 15 | 16 | console.error(error); 17 | return res.status(500).send(error.message); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/auth/index.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | app.put( 3 | `/auth/password-reset`, 4 | require('./authPasswordReset'), 5 | ); 6 | 7 | app.post( 8 | `/auth/send-email-address-verification-email`, 9 | require('./authSendEmailAddressVerificationEmail'), 10 | ); 11 | 12 | app.post( 13 | `/auth/send-password-reset-email`, 14 | require('./authSendPasswordResetEmail'), 15 | ); 16 | 17 | app.post(`/auth/sign-in`, require('./authSignIn')); 18 | 19 | app.post(`/auth/sign-up`, require('./authSignUp')); 20 | 21 | app.put(`/auth/profile`, require('./authUpdateProfile')); 22 | 23 | app.put( 24 | `/auth/verify-email`, 25 | require('./authVerifyEmail'), 26 | ); 27 | 28 | app.get(`/auth/me`, require('./authMe')); 29 | 30 | app.get( 31 | `/auth/email-configured`, 32 | require('./authIsEmailConfigured'), 33 | ); 34 | }; 35 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/book/bookAutocomplete.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const BookService = require('../../services/bookService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.bookAutocomplete, 10 | ); 11 | 12 | const payload = await new BookService( 13 | req, 14 | ).findAllAutocomplete(req.query.query, req.query.limit); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/book/bookCreate.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const BookService = require('../../services/bookService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.bookCreate, 10 | ); 11 | 12 | const payload = await new BookService(req).create( 13 | req.body.data, 14 | ); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/book/bookDestroy.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const BookService = require('../../services/bookService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.bookDestroy, 10 | ); 11 | 12 | await new BookService(req).destroyAll( 13 | req.query.ids, 14 | ); 15 | 16 | const payload = true; 17 | 18 | res.status(200).send(payload); 19 | } catch (error) { 20 | if ([400, 403, 404].includes(error.code)) { 21 | return res.status(error.code).send(error.message); 22 | } 23 | 24 | console.error(error); 25 | return res.status(500).send(error.message); 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/book/bookFind.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const BookService = require('../../services/bookService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.bookRead, 10 | ); 11 | 12 | const payload = await new BookService(req).findById( 13 | req.params.id, 14 | ); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/book/bookImport.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const BookService = require('../../services/bookService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.bookImport, 10 | ); 11 | 12 | await new BookService(req).import( 13 | req.body.data, 14 | req.body.importHash, 15 | ); 16 | 17 | const payload = true; 18 | 19 | res.status(200).send(payload); 20 | } catch (error) { 21 | if ([400, 403, 404].includes(error.code)) { 22 | return res.status(error.code).send(error.message); 23 | } 24 | 25 | console.error(error); 26 | return res.status(500).send(error.message); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/book/bookList.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const BookService = require('../../services/bookService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.bookRead, 10 | ); 11 | 12 | const payload = await new BookService( 13 | req, 14 | ).findAndCountAll(req.query); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/book/bookUpdate.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const BookService = require('../../services/bookService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.bookEdit, 10 | ); 11 | 12 | const payload = await new BookService(req).update( 13 | req.body.id, 14 | req.body.data, 15 | ); 16 | 17 | res.status(200).send(payload); 18 | } catch (error) { 19 | if ([400, 403, 404].includes(error.code)) { 20 | return res.status(error.code).send(error.message); 21 | } 22 | 23 | console.error(error); 24 | return res.status(500).send(error.message); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/book/index.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | app.post(`/book`, require('./bookCreate')); 3 | app.put(`/book/:id`, require('./bookUpdate')); 4 | app.post(`/book/import`, require('./bookImport')); 5 | app.delete(`/book`, require('./bookDestroy')); 6 | app.get( 7 | `/book/autocomplete`, 8 | require('./bookAutocomplete'), 9 | ); 10 | app.get(`/book`, require('./bookList')); 11 | app.get(`/book/:id`, require('./bookFind')); 12 | }; 13 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/file/download.js: -------------------------------------------------------------------------------- 1 | const config = require('../../../config')(); 2 | const path = require('path'); 3 | 4 | module.exports = (req, res) => { 5 | const privateUrl = req.query.privateUrl; 6 | 7 | if (!privateUrl) { 8 | return res.sendStatus(404); 9 | } 10 | 11 | res.download(path.join(config.uploadDir, privateUrl)); 12 | }; 13 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/file/index.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | const upload = require('./upload'); 3 | upload.mapAllUploadRequests(app); 4 | 5 | app.get(`/download`, require('./download')); 6 | }; 7 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/iam/iamChangeStatus.js: -------------------------------------------------------------------------------- 1 | const IamStatusChanger = require('../../services/iam/iamStatusChanger'); 2 | const PermissionChecker = require('../../services/iam/permissionChecker'); 3 | const permissions = require('../../security/permissions') 4 | .values; 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.iamEdit, 10 | ); 11 | 12 | let statusChanger = new IamStatusChanger( 13 | req.currentUser, 14 | req.language, 15 | ); 16 | 17 | await statusChanger.changeStatus(req.body); 18 | 19 | const payload = true; 20 | 21 | res.status(200).send(payload); 22 | } catch (error) { 23 | if ([400, 403, 404].includes(error.code)) { 24 | return res.status(error.code).send(error.message); 25 | } 26 | 27 | console.error(error); 28 | return res.status(500).send(error.message); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/iam/iamCreate.js: -------------------------------------------------------------------------------- 1 | const IamCreator = require('../../services/iam/iamCreator'); 2 | const PermissionChecker = require('../../services/iam/permissionChecker'); 3 | const permissions = require('../../security/permissions') 4 | .values; 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.iamCreate, 10 | ); 11 | 12 | let creator = new IamCreator( 13 | req.currentUser, 14 | req.language, 15 | ); 16 | 17 | await creator.execute(req.body.data); 18 | 19 | const payload = true; 20 | 21 | res.status(200).send(payload); 22 | } catch (error) { 23 | if ([400, 403, 404].includes(error.code)) { 24 | return res.status(error.code).send(error.message); 25 | } 26 | 27 | console.error(error); 28 | return res.status(500).send(error.message); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/iam/iamEdit.js: -------------------------------------------------------------------------------- 1 | const IamEditor = require('../../services/iam/iamEditor'); 2 | const PermissionChecker = require('../../services/iam/permissionChecker'); 3 | const permissions = require('../../security/permissions') 4 | .values; 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.iamEdit, 10 | ); 11 | 12 | let editor = new IamEditor( 13 | req.currentUser, 14 | req.language, 15 | ); 16 | 17 | await editor.update(req.body.data); 18 | 19 | const payload = true; 20 | 21 | res.status(200).send(payload); 22 | } catch (error) { 23 | if ([400, 403, 404].includes(error.code)) { 24 | return res.status(error.code).send(error.message); 25 | } 26 | 27 | console.error(error); 28 | return res.status(500).send(error.message); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/iam/iamFind.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const UserRepository = require('../../database/repositories/userRepository'); 3 | const permissions = require('../../security/permissions') 4 | .values; 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.iamRead, 10 | ); 11 | 12 | const payload = await UserRepository.findById( 13 | req.params.id, 14 | ); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/iam/iamImport.js: -------------------------------------------------------------------------------- 1 | const IamImporter = require('../../services/iam/iamImporter'); 2 | const PermissionChecker = require('../../services/iam/permissionChecker'); 3 | const permissions = require('../../security/permissions') 4 | .values; 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.iamImport, 10 | ); 11 | 12 | await new IamImporter( 13 | req.currentUser, 14 | req.language, 15 | ).import(req.body.data, req.body.importHash); 16 | 17 | const payload = true; 18 | 19 | res.status(200).send(payload); 20 | } catch (error) { 21 | if ([400, 403, 404].includes(error.code)) { 22 | return res.status(error.code).send(error.message); 23 | } 24 | 25 | console.error(error); 26 | return res.status(500).send(error.message); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/iam/iamListRoles.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const UserRoleRepository = require('../../database/repositories/userRoleRepository'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.iamRead, 10 | ); 11 | 12 | const payload = await UserRoleRepository.findAllWithUsers( 13 | req.query, 14 | ); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/iam/iamListUsers.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const UserRepository = require('../../database/repositories/userRepository'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.iamRead, 10 | ); 11 | 12 | const payload = await UserRepository.findAllWithCount( 13 | req.query, 14 | ); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/iam/iamRemove.js: -------------------------------------------------------------------------------- 1 | const IamRemover = require('../../services/iam/iamRemover'); 2 | const PermissionChecker = require('../../services/iam/permissionChecker'); 3 | const permissions = require('../../security/permissions') 4 | .values; 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.iamEdit, 10 | ); 11 | 12 | let remover = new IamRemover( 13 | req.currentUser, 14 | req.language, 15 | ); 16 | 17 | await remover.removeAll(req.query); 18 | 19 | const payload = true; 20 | 21 | res.status(200).send(payload); 22 | } catch (error) { 23 | if ([400, 403, 404].includes(error.code)) { 24 | return res.status(error.code).send(error.message); 25 | } 26 | 27 | console.error(error); 28 | return res.status(500).send(error.message); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/iam/iamUserAutocomplete.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const UserRepository = require('../../database/repositories/userRepository'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.iamUserAutocomplete, 10 | ); 11 | 12 | const payload = await UserRepository.findAllAutocomplete( 13 | req.query.query, 14 | req.query.limit, 15 | ); 16 | 17 | res.status(200).send(payload); 18 | } catch (error) { 19 | if ([400, 403, 404].includes(error.code)) { 20 | return res.status(error.code).send(error.message); 21 | } 22 | 23 | console.error(error); 24 | return res.status(500).send(error.message); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/iam/index.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | app.put(`/iam/status`, require('./iamChangeStatus')); 3 | app.post(`/iam`, require('./iamCreate')); 4 | app.put(`/iam`, require('./iamEdit')); 5 | app.post(`/iam/import`, require('./iamImport')); 6 | app.delete(`/iam`, require('./iamRemove')); 7 | app.get(`/iam/role`, require('./iamListRoles')); 8 | app.get(`/iam/user`, require('./iamListUsers')); 9 | app.get( 10 | `/iam/user/autocomplete`, 11 | require('./iamUserAutocomplete'), 12 | ); 13 | app.get(`/iam/:id`, require('./iamFind')); 14 | }; 15 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/loan/index.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | app.post(`/loan`, require('./loanCreate')); 3 | app.put(`/loan/:id`, require('./loanUpdate')); 4 | app.post(`/loan/import`, require('./loanImport')); 5 | app.delete(`/loan`, require('./loanDestroy')); 6 | app.get( 7 | `/loan/autocomplete`, 8 | require('./loanAutocomplete'), 9 | ); 10 | app.get(`/loan`, require('./loanList')); 11 | app.get(`/loan/:id`, require('./loanFind')); 12 | }; 13 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/loan/loanAutocomplete.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const LoanService = require('../../services/loanService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.loanAutocomplete, 10 | ); 11 | 12 | const payload = await new LoanService( 13 | req, 14 | ).findAllAutocomplete(req.query.query, req.query.limit); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/loan/loanCreate.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const LoanService = require('../../services/loanService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.loanCreate, 10 | ); 11 | 12 | const payload = await new LoanService(req).create( 13 | req.body.data, 14 | ); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/loan/loanDestroy.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const LoanService = require('../../services/loanService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.loanDestroy, 10 | ); 11 | 12 | await new LoanService(req).destroyAll( 13 | req.query.ids, 14 | ); 15 | 16 | const payload = true; 17 | 18 | res.status(200).send(payload); 19 | } catch (error) { 20 | if ([400, 403, 404].includes(error.code)) { 21 | return res.status(error.code).send(error.message); 22 | } 23 | 24 | console.error(error); 25 | return res.status(500).send(error.message); 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/loan/loanFind.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const LoanService = require('../../services/loanService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.loanRead, 10 | ); 11 | 12 | const payload = await new LoanService(req).findById( 13 | req.params.id, 14 | ); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/loan/loanImport.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const LoanService = require('../../services/loanService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.loanImport, 10 | ); 11 | 12 | await new LoanService(req).import( 13 | req.body.data, 14 | req.body.importHash, 15 | ); 16 | 17 | const payload = true; 18 | 19 | res.status(200).send(payload); 20 | } catch (error) { 21 | if ([400, 403, 404].includes(error.code)) { 22 | return res.status(error.code).send(error.message); 23 | } 24 | 25 | console.error(error); 26 | return res.status(500).send(error.message); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/loan/loanList.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const LoanService = require('../../services/loanService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.loanRead, 10 | ); 11 | 12 | const payload = await new LoanService( 13 | req, 14 | ).findAndCountAll(req.query); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/loan/loanUpdate.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const LoanService = require('../../services/loanService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.loanEdit, 10 | ); 11 | 12 | const payload = await new LoanService(req).update( 13 | req.body.id, 14 | req.body.data, 15 | ); 16 | 17 | res.status(200).send(payload); 18 | } catch (error) { 19 | if ([400, 403, 404].includes(error.code)) { 20 | return res.status(error.code).send(error.message); 21 | } 22 | 23 | console.error(error); 24 | return res.status(500).send(error.message); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/settings/index.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | app.put(`/settings`, require('./settingsSave')); 3 | app.get(`/settings`, require('./settingsFind')); 4 | }; 5 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/settings/settingsFind.js: -------------------------------------------------------------------------------- 1 | const SettingsService = require('../../services/settingsService'); 2 | 3 | module.exports = async (req, res) => { 4 | try { 5 | const payload = await SettingsService.findOrCreateDefault( 6 | req.currentUser, 7 | ); 8 | 9 | res.status(200).send(payload); 10 | } catch (error) { 11 | if ([400, 403, 404].includes(error.code)) { 12 | return res.status(error.code).send(error.message); 13 | } 14 | 15 | console.error(error); 16 | return res.status(500).send(error.message); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/api/settings/settingsSave.js: -------------------------------------------------------------------------------- 1 | const SettingsService = require('../../services/settingsService'); 2 | const PermissionChecker = require('../../services/iam/permissionChecker'); 3 | const permissions = require('../../security/permissions') 4 | .values; 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.settingsEdit, 10 | ); 11 | 12 | const payload = await SettingsService.save( 13 | req.body.settings, 14 | req.currentUser, 15 | ); 16 | 17 | res.status(200).send(payload); 18 | } catch (error) { 19 | if ([400, 403, 404].includes(error.code)) { 20 | return res.status(error.code).send(error.message); 21 | } 22 | 23 | console.error(error); 24 | return res.status(500).send(error.message); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/database/database.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | module.exports = mongoose; 3 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/database/databaseInit.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('./database'); 2 | const config = require('../../config')(); 3 | 4 | const init = async () => { 5 | if (!mongoose.connection.readyState) { 6 | return mongoose 7 | .connect(config.database.connection, { 8 | useNewUrlParser: true, 9 | }) 10 | .then(() => console.log('MongoDB connected')) 11 | .then(() => mongoose); 12 | } 13 | 14 | return mongoose; 15 | }; 16 | 17 | const middleware = async (req, res, next) => { 18 | try { 19 | await init(); 20 | } catch (error) { 21 | console.error(error); 22 | res.sendStatus(500); 23 | return; 24 | } 25 | return next(); 26 | }; 27 | 28 | exports.init = init; 29 | exports.middleware = middleware; 30 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/database/models/file.js: -------------------------------------------------------------------------------- 1 | const database = require('../database'); 2 | const Schema = database.Schema; 3 | 4 | const FileSchema = new Schema( 5 | { 6 | name: { 7 | type: String, 8 | maxlength: 21845, 9 | required: true, 10 | }, 11 | sizeInBytes: { type: Number }, 12 | privateUrl: { type: String, maxlength: 21845 }, 13 | publicUrl: { 14 | type: String, 15 | maxlength: 21845, 16 | required: true, 17 | }, 18 | }, 19 | { timestamps: true }, 20 | ); 21 | 22 | FileSchema.virtual('id').get(function() { 23 | return this._id.toHexString(); 24 | }); 25 | 26 | FileSchema.set('toJSON', { 27 | getters: true, 28 | }); 29 | 30 | FileSchema.set('toObject', { 31 | getters: true, 32 | }); 33 | 34 | exports.FileSchema = FileSchema; 35 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/database/models/settings.js: -------------------------------------------------------------------------------- 1 | const database = require('../database'); 2 | const Schema = database.Schema; 3 | 4 | const SettingsSchema = new Schema( 5 | { 6 | theme: { type: String }, 7 | createdBy: { 8 | type: Schema.Types.ObjectId, 9 | ref: 'user', 10 | }, 11 | updatedBy: { 12 | type: Schema.Types.ObjectId, 13 | ref: 'user', 14 | }, 15 | }, 16 | { timestamps: true }, 17 | ); 18 | 19 | SettingsSchema.virtual('id').get(function() { 20 | return this._id.toHexString(); 21 | }); 22 | 23 | SettingsSchema.set('toJSON', { 24 | getters: true, 25 | }); 26 | 27 | SettingsSchema.set('toObject', { 28 | getters: true, 29 | }); 30 | 31 | const Settings = database.model('settings', SettingsSchema); 32 | 33 | module.exports = Settings; 34 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/emails/emailAddressVerificationEmail.js: -------------------------------------------------------------------------------- 1 | const { i18n } = require('../i18n'); 2 | 3 | module.exports = class EmailAddressVerificationEmail { 4 | constructor(language, to, link) { 5 | this.language = language; 6 | this.to = to; 7 | this.link = link; 8 | } 9 | 10 | get subject() { 11 | return i18n( 12 | this.language, 13 | 'emails.emailAddressVerification.subject', 14 | i18n(this.language, 'app.title'), 15 | ); 16 | } 17 | 18 | get html() { 19 | return i18n( 20 | this.language, 21 | 'emails.emailAddressVerification.body', 22 | this.link, 23 | i18n(this.language, 'app.title'), 24 | ); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/emails/invitationEmail.js: -------------------------------------------------------------------------------- 1 | const config = require('../../config')(); 2 | const { i18n } = require('../i18n'); 3 | 4 | module.exports = class InvitationEmail { 5 | constructor(language, to) { 6 | this.language = language; 7 | this.to = to; 8 | } 9 | 10 | get subject() { 11 | return i18n( 12 | this.language, 13 | 'emails.invitation.subject', 14 | i18n(this.language, 'app.title'), 15 | ); 16 | } 17 | 18 | get html() { 19 | return i18n( 20 | this.language, 21 | 'emails.invitation.body', 22 | i18n(this.language, 'app.title'), 23 | `${config.clientUrl}/auth/signup?email=${ 24 | this.to 25 | }`, 26 | ); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/emails/passwordResetEmail.js: -------------------------------------------------------------------------------- 1 | const { i18n } = require('../i18n'); 2 | 3 | module.exports = class PasswordResetEmail { 4 | constructor(language, to, link) { 5 | this.language = language; 6 | this.to = to; 7 | this.link = link; 8 | } 9 | 10 | get subject() { 11 | return i18n( 12 | this.language, 13 | 'emails.passwordReset.subject', 14 | i18n(this.language, 'app.title'), 15 | ); 16 | } 17 | 18 | get html() { 19 | return i18n( 20 | this.language, 21 | 'emails.passwordReset.body', 22 | i18n(this.language, 'app.title'), 23 | this.to, 24 | this.link, 25 | ); 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/errors/forbiddenError.js: -------------------------------------------------------------------------------- 1 | const { i18n, i18nExists } = require('..//i18n'); 2 | 3 | module.exports = class ForbiddenError extends Error { 4 | constructor(language, messageCode) { 5 | let message; 6 | 7 | if (messageCode && i18nExists(language, messageCode)) { 8 | message = i18n(language, messageCode); 9 | } 10 | 11 | message = 12 | message || i18n(language, 'errors.forbidden.message'); 13 | 14 | super(message); 15 | this.code = 403; 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/errors/validationError.js: -------------------------------------------------------------------------------- 1 | const { i18n, i18nExists } = require('..//i18n'); 2 | 3 | module.exports = class ValidationError extends Error { 4 | constructor(language, messageCode) { 5 | let message; 6 | 7 | if (messageCode && i18nExists(language, messageCode)) { 8 | message = i18n(language, messageCode); 9 | } 10 | 11 | message = 12 | message || 13 | i18n(language, 'errors.validation.message'); 14 | 15 | super(message); 16 | this.code = 400; 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/external/nodemailer.js: -------------------------------------------------------------------------------- 1 | module.exports = () => { 2 | const isTest = process.env.NODE_ENV === 'test'; 3 | if (isTest) { 4 | return require('../__mocks__/nodemailer'); 5 | } 6 | 7 | return require('nodemailer'); 8 | }; 9 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/i18n/index.js: -------------------------------------------------------------------------------- 1 | const en = require('./en'); 2 | const ptBR = require('./pt-BR'); 3 | const _get = require('lodash/get'); 4 | 5 | const languages = { 6 | en: en, 7 | 'pt-BR': ptBR, 8 | }; 9 | 10 | function format(message, args) { 11 | if (!message) { 12 | return null; 13 | } 14 | 15 | return message.replace(/{(\d+)}/g, function( 16 | match, 17 | number, 18 | ) { 19 | return typeof args[number] != 'undefined' 20 | ? args[number] 21 | : match; 22 | }); 23 | } 24 | 25 | const i18nExists = (languageCode, key) => { 26 | const message = _get(languages[languageCode], key); 27 | return !!message; 28 | }; 29 | 30 | const i18n = (languageCode, key, ...args) => { 31 | const message = _get(languages[languageCode], key); 32 | 33 | if (!message) { 34 | return key; 35 | } 36 | 37 | return format(message, args); 38 | }; 39 | 40 | exports.i18n = i18n; 41 | exports.i18nExists = i18nExists; 42 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/security/roles.js: -------------------------------------------------------------------------------- 1 | class Roles { 2 | static get values() { 3 | return { 4 | owner: 'owner', 5 | editor: 'editor', 6 | viewer: 'viewer', 7 | auditLogViewer: 'auditLogViewer', 8 | iamSecurityReviewer: 'iamSecurityReviewer', 9 | entityEditor: 'entityEditor', 10 | entityViewer: 'entityViewer', 11 | loanEditor: 'loanEditor', 12 | loanViewer: 'loanViewer', 13 | bookEditor: 'bookEditor', 14 | bookViewer: 'bookViewer', 15 | }; 16 | } 17 | } 18 | 19 | module.exports = Roles; 20 | -------------------------------------------------------------------------------- /1-Project/backend-mongodb/src/services/settingsService.js: -------------------------------------------------------------------------------- 1 | const SettingsRepository = require('../database/repositories/settingsRepository'); 2 | 3 | const DEFAULT_SETTINGS = { 4 | id: 'default', 5 | theme: 'default', 6 | }; 7 | 8 | class SettingsService { 9 | static async findOrCreateDefault(currentUser) { 10 | return SettingsRepository.findOrCreateDefault( 11 | DEFAULT_SETTINGS, 12 | { currentUser }, 13 | ); 14 | } 15 | 16 | static async save(data, currentUser) { 17 | const session = await SettingsRepository.createSession(); 18 | 19 | const settings = await SettingsRepository.save(data, { 20 | currentUser, 21 | session, 22 | }); 23 | 24 | await SettingsRepository.commitTransaction(session); 25 | 26 | return settings; 27 | } 28 | } 29 | 30 | module.exports = SettingsService; 31 | -------------------------------------------------------------------------------- /1-Project/backend-sql/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | /service-accounts/*.json 3 | /data -------------------------------------------------------------------------------- /1-Project/backend-sql/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "arrowParens": "always", 4 | "printWidth": 60, 5 | "trailingComma": "all" 6 | } 7 | -------------------------------------------------------------------------------- /1-Project/backend-sql/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "env": { "NODE_ENV": "localhost" }, 12 | "program": "${workspaceFolder}/server.js" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /1-Project/backend-sql/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.colorCustomizations": { 3 | "titleBar.activeForeground": "#000", 4 | "titleBar.inactiveForeground": "#000000CC", 5 | "titleBar.activeBackground": "#eb2568", 6 | "titleBar.inactiveBackground": "#eb2568CC" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /1-Project/backend-sql/config/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function get() { 2 | const isMigration = !!process.env.MIGRATION_ENV; 3 | 4 | if (isMigration) { 5 | const config = require(`./${ 6 | process.env.MIGRATION_ENV 7 | }`); 8 | 9 | return config; 10 | } 11 | 12 | return require(`./${process.env.NODE_ENV}`); 13 | }; 14 | -------------------------------------------------------------------------------- /1-Project/backend-sql/config/test.js: -------------------------------------------------------------------------------- 1 | const os = require('os'); 2 | 3 | module.exports = { 4 | env: 'test', 5 | 6 | database: { 7 | dialect: 'sqlite', 8 | storage: ':memory:', 9 | logging: false, 10 | operatorsAliases: false, 11 | }, 12 | 13 | email: { 14 | auth: { 15 | user: 'mock', 16 | }, 17 | }, 18 | 19 | graphiql: false, 20 | 21 | clientUrl: '', 22 | 23 | defaultUser: '', 24 | 25 | uploadDir: os.tmpdir(), 26 | 27 | authJwtSecret: '', 28 | }; 29 | -------------------------------------------------------------------------------- /1-Project/backend-sql/migrations/reset.js: -------------------------------------------------------------------------------- 1 | const models = require('../src/database/models'); 2 | 3 | console.log(`Reseting ${process.env.MIGRATION_ENV}...`); 4 | 5 | models.sequelize 6 | .sync({ force: true }) 7 | .then(() => { 8 | console.log('OK'); 9 | process.exit(); 10 | }) 11 | .catch((error) => { 12 | console.error(error); 13 | process.exit(1); 14 | }); 15 | -------------------------------------------------------------------------------- /1-Project/backend-sql/server.js: -------------------------------------------------------------------------------- 1 | const api = require('./src/api'); 2 | 3 | const PORT = process.env.PORT || 8080; 4 | 5 | api.listen(PORT, () => { 6 | console.log(`Listening on port ${PORT}`); 7 | }); 8 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/__fixtures__/bookFixture.js: -------------------------------------------------------------------------------- 1 | const genericFixture = require('./genericFixture'); 2 | const BookRepository = require('../database/repositories/bookRepository'); 3 | 4 | const bookFixture = genericFixture({ 5 | idField: 'id', 6 | createFn: (data) => new BookRepository().create(data), 7 | data: [ 8 | { 9 | id: '1', 10 | // Add attributes here 11 | }, 12 | ], 13 | }); 14 | 15 | module.exports = bookFixture; 16 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/__fixtures__/genericFixture.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ createFn, data, idField = 'id' }) => ({ 2 | buildAll() { 3 | return JSON.parse(JSON.stringify(data)); 4 | }, 5 | 6 | build(id, overrides) { 7 | const item = this.buildAll().find( 8 | (item) => item[idField] === id, 9 | ); 10 | 11 | if (!item) { 12 | throw new Error(`Not found fixture with id: ${id}.`); 13 | } 14 | 15 | return { 16 | ...item, 17 | ...overrides, 18 | }; 19 | }, 20 | 21 | async createAll() { 22 | const items = []; 23 | 24 | for (let item of this.buildAll()) { 25 | items.push(await this.create(item.id)); 26 | } 27 | 28 | return items; 29 | }, 30 | 31 | async create(id, overrides) { 32 | const item = this.build(id, overrides); 33 | 34 | if (!createFn) { 35 | return item; 36 | } 37 | 38 | return createFn(item); 39 | }, 40 | }); 41 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/__fixtures__/index.js: -------------------------------------------------------------------------------- 1 | const userFixture = require('./userFixture'); 2 | const loanFixture = require('./loanFixture'); 3 | const bookFixture = require('./bookFixture'); 4 | const AbstractRepository = require('../database/repositories/abstractRepository'); 5 | 6 | module.exports = { 7 | user: userFixture, 8 | loan: loanFixture, 9 | book: bookFixture, 10 | 11 | async cleanDatabase() { 12 | await AbstractRepository.cleanDatabase(); 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/__fixtures__/loanFixture.js: -------------------------------------------------------------------------------- 1 | const genericFixture = require('./genericFixture'); 2 | const LoanRepository = require('../database/repositories/loanRepository'); 3 | 4 | const loanFixture = genericFixture({ 5 | idField: 'id', 6 | createFn: (data) => new LoanRepository().create(data), 7 | data: [ 8 | { 9 | id: '1', 10 | // Add attributes here 11 | }, 12 | ], 13 | }); 14 | 15 | module.exports = loanFixture; 16 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/__mocks__/nodemailer.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | createTransport() { 3 | return { 4 | sendMail: () => {}, 5 | }; 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/auditLog/auditLogList.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const AuditLogRepository = require('../../database/repositories/auditLogRepository'); 3 | const permissions = require('../../security/permissions') 4 | .values; 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.auditLogRead, 10 | ); 11 | 12 | const payload = await AuditLogRepository.findAndCountAll( 13 | req.query, 14 | ); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/auditLog/index.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | app.get(`/auditLog`, require('./auditLogList')); 3 | }; 4 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/auth/authIsEmailConfigured.js: -------------------------------------------------------------------------------- 1 | const EmailSender = require('../../services/shared/email/emailSender'); 2 | 3 | module.exports = (req, res) => { 4 | try { 5 | const payload = EmailSender.isConfigured; 6 | 7 | res.status(200).send(payload); 8 | } catch (error) { 9 | if ([400, 403, 404].includes(error.code)) { 10 | return res.status(error.code).send(error.message); 11 | } 12 | 13 | console.error(error); 14 | return res.status(500).send(error.message); 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/auth/authMe.js: -------------------------------------------------------------------------------- 1 | const ForbiddenError = require('../../errors/forbiddenError'); 2 | 3 | module.exports = (req, res) => { 4 | try { 5 | if (!req.currentUser || !req.currentUser.id) { 6 | throw new ForbiddenError(req.language); 7 | } 8 | 9 | const payload = req.currentUser; 10 | 11 | res.status(200).send(payload); 12 | } catch (error) { 13 | if ([400, 403, 404].includes(error.code)) { 14 | return res.status(error.code).send(error.message); 15 | } 16 | 17 | console.error(error); 18 | return res.status(500).send(error.message); 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/auth/authPasswordReset.js: -------------------------------------------------------------------------------- 1 | const AuthService = require('../../services/auth/authService'); 2 | 3 | module.exports = async (req, res) => { 4 | try { 5 | const payload = await AuthService.passwordReset( 6 | req.body.token, 7 | req.body.password, 8 | req, 9 | ); 10 | 11 | res.status(200).send(payload); 12 | } catch (error) { 13 | if ([400, 403, 404].includes(error.code)) { 14 | return res.status(error.code).send(error.message); 15 | } 16 | 17 | console.error(error); 18 | return res.status(500).send(error.message); 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/auth/authSendEmailAddressVerificationEmail.js: -------------------------------------------------------------------------------- 1 | const ForbiddenError = require('../../errors/forbiddenError'); 2 | const AuthService = require('../../services/auth/authService'); 3 | 4 | module.exports = async (req, res) => { 5 | try { 6 | if (!req.currentUser) { 7 | throw new ForbiddenError(req.language); 8 | } 9 | 10 | await AuthService.sendEmailAddressVerificationEmail( 11 | req.language, 12 | req.currentUser.email, 13 | ); 14 | 15 | const payload = true; 16 | 17 | res.status(200).send(payload); 18 | } catch (error) { 19 | if ([400, 403, 404].includes(error.code)) { 20 | return res.status(error.code).send(error.message); 21 | } 22 | 23 | console.error(error); 24 | return res.status(500).send(error.message); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/auth/authSendPasswordResetEmail.js: -------------------------------------------------------------------------------- 1 | const AuthService = require('../../services/auth/authService'); 2 | 3 | module.exports = async (req, res) => { 4 | try { 5 | await AuthService.sendPasswordResetEmail( 6 | req.language, 7 | req.body.email, 8 | ); 9 | 10 | const payload = true; 11 | 12 | res.status(200).send(payload); 13 | } catch (error) { 14 | if ([400, 403, 404].includes(error.code)) { 15 | return res.status(error.code).send(error.message); 16 | } 17 | 18 | console.error(error); 19 | return res.status(500).send(error.message); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/auth/authSignIn.js: -------------------------------------------------------------------------------- 1 | const AuthService = require('../../services/auth/authService'); 2 | 3 | module.exports = async (req, res) => { 4 | try { 5 | const payload = await AuthService.signin( 6 | req.body.email, 7 | req.body.password, 8 | req, 9 | ); 10 | 11 | res.status(200).send(payload); 12 | } catch (error) { 13 | if ([400, 403, 404].includes(error.code)) { 14 | return res.status(error.code).send(error.message); 15 | } 16 | 17 | console.error(error); 18 | return res.status(500).send(error.message); 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/auth/authSignUp.js: -------------------------------------------------------------------------------- 1 | const AuthService = require('../../services/auth/authService'); 2 | 3 | module.exports = async (req, res) => { 4 | try { 5 | const payload = await AuthService.signup( 6 | req.body.email, 7 | req.body.password, 8 | req, 9 | ); 10 | 11 | res.status(200).send(payload); 12 | } catch (error) { 13 | if ([400, 403, 404].includes(error.code)) { 14 | return res.status(error.code).send(error.message); 15 | } 16 | 17 | console.error(error); 18 | return res.status(500).send(error.message); 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/auth/authUpdateProfile.js: -------------------------------------------------------------------------------- 1 | const AuthProfileEditor = require('../../services/auth/authProfileEditor'); 2 | const ForbiddenError = require('../../errors/forbiddenError'); 3 | 4 | module.exports = async (req, res) => { 5 | try { 6 | if (!req.currentUser || !req.currentUser.id) { 7 | throw new ForbiddenError(req.language); 8 | } 9 | 10 | let editor = new AuthProfileEditor( 11 | req.currentUser, 12 | req.language, 13 | ); 14 | 15 | await editor.execute(req.body.profile); 16 | 17 | const payload = true; 18 | 19 | res.status(200).send(payload); 20 | } catch (error) { 21 | if ([400, 403, 404].includes(error.code)) { 22 | return res.status(error.code).send(error.message); 23 | } 24 | 25 | console.error(error); 26 | return res.status(500).send(error.message); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/auth/authVerifyEmail.js: -------------------------------------------------------------------------------- 1 | const AuthService = require('../../services/auth/authService'); 2 | 3 | module.exports = async (req, res) => { 4 | try { 5 | const payload = await AuthService.verifyEmail( 6 | req.body.token, 7 | req, 8 | ); 9 | 10 | res.status(200).send(payload); 11 | } catch (error) { 12 | if ([400, 403, 404].includes(error.code)) { 13 | return res.status(error.code).send(error.message); 14 | } 15 | 16 | console.error(error); 17 | return res.status(500).send(error.message); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/auth/index.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | app.put( 3 | `/auth/password-reset`, 4 | require('./authPasswordReset'), 5 | ); 6 | 7 | app.post( 8 | `/auth/send-email-address-verification-email`, 9 | require('./authSendEmailAddressVerificationEmail'), 10 | ); 11 | 12 | app.post( 13 | `/auth/send-password-reset-email`, 14 | require('./authSendPasswordResetEmail'), 15 | ); 16 | 17 | app.post(`/auth/sign-in`, require('./authSignIn')); 18 | 19 | app.post(`/auth/sign-up`, require('./authSignUp')); 20 | 21 | app.put(`/auth/profile`, require('./authUpdateProfile')); 22 | 23 | app.put( 24 | `/auth/verify-email`, 25 | require('./authVerifyEmail'), 26 | ); 27 | 28 | app.get(`/auth/me`, require('./authMe')); 29 | 30 | app.get( 31 | `/auth/email-configured`, 32 | require('./authIsEmailConfigured'), 33 | ); 34 | }; 35 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/book/bookAutocomplete.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const BookService = require('../../services/bookService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.bookAutocomplete, 10 | ); 11 | 12 | const payload = await new BookService( 13 | req, 14 | ).findAllAutocomplete(req.query.query, req.query.limit); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/book/bookCreate.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const BookService = require('../../services/bookService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.bookCreate, 10 | ); 11 | 12 | const payload = await new BookService(req).create( 13 | req.body.data, 14 | ); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/book/bookDestroy.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const BookService = require('../../services/bookService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.bookDestroy, 10 | ); 11 | 12 | await new BookService(req).destroyAll( 13 | req.query.ids, 14 | ); 15 | 16 | const payload = true; 17 | 18 | res.status(200).send(payload); 19 | } catch (error) { 20 | if ([400, 403, 404].includes(error.code)) { 21 | return res.status(error.code).send(error.message); 22 | } 23 | 24 | console.error(error); 25 | return res.status(500).send(error.message); 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/book/bookFind.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const BookService = require('../../services/bookService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.bookRead, 10 | ); 11 | 12 | const payload = await new BookService(req).findById( 13 | req.params.id, 14 | ); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/book/bookImport.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const BookService = require('../../services/bookService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.bookImport, 10 | ); 11 | 12 | await new BookService(req).import( 13 | req.body.data, 14 | req.body.importHash, 15 | ); 16 | 17 | const payload = true; 18 | 19 | res.status(200).send(payload); 20 | } catch (error) { 21 | if ([400, 403, 404].includes(error.code)) { 22 | return res.status(error.code).send(error.message); 23 | } 24 | 25 | console.error(error); 26 | return res.status(500).send(error.message); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/book/bookList.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const BookService = require('../../services/bookService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.bookRead, 10 | ); 11 | 12 | const payload = await new BookService( 13 | req, 14 | ).findAndCountAll(req.query); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/book/bookUpdate.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const BookService = require('../../services/bookService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.bookEdit, 10 | ); 11 | 12 | const payload = await new BookService(req).update( 13 | req.body.id, 14 | req.body.data, 15 | ); 16 | 17 | res.status(200).send(payload); 18 | } catch (error) { 19 | if ([400, 403, 404].includes(error.code)) { 20 | return res.status(error.code).send(error.message); 21 | } 22 | 23 | console.error(error); 24 | return res.status(500).send(error.message); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/book/index.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | app.post(`/book`, require('./bookCreate')); 3 | app.put(`/book/:id`, require('./bookUpdate')); 4 | app.post(`/book/import`, require('./bookImport')); 5 | app.delete(`/book`, require('./bookDestroy')); 6 | app.get( 7 | `/book/autocomplete`, 8 | require('./bookAutocomplete'), 9 | ); 10 | app.get(`/book`, require('./bookList')); 11 | app.get(`/book/:id`, require('./bookFind')); 12 | }; 13 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/file/download.js: -------------------------------------------------------------------------------- 1 | const config = require('../../../config')(); 2 | const path = require('path'); 3 | 4 | module.exports = (req, res) => { 5 | const privateUrl = req.query.privateUrl; 6 | 7 | if (!privateUrl) { 8 | return res.sendStatus(404); 9 | } 10 | 11 | res.download(path.join(config.uploadDir, privateUrl)); 12 | }; 13 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/file/index.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | const upload = require('./upload'); 3 | upload.mapAllUploadRequests(app); 4 | 5 | app.get(`/download`, require('./download')); 6 | }; 7 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/iam/iamChangeStatus.js: -------------------------------------------------------------------------------- 1 | const IamStatusChanger = require('../../services/iam/iamStatusChanger'); 2 | const PermissionChecker = require('../../services/iam/permissionChecker'); 3 | const permissions = require('../../security/permissions') 4 | .values; 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.iamEdit, 10 | ); 11 | 12 | let statusChanger = new IamStatusChanger( 13 | req.currentUser, 14 | req.language, 15 | ); 16 | 17 | await statusChanger.changeStatus(req.body); 18 | 19 | const payload = true; 20 | 21 | res.status(200).send(payload); 22 | } catch (error) { 23 | if ([400, 403, 404].includes(error.code)) { 24 | return res.status(error.code).send(error.message); 25 | } 26 | 27 | console.error(error); 28 | return res.status(500).send(error.message); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/iam/iamCreate.js: -------------------------------------------------------------------------------- 1 | const IamCreator = require('../../services/iam/iamCreator'); 2 | const PermissionChecker = require('../../services/iam/permissionChecker'); 3 | const permissions = require('../../security/permissions') 4 | .values; 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.iamCreate, 10 | ); 11 | 12 | let creator = new IamCreator( 13 | req.currentUser, 14 | req.language, 15 | ); 16 | 17 | await creator.execute(req.body.data); 18 | 19 | const payload = true; 20 | 21 | res.status(200).send(payload); 22 | } catch (error) { 23 | if ([400, 403, 404].includes(error.code)) { 24 | return res.status(error.code).send(error.message); 25 | } 26 | 27 | console.error(error); 28 | return res.status(500).send(error.message); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/iam/iamEdit.js: -------------------------------------------------------------------------------- 1 | const IamEditor = require('../../services/iam/iamEditor'); 2 | const PermissionChecker = require('../../services/iam/permissionChecker'); 3 | const permissions = require('../../security/permissions') 4 | .values; 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.iamEdit, 10 | ); 11 | 12 | let editor = new IamEditor( 13 | req.currentUser, 14 | req.language, 15 | ); 16 | 17 | await editor.update(req.body.data); 18 | 19 | const payload = true; 20 | 21 | res.status(200).send(payload); 22 | } catch (error) { 23 | if ([400, 403, 404].includes(error.code)) { 24 | return res.status(error.code).send(error.message); 25 | } 26 | 27 | console.error(error); 28 | return res.status(500).send(error.message); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/iam/iamFind.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const UserRepository = require('../../database/repositories/userRepository'); 3 | const permissions = require('../../security/permissions') 4 | .values; 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.iamRead, 10 | ); 11 | 12 | const payload = await UserRepository.findById( 13 | req.params.id, 14 | ); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/iam/iamImport.js: -------------------------------------------------------------------------------- 1 | const IamImporter = require('../../services/iam/iamImporter'); 2 | const PermissionChecker = require('../../services/iam/permissionChecker'); 3 | const permissions = require('../../security/permissions') 4 | .values; 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.iamImport, 10 | ); 11 | 12 | await new IamImporter( 13 | req.currentUser, 14 | req.language, 15 | ).import(req.body.data, req.body.importHash); 16 | 17 | const payload = true; 18 | 19 | res.status(200).send(payload); 20 | } catch (error) { 21 | if ([400, 403, 404].includes(error.code)) { 22 | return res.status(error.code).send(error.message); 23 | } 24 | 25 | console.error(error); 26 | return res.status(500).send(error.message); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/iam/iamListRoles.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const UserRoleRepository = require('../../database/repositories/userRoleRepository'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.iamRead, 10 | ); 11 | 12 | const payload = await UserRoleRepository.findAllWithUsers( 13 | req.query, 14 | ); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/iam/iamListUsers.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const UserRepository = require('../../database/repositories/userRepository'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.iamRead, 10 | ); 11 | 12 | const payload = await UserRepository.findAllWithCount( 13 | req.query, 14 | ); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/iam/iamRemove.js: -------------------------------------------------------------------------------- 1 | const IamRemover = require('../../services/iam/iamRemover'); 2 | const PermissionChecker = require('../../services/iam/permissionChecker'); 3 | const permissions = require('../../security/permissions') 4 | .values; 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.iamEdit, 10 | ); 11 | 12 | let remover = new IamRemover( 13 | req.currentUser, 14 | req.language, 15 | ); 16 | 17 | await remover.removeAll(req.query); 18 | 19 | const payload = true; 20 | 21 | res.status(200).send(payload); 22 | } catch (error) { 23 | if ([400, 403, 404].includes(error.code)) { 24 | return res.status(error.code).send(error.message); 25 | } 26 | 27 | console.error(error); 28 | return res.status(500).send(error.message); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/iam/iamUserAutocomplete.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const UserRepository = require('../../database/repositories/userRepository'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.iamUserAutocomplete, 10 | ); 11 | 12 | const payload = await UserRepository.findAllAutocomplete( 13 | req.query.query, 14 | req.query.limit, 15 | ); 16 | 17 | res.status(200).send(payload); 18 | } catch (error) { 19 | if ([400, 403, 404].includes(error.code)) { 20 | return res.status(error.code).send(error.message); 21 | } 22 | 23 | console.error(error); 24 | return res.status(500).send(error.message); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/iam/index.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | app.put(`/iam/status`, require('./iamChangeStatus')); 3 | app.post(`/iam`, require('./iamCreate')); 4 | app.put(`/iam`, require('./iamEdit')); 5 | app.post(`/iam/import`, require('./iamImport')); 6 | app.delete(`/iam`, require('./iamRemove')); 7 | app.get(`/iam/role`, require('./iamListRoles')); 8 | app.get(`/iam/user`, require('./iamListUsers')); 9 | app.get( 10 | `/iam/user/autocomplete`, 11 | require('./iamUserAutocomplete'), 12 | ); 13 | app.get(`/iam/:id`, require('./iamFind')); 14 | }; 15 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/loan/index.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | app.post(`/loan`, require('./loanCreate')); 3 | app.put(`/loan/:id`, require('./loanUpdate')); 4 | app.post(`/loan/import`, require('./loanImport')); 5 | app.delete(`/loan`, require('./loanDestroy')); 6 | app.get( 7 | `/loan/autocomplete`, 8 | require('./loanAutocomplete'), 9 | ); 10 | app.get(`/loan`, require('./loanList')); 11 | app.get(`/loan/:id`, require('./loanFind')); 12 | }; 13 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/loan/loanAutocomplete.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const LoanService = require('../../services/loanService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.loanAutocomplete, 10 | ); 11 | 12 | const payload = await new LoanService( 13 | req, 14 | ).findAllAutocomplete(req.query.query, req.query.limit); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/loan/loanCreate.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const LoanService = require('../../services/loanService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.loanCreate, 10 | ); 11 | 12 | const payload = await new LoanService(req).create( 13 | req.body.data, 14 | ); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/loan/loanDestroy.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const LoanService = require('../../services/loanService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.loanDestroy, 10 | ); 11 | 12 | await new LoanService(req).destroyAll( 13 | req.query.ids, 14 | ); 15 | 16 | const payload = true; 17 | 18 | res.status(200).send(payload); 19 | } catch (error) { 20 | if ([400, 403, 404].includes(error.code)) { 21 | return res.status(error.code).send(error.message); 22 | } 23 | 24 | console.error(error); 25 | return res.status(500).send(error.message); 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/loan/loanFind.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const LoanService = require('../../services/loanService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.loanRead, 10 | ); 11 | 12 | const payload = await new LoanService(req).findById( 13 | req.params.id, 14 | ); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/loan/loanImport.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const LoanService = require('../../services/loanService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.loanImport, 10 | ); 11 | 12 | await new LoanService(req).import( 13 | req.body.data, 14 | req.body.importHash, 15 | ); 16 | 17 | const payload = true; 18 | 19 | res.status(200).send(payload); 20 | } catch (error) { 21 | if ([400, 403, 404].includes(error.code)) { 22 | return res.status(error.code).send(error.message); 23 | } 24 | 25 | console.error(error); 26 | return res.status(500).send(error.message); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/loan/loanList.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const LoanService = require('../../services/loanService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.loanRead, 10 | ); 11 | 12 | const payload = await new LoanService( 13 | req, 14 | ).findAndCountAll(req.query); 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/loan/loanUpdate.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const LoanService = require('../../services/loanService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.loanEdit, 10 | ); 11 | 12 | const payload = await new LoanService(req).update( 13 | req.body.id, 14 | req.body.data, 15 | ); 16 | 17 | res.status(200).send(payload); 18 | } catch (error) { 19 | if ([400, 403, 404].includes(error.code)) { 20 | return res.status(error.code).send(error.message); 21 | } 22 | 23 | console.error(error); 24 | return res.status(500).send(error.message); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/settings/index.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | app.put(`/settings`, require('./settingsSave')); 3 | app.get(`/settings`, require('./settingsFind')); 4 | }; 5 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/settings/settingsFind.js: -------------------------------------------------------------------------------- 1 | const SettingsService = require('../../services/settingsService'); 2 | 3 | module.exports = async (req, res) => { 4 | try { 5 | const payload = await SettingsService.findOrCreateDefault( 6 | req.currentUser, 7 | ); 8 | 9 | res.status(200).send(payload); 10 | } catch (error) { 11 | if ([400, 403, 404].includes(error.code)) { 12 | return res.status(error.code).send(error.message); 13 | } 14 | 15 | console.error(error); 16 | return res.status(500).send(error.message); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/api/settings/settingsSave.js: -------------------------------------------------------------------------------- 1 | const SettingsService = require('../../services/settingsService'); 2 | const PermissionChecker = require('../../services/iam/permissionChecker'); 3 | const permissions = require('../../security/permissions') 4 | .values; 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.settingsEdit, 10 | ); 11 | 12 | const payload = await SettingsService.save( 13 | req.body.settings, 14 | req.currentUser, 15 | ); 16 | 17 | res.status(200).send(payload); 18 | } catch (error) { 19 | if ([400, 403, 404].includes(error.code)) { 20 | return res.status(error.code).send(error.message); 21 | } 22 | 23 | console.error(error); 24 | return res.status(500).send(error.message); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/database/database.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/1-Project/backend-sql/src/database/database.js -------------------------------------------------------------------------------- /1-Project/backend-sql/src/database/databaseInit.js: -------------------------------------------------------------------------------- 1 | const init = async () => { 2 | return; 3 | }; 4 | 5 | const middleware = async (req, res, next) => { 6 | return next(); 7 | }; 8 | 9 | exports.init = init; 10 | exports.middleware = middleware; 11 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/database/models/settings.js: -------------------------------------------------------------------------------- 1 | module.exports = function(sequelize, DataTypes) { 2 | const settings = sequelize.define( 3 | 'settings', 4 | { 5 | id: { 6 | type: DataTypes.STRING, 7 | defaultValue: 'default', 8 | primaryKey: true, 9 | }, 10 | theme: { 11 | type: DataTypes.STRING(255), 12 | allowNull: false, 13 | }, 14 | }, 15 | { 16 | timestamps: true, 17 | paranoid: true, 18 | }, 19 | ); 20 | 21 | settings.associate = (models) => { 22 | models.settings.belongsTo(models.user, { 23 | as: 'createdBy', 24 | }); 25 | 26 | models.settings.belongsTo(models.user, { 27 | as: 'updatedBy', 28 | }); 29 | }; 30 | 31 | return settings; 32 | }; 33 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/database/models/userRole.js: -------------------------------------------------------------------------------- 1 | module.exports = function(sequelize, DataTypes) { 2 | const userRole = sequelize.define( 3 | 'userRole', 4 | { 5 | id: { 6 | type: DataTypes.UUID, 7 | defaultValue: DataTypes.UUIDV4, 8 | primaryKey: true, 9 | }, 10 | role: { 11 | type: DataTypes.STRING, 12 | allowNull: false, 13 | validate: { 14 | notEmpty: true, 15 | }, 16 | }, 17 | }, 18 | { 19 | timestamps: true, 20 | paranoid: true, 21 | }, 22 | ); 23 | 24 | userRole.associate = (models) => { 25 | models.userRole.belongsTo(models.user); 26 | 27 | models.userRole.belongsTo(models.user, { 28 | as: 'createdBy', 29 | }); 30 | 31 | models.userRole.belongsTo(models.user, { 32 | as: 'updatedBy', 33 | }); 34 | }; 35 | 36 | return userRole; 37 | }; 38 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/emails/emailAddressVerificationEmail.js: -------------------------------------------------------------------------------- 1 | const { i18n } = require('../i18n'); 2 | 3 | module.exports = class EmailAddressVerificationEmail { 4 | constructor(language, to, link) { 5 | this.language = language; 6 | this.to = to; 7 | this.link = link; 8 | } 9 | 10 | get subject() { 11 | return i18n( 12 | this.language, 13 | 'emails.emailAddressVerification.subject', 14 | i18n(this.language, 'app.title'), 15 | ); 16 | } 17 | 18 | get html() { 19 | return i18n( 20 | this.language, 21 | 'emails.emailAddressVerification.body', 22 | this.link, 23 | i18n(this.language, 'app.title'), 24 | ); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/emails/invitationEmail.js: -------------------------------------------------------------------------------- 1 | const config = require('../../config')(); 2 | const { i18n } = require('../i18n'); 3 | 4 | module.exports = class InvitationEmail { 5 | constructor(language, to) { 6 | this.language = language; 7 | this.to = to; 8 | } 9 | 10 | get subject() { 11 | return i18n( 12 | this.language, 13 | 'emails.invitation.subject', 14 | i18n(this.language, 'app.title'), 15 | ); 16 | } 17 | 18 | get html() { 19 | return i18n( 20 | this.language, 21 | 'emails.invitation.body', 22 | i18n(this.language, 'app.title'), 23 | `${config.clientUrl}/auth/signup?email=${ 24 | this.to 25 | }`, 26 | ); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/emails/passwordResetEmail.js: -------------------------------------------------------------------------------- 1 | const { i18n } = require('../i18n'); 2 | 3 | module.exports = class PasswordResetEmail { 4 | constructor(language, to, link) { 5 | this.language = language; 6 | this.to = to; 7 | this.link = link; 8 | } 9 | 10 | get subject() { 11 | return i18n( 12 | this.language, 13 | 'emails.passwordReset.subject', 14 | i18n(this.language, 'app.title'), 15 | ); 16 | } 17 | 18 | get html() { 19 | return i18n( 20 | this.language, 21 | 'emails.passwordReset.body', 22 | i18n(this.language, 'app.title'), 23 | this.to, 24 | this.link, 25 | ); 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/errors/forbiddenError.js: -------------------------------------------------------------------------------- 1 | const { i18n, i18nExists } = require('..//i18n'); 2 | 3 | module.exports = class ForbiddenError extends Error { 4 | constructor(language, messageCode) { 5 | let message; 6 | 7 | if (messageCode && i18nExists(language, messageCode)) { 8 | message = i18n(language, messageCode); 9 | } 10 | 11 | message = 12 | message || i18n(language, 'errors.forbidden.message'); 13 | 14 | super(message); 15 | this.code = 403; 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/errors/validationError.js: -------------------------------------------------------------------------------- 1 | const { i18n, i18nExists } = require('..//i18n'); 2 | 3 | module.exports = class ValidationError extends Error { 4 | constructor(language, messageCode) { 5 | let message; 6 | 7 | if (messageCode && i18nExists(language, messageCode)) { 8 | message = i18n(language, messageCode); 9 | } 10 | 11 | message = 12 | message || 13 | i18n(language, 'errors.validation.message'); 14 | 15 | super(message); 16 | this.code = 400; 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/external/nodemailer.js: -------------------------------------------------------------------------------- 1 | module.exports = () => { 2 | const isTest = process.env.NODE_ENV === 'test'; 3 | if (isTest) { 4 | return require('../__mocks__/nodemailer'); 5 | } 6 | 7 | return require('nodemailer'); 8 | }; 9 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/i18n/index.js: -------------------------------------------------------------------------------- 1 | const en = require('./en'); 2 | const ptBR = require('./pt-BR'); 3 | const _get = require('lodash/get'); 4 | 5 | const languages = { 6 | en: en, 7 | 'pt-BR': ptBR, 8 | }; 9 | 10 | function format(message, args) { 11 | if (!message) { 12 | return null; 13 | } 14 | 15 | return message.replace(/{(\d+)}/g, function( 16 | match, 17 | number, 18 | ) { 19 | return typeof args[number] != 'undefined' 20 | ? args[number] 21 | : match; 22 | }); 23 | } 24 | 25 | const i18nExists = (languageCode, key) => { 26 | const message = _get(languages[languageCode], key); 27 | return !!message; 28 | }; 29 | 30 | const i18n = (languageCode, key, ...args) => { 31 | const message = _get(languages[languageCode], key); 32 | 33 | if (!message) { 34 | return key; 35 | } 36 | 37 | return format(message, args); 38 | }; 39 | 40 | exports.i18n = i18n; 41 | exports.i18nExists = i18nExists; 42 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/security/roles.js: -------------------------------------------------------------------------------- 1 | class Roles { 2 | static get values() { 3 | return { 4 | owner: 'owner', 5 | editor: 'editor', 6 | viewer: 'viewer', 7 | auditLogViewer: 'auditLogViewer', 8 | iamSecurityReviewer: 'iamSecurityReviewer', 9 | entityEditor: 'entityEditor', 10 | entityViewer: 'entityViewer', 11 | loanEditor: 'loanEditor', 12 | loanViewer: 'loanViewer', 13 | bookEditor: 'bookEditor', 14 | bookViewer: 'bookViewer', 15 | }; 16 | } 17 | } 18 | 19 | module.exports = Roles; 20 | -------------------------------------------------------------------------------- /1-Project/backend-sql/src/services/settingsService.js: -------------------------------------------------------------------------------- 1 | const SettingsRepository = require('../database/repositories/settingsRepository'); 2 | 3 | const DEFAULT_SETTINGS = { 4 | id: 'default', 5 | theme: 'default', 6 | }; 7 | 8 | class SettingsService { 9 | static async findOrCreateDefault(currentUser) { 10 | return SettingsRepository.findOrCreateDefault( 11 | DEFAULT_SETTINGS, 12 | { currentUser }, 13 | ); 14 | } 15 | 16 | static async save(data, currentUser) { 17 | const transaction = await SettingsRepository.createTransaction(); 18 | 19 | const settings = await SettingsRepository.save(data, { 20 | currentUser, 21 | transaction, 22 | }); 23 | 24 | await SettingsRepository.commitTransaction(transaction); 25 | 26 | return settings; 27 | } 28 | } 29 | 30 | module.exports = SettingsService; 31 | -------------------------------------------------------------------------------- /1-Project/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.1' 2 | 3 | services: 4 | app: 5 | build: . 6 | ports: 7 | - '8080:8080' 8 | depends_on: 9 | - postgres 10 | volumes: 11 | - storage:/storage 12 | postgres: 13 | image: postgres 14 | restart: always 15 | ports: 16 | - '5432:5432' 17 | volumes: 18 | - data-volume:/var/lib/postgresql/data 19 | volumes: 20 | data-volume: 21 | storage: 22 | -------------------------------------------------------------------------------- /1-Project/frontend/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not ie <= 8 4 | -------------------------------------------------------------------------------- /1-Project/frontend/.env.localhost: -------------------------------------------------------------------------------- 1 | VUE_APP_ENVIRONMENT=localhost -------------------------------------------------------------------------------- /1-Project/frontend/.env.production: -------------------------------------------------------------------------------- 1 | VUE_APP_ENVIRONMENT=production -------------------------------------------------------------------------------- /1-Project/frontend/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true, 5 | }, 6 | extends: ['plugin:vue/essential', 'eslint:recommended'], 7 | rules: { 8 | 'no-console': 9 | process.env.NODE_ENV === 'production' 10 | ? 'error' 11 | : 'off', 12 | 'no-debugger': 13 | process.env.NODE_ENV === 'production' 14 | ? 'error' 15 | : 'off', 16 | }, 17 | parserOptions: { 18 | parser: 'babel-eslint', 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /1-Project/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | *.suo 17 | *.ntvs* 18 | *.njsproj 19 | *.sln 20 | *.sw* 21 | -------------------------------------------------------------------------------- /1-Project/frontend/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "arrowParens": "always", 4 | "printWidth": 60, 5 | "trailingComma": "all" 6 | } 7 | -------------------------------------------------------------------------------- /1-Project/frontend/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "javascript.updateImportsOnFileMove.enabled": "never", 3 | "javascript.preferences.importModuleSpecifier": "non-relative", 4 | "prettier.eslintIntegration": true, 5 | "workbench.colorCustomizations": { 6 | "titleBar.activeForeground": "#000", 7 | "titleBar.inactiveForeground": "#000000CC", 8 | "titleBar.activeBackground": "#ffc600", 9 | "titleBar.inactiveBackground": "#ffc600CC" 10 | }, 11 | "vetur.format.defaultFormatterOptions": { 12 | "prettyhtml": { 13 | "sortAttributes": true 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /1-Project/frontend/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['@vue/app'], 3 | }; 4 | -------------------------------------------------------------------------------- /1-Project/frontend/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["./src/**/*"], 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "paths": { 6 | "@/*": ["src/*"] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /1-Project/frontend/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | }; 6 | -------------------------------------------------------------------------------- /1-Project/frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/1-Project/frontend/public/favicon.ico -------------------------------------------------------------------------------- /1-Project/frontend/public/images/emailUnverified.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/1-Project/frontend/public/images/emailUnverified.jpg -------------------------------------------------------------------------------- /1-Project/frontend/public/images/emptyPermissions.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/1-Project/frontend/public/images/emptyPermissions.jpg -------------------------------------------------------------------------------- /1-Project/frontend/public/images/flags/16/Brazil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/1-Project/frontend/public/images/flags/16/Brazil.png -------------------------------------------------------------------------------- /1-Project/frontend/public/images/flags/16/United-States.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/1-Project/frontend/public/images/flags/16/United-States.png -------------------------------------------------------------------------------- /1-Project/frontend/public/images/flags/24/Brazil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/1-Project/frontend/public/images/flags/24/Brazil.png -------------------------------------------------------------------------------- /1-Project/frontend/public/images/flags/24/United-States.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/1-Project/frontend/public/images/flags/24/United-States.png -------------------------------------------------------------------------------- /1-Project/frontend/public/images/flags/README.md: -------------------------------------------------------------------------------- 1 | Download more flags at https://github.com/gosquared/flags/tree/master/flags/flags/flat 2 | -------------------------------------------------------------------------------- /1-Project/frontend/public/images/forgotPassword.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/1-Project/frontend/public/images/forgotPassword.jpg -------------------------------------------------------------------------------- /1-Project/frontend/public/images/signin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/1-Project/frontend/public/images/signin.jpg -------------------------------------------------------------------------------- /1-Project/frontend/public/images/signup.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/1-Project/frontend/public/images/signup.jpg -------------------------------------------------------------------------------- /1-Project/frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 16 | 17 | 18 | 19 | 26 |
27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /1-Project/frontend/public/styles/css/colors.css: -------------------------------------------------------------------------------- 1 | .bg-green { 2 | background-color: #4caf50 !important; 3 | } 4 | 5 | .text-green { 6 | color: #4caf50 !important; 7 | } 8 | 9 | .bg-red { 10 | background-color: #f44336 !important; 11 | } 12 | 13 | .text-red { 14 | color: #f44336 !important; 15 | } 16 | 17 | .text-white { 18 | color: white !important; 19 | } 20 | 21 | .text-black { 22 | color: black !important; 23 | } 24 | -------------------------------------------------------------------------------- /1-Project/frontend/public/styles/css/filter.css: -------------------------------------------------------------------------------- 1 | .filter { 2 | padding: 24px; 3 | margin-bottom: 24px; 4 | border: 1px solid rgba(0, 0, 0, 0.12); 5 | border-radius: 4px; 6 | } 7 | 8 | .filter .el-select { 9 | width: 100%; 10 | } 11 | 12 | .filter .filter-buttons { 13 | text-align: right; 14 | } 15 | 16 | .filter .filter-buttons > * { 17 | margin-left: 8px; 18 | margin-bottom: 8px; 19 | } 20 | 21 | .filter .el-date-editor--datetimerange.el-input__inner { 22 | width: 100%; 23 | } 24 | 25 | .filter .el-date-editor--daterange.el-input__inner { 26 | width: 100%; 27 | } 28 | -------------------------------------------------------------------------------- /1-Project/frontend/public/styles/css/form.css: -------------------------------------------------------------------------------- 1 | .form .form-buttons { 2 | width: 100%; 3 | margin-top: 16px; 4 | } 5 | 6 | .form .form-buttons > * { 7 | margin-right: 8px; 8 | margin-bottom: 8px; 9 | } 10 | 11 | .form .form-buttons .el-button + .el-button { 12 | margin-left: 0px; 13 | } 14 | 15 | .form .form-field { 16 | margin-top: 8px; 17 | } 18 | 19 | .form .el-input { 20 | width: 100% !important; 21 | } 22 | 23 | .form .el-input-number { 24 | width: 100% !important; 25 | } 26 | 27 | .form .el-select { 28 | width: 100%; 29 | } 30 | -------------------------------------------------------------------------------- /1-Project/frontend/public/styles/css/index.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | @import './font-awesome.custom.css'; 3 | @import './layout.css'; 4 | @import './auth.css'; 5 | @import './form.css'; 6 | @import './filter.css'; 7 | @import './errors.css'; 8 | @import './colors.css'; 9 | @import './settings.css'; 10 | @import './table.css'; 11 | @import './view.css'; 12 | -------------------------------------------------------------------------------- /1-Project/frontend/public/styles/css/table.css: -------------------------------------------------------------------------------- 1 | .el-table { 2 | width: 100%; 3 | border-radius: 5px; 4 | } 5 | 6 | .el-pagination-wrapper { 7 | width: 100%; 8 | display: flex; 9 | flex-direction: row-reverse; 10 | margin-top: 24px; 11 | } 12 | 13 | .el-table .table-actions > * { 14 | margin-right: 8px; 15 | } 16 | -------------------------------------------------------------------------------- /1-Project/frontend/public/styles/css/view.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/1-Project/frontend/public/styles/css/view.css -------------------------------------------------------------------------------- /1-Project/frontend/public/styles/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/1-Project/frontend/public/styles/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /1-Project/frontend/public/styles/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/1-Project/frontend/public/styles/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /1-Project/frontend/public/styles/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/1-Project/frontend/public/styles/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /1-Project/frontend/public/styles/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/1-Project/frontend/public/styles/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /1-Project/frontend/public/styles/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/1-Project/frontend/public/styles/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /1-Project/frontend/public/theme/fonts/element-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/1-Project/frontend/public/theme/fonts/element-icons.ttf -------------------------------------------------------------------------------- /1-Project/frontend/public/theme/fonts/element-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/1-Project/frontend/public/theme/fonts/element-icons.woff -------------------------------------------------------------------------------- /1-Project/frontend/src/config/index.js: -------------------------------------------------------------------------------- 1 | const config = require(`./${ 2 | process.env.VUE_APP_ENVIRONMENT 3 | }`).default; 4 | 5 | export default config; 6 | -------------------------------------------------------------------------------- /1-Project/frontend/src/config/localhost.js: -------------------------------------------------------------------------------- 1 | const backendUrl = `http://localhost:8080/api`; 2 | 3 | export default { 4 | backendUrl, 5 | }; 6 | -------------------------------------------------------------------------------- /1-Project/frontend/src/config/production.js: -------------------------------------------------------------------------------- 1 | const backendUrl = `/api`; 2 | 3 | export default { 4 | backendUrl, 5 | }; 6 | -------------------------------------------------------------------------------- /1-Project/frontend/src/config/testenv.js: -------------------------------------------------------------------------------- 1 | const backendUrl = null; 2 | 3 | export default { 4 | backendUrl, 5 | }; 6 | -------------------------------------------------------------------------------- /1-Project/frontend/src/main.js: -------------------------------------------------------------------------------- 1 | import '@/shared/plugins/element'; 2 | import Vue from 'vue'; 3 | import Vuex from 'vuex'; 4 | import Router from 'vue-router'; 5 | import { 6 | setupComponentsFiltersDirectivesAndMixins, 7 | storeAsync, 8 | routerAsync, 9 | } from '@/app-module'; 10 | import app from '@/app.vue'; 11 | import { SettingsService } from '@/modules/settings/settings-service'; 12 | import ProgressBar from '@/shared/progress-bar/progress-bar'; 13 | import { i18n } from '@/i18n'; 14 | 15 | (async function() { 16 | document.title = i18n('app.title'); 17 | ProgressBar.start(); 18 | await SettingsService.fetchAndApply(); 19 | 20 | Vue.use(Router); 21 | Vue.config.productionTip = 22 | process.env.NODE_ENV === 'production'; 23 | Vue.use(Vuex); 24 | setupComponentsFiltersDirectivesAndMixins(); 25 | 26 | // eslint-disable-next-line 27 | new Vue({ 28 | store: storeAsync(), 29 | router: routerAsync(), 30 | render: (h) => h(app), 31 | }).$mount('#app'); 32 | })(); 33 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/audit-log/audit-log-exporter-fields.js: -------------------------------------------------------------------------------- 1 | import { AuditLogModel } from '@/modules/audit-log/audit-log-model'; 2 | 3 | const { fields } = AuditLogModel; 4 | 5 | export default [ 6 | fields.timestamp, 7 | fields.createdByEmail, 8 | fields.entityName, 9 | fields.action, 10 | fields.entityId, 11 | fields.values, 12 | fields.id, 13 | ]; 14 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/audit-log/audit-log-module.js: -------------------------------------------------------------------------------- 1 | import routes from '@/modules/audit-log/audit-log-routes'; 2 | import store from '@/modules/audit-log/audit-log-store'; 3 | 4 | export default { 5 | routes, 6 | store, 7 | }; 8 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/audit-log/audit-log-permissions.js: -------------------------------------------------------------------------------- 1 | import PermissionChecker from '@/modules/iam/permission-checker'; 2 | import Permissions from '@/security/permissions'; 3 | 4 | export class AuditLogPermissions { 5 | constructor(currentUser) { 6 | const permissionChecker = new PermissionChecker( 7 | currentUser, 8 | ); 9 | 10 | this.read = permissionChecker.match( 11 | Permissions.values.auditLogRead, 12 | ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/audit-log/audit-log-routes.js: -------------------------------------------------------------------------------- 1 | import Layout from '@/modules/layout/components/layout'; 2 | import Permissions from '@/security/permissions'; 3 | 4 | const AuditLogPage = () => 5 | import('@/modules/audit-log/components/audit-log-page.vue'); 6 | 7 | export default [ 8 | { 9 | path: '', 10 | component: Layout, 11 | children: [ 12 | { 13 | name: 'auditLogs', 14 | path: '/audit-logs', 15 | component: AuditLogPage, 16 | exact: true, 17 | meta: { 18 | auth: true, 19 | permission: Permissions.values.auditLogRead, 20 | }, 21 | }, 22 | ], 23 | }, 24 | ]; 25 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/audit-log/audit-log-service.js: -------------------------------------------------------------------------------- 1 | import authAxios from '@/shared/axios/auth-axios'; 2 | 3 | export class AuditLogService { 4 | static async fetch(filter, orderBy, limit, offset) { 5 | const query = { 6 | filter, 7 | orderBy, 8 | limit, 9 | offset, 10 | }; 11 | 12 | const response = await authAxios.get('/auditLog', { 13 | params: query, 14 | }); 15 | 16 | return response.data; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/auth/auth-module.js: -------------------------------------------------------------------------------- 1 | import routes from '@/modules/auth/auth-routes'; 2 | import store from '@/modules/auth/auth-store'; 3 | import authGuardMixin from '@/modules/auth/guards/auth-guard-mixin'; 4 | import unauthGuardMixin from '@/modules/auth/guards/unauth-guard-mixin'; 5 | import emailAlreadyVerifiedGuardMixin from '@/modules/auth/guards/email-already-verified-guard-mixin'; 6 | import notEmptyPermissionsGuardMixin from '@/modules/auth/guards/not-empty-permissions-guard-mixin'; 7 | import permissionGuardMixin from '@/modules/auth/guards/permission-guard-mixin'; 8 | 9 | const mixins = [ 10 | authGuardMixin, 11 | unauthGuardMixin, 12 | emailAlreadyVerifiedGuardMixin, 13 | notEmptyPermissionsGuardMixin, 14 | permissionGuardMixin, 15 | ]; 16 | 17 | export default { 18 | routes, 19 | store, 20 | mixins, 21 | }; 22 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/auth/auth-token.js: -------------------------------------------------------------------------------- 1 | let inMemoryToken = null; 2 | 3 | export class AuthToken { 4 | static async get() { 5 | return ( 6 | inMemoryToken || localStorage.getItem('jwt') || null 7 | ); 8 | } 9 | 10 | static async set(token, rememberMe) { 11 | if (rememberMe) { 12 | localStorage.setItem('jwt', token || ''); 13 | } else { 14 | inMemoryToken = token; 15 | localStorage.setItem('jwt', ''); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/auth/components/empty-permissions-page.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 38 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/auth/components/verify-email-page.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 36 | 37 | 39 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/auth/guards/auth-guard-mixin.js: -------------------------------------------------------------------------------- 1 | import { storeAsync } from '@/app-module'; 2 | 3 | export default { 4 | async beforeRouteEnter(to, from, next) { 5 | if (!to.meta || !to.meta.auth) { 6 | next(); 7 | return; 8 | } 9 | 10 | const store = storeAsync(); 11 | 12 | await store.dispatch('auth/doWaitUntilInit'); 13 | 14 | if (!store.getters['auth/signedIn']) { 15 | next({ path: '/auth/signin' }); 16 | return; 17 | } 18 | 19 | if ( 20 | to.path !== '/auth/email-unverified' && 21 | !store.getters['auth/currentUser'].emailVerified 22 | ) { 23 | next({ path: '/auth/email-unverified' }); 24 | return; 25 | } 26 | 27 | if ( 28 | to.path !== '/auth/empty-permissions' && 29 | store.getters['auth/currentUser'].emailVerified && 30 | !store.getters['auth/roles'].length 31 | ) { 32 | next({ path: '/auth/empty-permissions' }); 33 | return; 34 | } 35 | 36 | next(); 37 | }, 38 | }; 39 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/auth/guards/email-already-verified-guard-mixin.js: -------------------------------------------------------------------------------- 1 | import { storeAsync } from '@/app-module'; 2 | 3 | export default { 4 | async beforeRouteEnter(to, from, next) { 5 | if (!to.meta || !to.meta.emailAlreadyVerified) { 6 | next(); 7 | return; 8 | } 9 | 10 | const store = storeAsync(); 11 | 12 | await store.dispatch('auth/doWaitUntilInit'); 13 | 14 | if ( 15 | store.getters['auth/signedIn'] && 16 | store.getters['auth/currentUser'].emailVerified 17 | ) { 18 | next('/'); 19 | } else { 20 | next(); 21 | } 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/auth/guards/not-empty-permissions-guard-mixin.js: -------------------------------------------------------------------------------- 1 | import { storeAsync } from '@/app-module'; 2 | 3 | export default { 4 | async beforeRouteEnter(to, from, next) { 5 | if (!to.meta || !to.meta.notEmptyPermissions) { 6 | next(); 7 | return; 8 | } 9 | 10 | const store = storeAsync(); 11 | 12 | await store.dispatch('auth/doWaitUntilInit'); 13 | 14 | if ( 15 | store.getters['auth/signedIn'] && 16 | store.getters['auth/roles'].length 17 | ) { 18 | next('/'); 19 | } else { 20 | next(); 21 | } 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/auth/guards/permission-guard-mixin.js: -------------------------------------------------------------------------------- 1 | import { storeAsync } from '@/app-module'; 2 | import PermissionChecker from '@/modules/iam/permission-checker'; 3 | 4 | export default { 5 | async beforeRouteEnter(to, from, next) { 6 | if (!to.meta || !to.meta.permission) { 7 | next(); 8 | return; 9 | } 10 | 11 | await storeAsync().dispatch('auth/doWaitUntilInit'); 12 | 13 | if ( 14 | new PermissionChecker( 15 | storeAsync().getters['auth/currentUser'], 16 | ).match(to.meta.permission) 17 | ) { 18 | next(); 19 | } else { 20 | next('/403'); 21 | } 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/auth/guards/unauth-guard-mixin.js: -------------------------------------------------------------------------------- 1 | import { storeAsync } from '@/app-module'; 2 | 3 | export default { 4 | async beforeRouteEnter(to, from, next) { 5 | if (!to.meta || !to.meta.unauth) { 6 | next(); 7 | return; 8 | } 9 | 10 | await storeAsync().dispatch('auth/doWaitUntilInit'); 11 | 12 | if (storeAsync().getters['auth/signedIn']) { 13 | next('/'); 14 | } else { 15 | next(); 16 | } 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/book/book-importer-fields.js: -------------------------------------------------------------------------------- 1 | import { BookModel } from '@/modules/book/book-model'; 2 | 3 | const { fields } = BookModel; 4 | 5 | export default [ 6 | fields.isbn, 7 | fields.title, 8 | fields.author, 9 | fields.numberOfCopies, 10 | fields.stock, 11 | fields.images, 12 | fields.status, 13 | ]; 14 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/book/book-importer-store.js: -------------------------------------------------------------------------------- 1 | import importerStore from '@/shared/importer/importer-store'; 2 | import { BookService } from '@/modules/book/book-service'; 3 | import bookImporterFields from '@/modules/book/book-importer-fields'; 4 | import { i18n } from '@/i18n'; 5 | 6 | export default importerStore( 7 | BookService.import, 8 | bookImporterFields, 9 | i18n('entities.book.importer.fileName'), 10 | i18n('entities.book.importer.hint'), 11 | ); 12 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/book/book-list-exporter-fields.js: -------------------------------------------------------------------------------- 1 | import { BookModel } from '@/modules/book/book-model'; 2 | 3 | const { fields } = BookModel; 4 | 5 | export default [ 6 | fields.id, 7 | fields.isbn, 8 | fields.title, 9 | fields.author, 10 | fields.numberOfCopies, 11 | fields.stock, 12 | fields.images, 13 | fields.status, 14 | fields.createdAt 15 | ]; 16 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/book/book-module.js: -------------------------------------------------------------------------------- 1 | import routes from '@/modules/book/book-routes'; 2 | import store from '@/modules/book/book-store'; 3 | 4 | export default { 5 | routes, 6 | store, 7 | }; 8 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/book/book-permissions.js: -------------------------------------------------------------------------------- 1 | import Permissions from '@/security/permissions'; 2 | import PermissionChecker from '@/modules/iam/permission-checker'; 3 | 4 | export class BookPermissions { 5 | constructor(currentUser) { 6 | const permissionChecker = new PermissionChecker( 7 | currentUser, 8 | ); 9 | 10 | this.read = permissionChecker.match( 11 | Permissions.values.bookRead, 12 | ); 13 | this.import = permissionChecker.match( 14 | Permissions.values.bookImport, 15 | ); 16 | this.bookAutocomplete = permissionChecker.match( 17 | Permissions.values.bookAutocomplete, 18 | ); 19 | this.create = permissionChecker.match( 20 | Permissions.values.bookCreate, 21 | ); 22 | this.edit = permissionChecker.match( 23 | Permissions.values.bookEdit, 24 | ); 25 | this.destroy = permissionChecker.match( 26 | Permissions.values.bookDestroy, 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/book/book-store.js: -------------------------------------------------------------------------------- 1 | import bookListStore from '@/modules/book/book-list-store'; 2 | import bookViewStore from '@/modules/book/book-view-store'; 3 | import bookImporterStore from '@/modules/book/book-importer-store'; 4 | import bookFormStore from '@/modules/book/book-form-store'; 5 | import bookDestroyStore from '@/modules/book/book-destroy-store'; 6 | 7 | export default { 8 | namespaced: true, 9 | 10 | modules: { 11 | destroy: bookDestroyStore, 12 | form: bookFormStore, 13 | list: bookListStore, 14 | view: bookViewStore, 15 | importer: bookImporterStore, 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/book/components/book-importer-page.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 30 | 31 | 33 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/home/components/home-chart.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 28 | 29 | 36 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/home/home-module.js: -------------------------------------------------------------------------------- 1 | import routes from '@/modules/home/home-routes'; 2 | 3 | export default { 4 | routes, 5 | }; 6 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/home/home-routes.js: -------------------------------------------------------------------------------- 1 | import Layout from '@/modules/layout/components/layout'; 2 | 3 | const HomePage = () => 4 | import('@/modules/home/components/home-page.vue'); 5 | 6 | export default [ 7 | { 8 | path: '', 9 | exact: true, 10 | component: Layout, 11 | children: [ 12 | { 13 | name: 'home', 14 | path: '', 15 | component: HomePage, 16 | exact: true, 17 | meta: { auth: true }, 18 | }, 19 | ], 20 | }, 21 | ]; 22 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/iam/components/iam-importer-page.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 30 | 31 | 33 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/iam/iam-importer-fields.js: -------------------------------------------------------------------------------- 1 | import { UserModel } from '@/modules/auth/user-model'; 2 | 3 | const { fields } = UserModel; 4 | 5 | export default [ 6 | fields.email, 7 | fields.firstName, 8 | fields.lastName, 9 | fields.phoneNumber, 10 | fields.avatarsIam, 11 | fields.roles, 12 | ]; 13 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/iam/iam-importer-store.js: -------------------------------------------------------------------------------- 1 | import importerStore from '@/shared/importer/importer-store'; 2 | import { IamService } from '@/modules/iam/iam-service'; 3 | import iamImporterFields from '@/modules/iam/iam-importer-fields'; 4 | import { i18n } from '@/i18n'; 5 | 6 | export default importerStore( 7 | IamService.import, 8 | iamImporterFields, 9 | i18n('iam.importer.fileName'), 10 | i18n('iam.importer.hint'), 11 | ); 12 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/iam/iam-list-exporter-fields.js: -------------------------------------------------------------------------------- 1 | import { UserModel } from '@/modules/auth/user-model'; 2 | 3 | const { fields } = UserModel; 4 | 5 | export default [ 6 | fields.id, 7 | fields.email, 8 | fields.fullName, 9 | fields.phoneNumber, 10 | fields.avatarsIam, 11 | fields.roles, 12 | fields.disabled, 13 | fields.createdAt, 14 | ]; 15 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/iam/iam-module.js: -------------------------------------------------------------------------------- 1 | import routes from '@/modules/iam/iam-routes'; 2 | import store from '@/modules/iam/iam-store'; 3 | 4 | export default { 5 | routes, 6 | store, 7 | }; 8 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/iam/iam-permissions.js: -------------------------------------------------------------------------------- 1 | import PermissionChecker from '@/modules/iam/permission-checker'; 2 | import Permissions from '@/security/permissions'; 3 | 4 | export class IamPermissions { 5 | constructor(currentUser) { 6 | const permissionChecker = new PermissionChecker( 7 | currentUser, 8 | ); 9 | 10 | this.read = permissionChecker.match( 11 | Permissions.values.iamRead, 12 | ); 13 | this.import = permissionChecker.match( 14 | Permissions.values.iamImport, 15 | ); 16 | this.userAutocomplete = permissionChecker.match( 17 | Permissions.values.iamUserAutocomplete, 18 | ); 19 | this.create = permissionChecker.match( 20 | Permissions.values.iamCreate, 21 | ); 22 | this.edit = permissionChecker.match( 23 | Permissions.values.iamEdit, 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/iam/iam-store.js: -------------------------------------------------------------------------------- 1 | import iamListStore from '@/modules/iam/iam-list-store'; 2 | import iamFormStore from '@/modules/iam/iam-form-store'; 3 | import iamViewStore from '@/modules/iam/iam-view-store'; 4 | import iamImporterStore from '@/modules/iam/iam-importer-store'; 5 | 6 | export default { 7 | namespaced: true, 8 | 9 | modules: { 10 | list: iamListStore, 11 | form: iamFormStore, 12 | view: iamViewStore, 13 | importer: iamImporterStore, 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/layout/components/error-403-page.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 27 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/layout/components/error-404-page.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 27 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/layout/components/error-500-page.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 27 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/layout/components/layout.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 24 | 25 | 27 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/layout/layout-module.js: -------------------------------------------------------------------------------- 1 | import Header from '@/modules/layout/components/header.vue'; 2 | import Menu from '@/modules/layout/components/menu.vue'; 3 | import Layout from '@/modules/layout/components/layout'; 4 | import store from '@/modules/layout/layout-store'; 5 | import routes from '@/modules/layout/layout-routes'; 6 | 7 | export default { 8 | components: [Header, Menu, Layout], 9 | 10 | filters: [], 11 | 12 | mixins: [], 13 | 14 | store, 15 | 16 | routes, 17 | }; 18 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/layout/layout-routes.js: -------------------------------------------------------------------------------- 1 | import Error403Page from '@/modules/layout/components/error-403-page.vue'; 2 | import Error404Page from '@/modules/layout/components/error-404-page.vue'; 3 | import Error500Page from '@/modules/layout/components/error-500-page.vue'; 4 | 5 | export default [ 6 | { 7 | name: 'error403', 8 | path: '/403', 9 | component: Error403Page, 10 | }, 11 | { 12 | name: 'error404', 13 | path: '/404', 14 | component: Error404Page, 15 | }, 16 | { 17 | name: 'error500', 18 | path: '/500', 19 | component: Error500Page, 20 | }, 21 | ]; 22 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/loan/components/loan-importer-page.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 30 | 31 | 33 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/loan/loan-importer-fields.js: -------------------------------------------------------------------------------- 1 | import { LoanModel } from '@/modules/loan/loan-model'; 2 | 3 | const { fields } = LoanModel; 4 | 5 | export default [ 6 | fields.book, 7 | fields.member, 8 | fields.issueDate, 9 | fields.dueDate, 10 | fields.returnDate, 11 | fields.status, 12 | ]; 13 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/loan/loan-importer-store.js: -------------------------------------------------------------------------------- 1 | import importerStore from '@/shared/importer/importer-store'; 2 | import { LoanService } from '@/modules/loan/loan-service'; 3 | import loanImporterFields from '@/modules/loan/loan-importer-fields'; 4 | import { i18n } from '@/i18n'; 5 | 6 | export default importerStore( 7 | LoanService.import, 8 | loanImporterFields, 9 | i18n('entities.loan.importer.fileName'), 10 | i18n('entities.loan.importer.hint'), 11 | ); 12 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/loan/loan-list-exporter-fields.js: -------------------------------------------------------------------------------- 1 | import { LoanModel } from '@/modules/loan/loan-model'; 2 | 3 | const { fields } = LoanModel; 4 | 5 | export default [ 6 | fields.id, 7 | fields.book, 8 | fields.member, 9 | fields.issueDate, 10 | fields.dueDate, 11 | fields.returnDate, 12 | fields.status, 13 | fields.createdAt 14 | ]; 15 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/loan/loan-module.js: -------------------------------------------------------------------------------- 1 | import routes from '@/modules/loan/loan-routes'; 2 | import store from '@/modules/loan/loan-store'; 3 | 4 | export default { 5 | routes, 6 | store, 7 | }; 8 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/loan/loan-permissions.js: -------------------------------------------------------------------------------- 1 | import Permissions from '@/security/permissions'; 2 | import PermissionChecker from '@/modules/iam/permission-checker'; 3 | 4 | export class LoanPermissions { 5 | constructor(currentUser) { 6 | const permissionChecker = new PermissionChecker( 7 | currentUser, 8 | ); 9 | 10 | this.read = permissionChecker.match( 11 | Permissions.values.loanRead, 12 | ); 13 | this.import = permissionChecker.match( 14 | Permissions.values.loanImport, 15 | ); 16 | this.loanAutocomplete = permissionChecker.match( 17 | Permissions.values.loanAutocomplete, 18 | ); 19 | this.create = permissionChecker.match( 20 | Permissions.values.loanCreate, 21 | ); 22 | this.edit = permissionChecker.match( 23 | Permissions.values.loanEdit, 24 | ); 25 | this.destroy = permissionChecker.match( 26 | Permissions.values.loanDestroy, 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/loan/loan-store.js: -------------------------------------------------------------------------------- 1 | import loanListStore from '@/modules/loan/loan-list-store'; 2 | import loanViewStore from '@/modules/loan/loan-view-store'; 3 | import loanImporterStore from '@/modules/loan/loan-importer-store'; 4 | import loanFormStore from '@/modules/loan/loan-form-store'; 5 | import loanDestroyStore from '@/modules/loan/loan-destroy-store'; 6 | 7 | export default { 8 | namespaced: true, 9 | 10 | modules: { 11 | destroy: loanDestroyStore, 12 | form: loanFormStore, 13 | list: loanListStore, 14 | view: loanViewStore, 15 | importer: loanImporterStore, 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/settings/components/settings-toolbar.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 32 | 33 | 35 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/settings/settings-module.js: -------------------------------------------------------------------------------- 1 | import routes from '@/modules/settings/settings-routes'; 2 | import store from '@/modules/settings/settings-store'; 3 | 4 | export default { 5 | routes, 6 | store, 7 | }; 8 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/settings/settings-permissions.js: -------------------------------------------------------------------------------- 1 | import PermissionChecker from '@/modules/iam/permission-checker'; 2 | import Permissions from '@/security/permissions'; 3 | 4 | export class SettingsPermissions { 5 | constructor(currentUser) { 6 | const permissionChecker = new PermissionChecker( 7 | currentUser, 8 | ); 9 | 10 | this.edit = permissionChecker.match( 11 | Permissions.values.settingsEdit, 12 | ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /1-Project/frontend/src/modules/settings/settings-routes.js: -------------------------------------------------------------------------------- 1 | import Layout from '@/modules/layout/components/layout'; 2 | import Permissions from '@/security/permissions'; 3 | 4 | const SettingsPage = () => 5 | import('@/modules/settings/components/settings-page.vue'); 6 | 7 | export default [ 8 | { 9 | path: '', 10 | component: Layout, 11 | children: [ 12 | { 13 | name: 'settings', 14 | path: '/settings', 15 | component: SettingsPage, 16 | exact: true, 17 | meta: { 18 | auth: true, 19 | permission: Permissions.values.settingsEdit, 20 | }, 21 | }, 22 | ], 23 | }, 24 | ]; 25 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/exporter/exporter-schema.js: -------------------------------------------------------------------------------- 1 | import * as yup from 'yup'; 2 | 3 | export default class ExporterSchema { 4 | constructor(fields) { 5 | this.fields = fields; 6 | this.yupSchema = this.buildSchema(); 7 | } 8 | 9 | get labels() { 10 | return this.fields.map((field) => field.label); 11 | } 12 | 13 | labelOf(name) { 14 | const field = this.fields.find( 15 | (field) => field.name === name, 16 | ); 17 | 18 | if (field) { 19 | return field.label; 20 | } 21 | 22 | return name; 23 | } 24 | 25 | buildSchema() { 26 | const shape = {}; 27 | 28 | this.fields.forEach((field) => { 29 | shape[field.name] = field.forExport(); 30 | }); 31 | 32 | return yup 33 | .object() 34 | .shape(shape) 35 | .noUnknown(true); 36 | } 37 | 38 | cast(row) { 39 | return this.yupSchema.cast(row); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/exporter/exporter.js: -------------------------------------------------------------------------------- 1 | import { mapKeys } from 'lodash'; 2 | import ExporterSchema from '@/shared/exporter/exporter-schema'; 3 | import { Excel } from '@/shared/excel/excel'; 4 | 5 | export default class Exporter { 6 | constructor(fields, excelFileName) { 7 | this.schema = new ExporterSchema(fields); 8 | this.excelFileName = excelFileName; 9 | } 10 | 11 | transformAndExportAsExcelFile(rows) { 12 | const exportableData = rows.map((row) => { 13 | const rowCasted = this.schema.cast(row); 14 | return this._makeNameHeadersIntoLabels(rowCasted); 15 | }); 16 | 17 | return Excel.exportAsExcelFile( 18 | exportableData, 19 | this.schema.labels, 20 | this.excelFileName + '_' + new Date().getTime(), 21 | ); 22 | } 23 | 24 | _makeNameHeadersIntoLabels(row) { 25 | return mapKeys(row, (value, key) => { 26 | return this.schema.labelOf(key); 27 | }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/fields/date-range-field.js: -------------------------------------------------------------------------------- 1 | import * as yup from 'yup'; 2 | import GenericField from '@/shared/fields/generic-field'; 3 | import moment from 'moment'; 4 | 5 | export default class DateRangeField extends GenericField { 6 | forFilterInitialValue(value) { 7 | return value || []; 8 | } 9 | 10 | forFilterRules() { 11 | return undefined; 12 | } 13 | 14 | forFilterCast() { 15 | return yup.mixed().transform((value, originalValue) => { 16 | if (!originalValue) { 17 | return originalValue; 18 | } 19 | 20 | if (!originalValue.length) { 21 | return originalValue; 22 | } 23 | 24 | return originalValue.map((value) => { 25 | return value ? moment(value).format('YYYY-MM-DD') : null; 26 | }); 27 | }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/fields/date-time-range-field.js: -------------------------------------------------------------------------------- 1 | import * as yup from 'yup'; 2 | import GenericField from '@/shared/fields/generic-field'; 3 | 4 | export default class DateTimeRangeField extends GenericField { 5 | forFilterInitialValue(value) { 6 | return value || []; 7 | } 8 | 9 | forFilterRules() { 10 | return undefined; 11 | } 12 | 13 | forFilterCast() { 14 | return yup.mixed(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/fields/generic-field.js: -------------------------------------------------------------------------------- 1 | export default class GenericField { 2 | constructor(name, label) { 3 | this.name = name; 4 | this.label = label; 5 | } 6 | 7 | forPresenter() { 8 | throw new Error('Called superclass'); 9 | } 10 | 11 | forFilterCast() { 12 | throw new Error('Called superclass'); 13 | } 14 | 15 | forFilterRules() { 16 | throw new Error('Called superclass'); 17 | } 18 | 19 | forFormCast() { 20 | throw new Error('Called superclass'); 21 | } 22 | 23 | forFormRules() { 24 | throw new Error('Called superclass'); 25 | } 26 | 27 | forFilterInitialValue() { 28 | throw new Error('Called superclass'); 29 | } 30 | 31 | forFormInitialValue() { 32 | throw new Error('Called superclass'); 33 | } 34 | 35 | forExport() { 36 | throw new Error('Called superclass'); 37 | } 38 | 39 | forImport() { 40 | throw new Error('Called superclass'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/fields/id-field.js: -------------------------------------------------------------------------------- 1 | import StringField from '@/shared/fields/string-field'; 2 | 3 | export default class IdField extends StringField {} 4 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/fields/json-field.js: -------------------------------------------------------------------------------- 1 | import * as yup from 'yup'; 2 | import GenericField from '@/shared/fields/generic-field'; 3 | 4 | export default class JsonField extends GenericField { 5 | forPresenter(value) { 6 | return value; 7 | } 8 | 9 | forFormInitialValue(value) { 10 | return value; 11 | } 12 | 13 | forFormRules() { 14 | let yupChain = yup.mixed().label(this.label); 15 | return yupChain; 16 | } 17 | 18 | forFilter() { 19 | let yupChain = yup.mixed().label(this.label); 20 | return yupChain; 21 | } 22 | 23 | forExport() { 24 | let yupChain = yup 25 | .mixed() 26 | .label(this.label) 27 | .transform((value, originalValue) => { 28 | return JSON.stringify(originalValue, null, 2); 29 | }); 30 | return yupChain; 31 | } 32 | 33 | forImport() { 34 | let yupChain = yup.mixed().label(this.label); 35 | return yupChain; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/filters/format-date-filter.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment'; 2 | 3 | export default { 4 | name: 'formatDate', 5 | implementation(value) { 6 | if (value) { 7 | return moment(value).format('YYYY-MM-DD'); 8 | } 9 | 10 | return null; 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/filters/format-datetime-filter.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment'; 2 | 3 | export default { 4 | name: 'formatDatetime', 5 | implementation(value) { 6 | if (value) { 7 | return moment(value).format('YYYY-MM-DD HH:mm'); 8 | } 9 | 10 | return null; 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/i18n/i18n-util.js: -------------------------------------------------------------------------------- 1 | import { setLanguageCode } from '@/i18n'; 2 | 3 | export class I18nUtil { 4 | static doChangeLanguage(language) { 5 | setLanguageCode(language); 6 | window.location.reload(); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/i18n/i18n.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 18 | 19 | 21 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/importer/importer-statuses.js: -------------------------------------------------------------------------------- 1 | export default { 2 | PENDING: 'PENDING', 3 | IMPORTED: 'IMPORTED', 4 | ERROR: 'ERROR', 5 | }; 6 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/list/list-item-file.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 30 | 31 | 33 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/list/list-item-image.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | 21 | 23 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/list/list-item-relation-to-many.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 26 | 27 | 29 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/message/message.js: -------------------------------------------------------------------------------- 1 | import { i18n } from '@/i18n'; 2 | import { Notification } from 'element-ui'; 3 | 4 | export default class Message { 5 | static success(payload) { 6 | Notification({ 7 | showClose: true, 8 | message: payload, 9 | type: 'success', 10 | duration: 6000, 11 | }); 12 | } 13 | 14 | static error(payload) { 15 | let message = payload; 16 | 17 | if (!message) { 18 | message = i18n('errors.defaultErrorMessage'); 19 | } 20 | // eslint-disable-next-line 21 | 22 | Notification({ 23 | showClose: true, 24 | message, 25 | 26 | type: 'error', 27 | duration: 6000, 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/mixins/autofocus-mixin.js: -------------------------------------------------------------------------------- 1 | export default { 2 | mounted() { 3 | if (this.$refs.focus) { 4 | this.$refs.focus.focus(); 5 | } 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/model/generic-model.js: -------------------------------------------------------------------------------- 1 | export class GenericModel { 2 | static get fields() { 3 | throw new Error('Not implemented'); 4 | } 5 | 6 | static presenter(row, fieldName) { 7 | if (!this.fields[fieldName]) { 8 | throw new Error(`${fieldName} not found`); 9 | } 10 | 11 | return this.fields[fieldName].forPresenter( 12 | row[this.fields[fieldName].name], 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/plugins/element.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Element from 'element-ui'; 3 | import { getElementUILanguage } from '@/i18n'; 4 | 5 | Vue.use(Element, { locale: getElementUILanguage() }); 6 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/progress-bar/progress-bar.js: -------------------------------------------------------------------------------- 1 | import NProgress from 'nprogress'; 2 | import 'nprogress/nprogress.css'; 3 | 4 | NProgress.configure({ showSpinner: false }); 5 | 6 | export default class ProgressBar { 7 | static start() { 8 | NProgress.start(); 9 | } 10 | 11 | static done() { 12 | NProgress.done(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/view/image-carousel.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 30 | 31 | 33 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/view/view-item-custom.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 27 | 28 | 30 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/view/view-item-file.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 26 | 27 | 29 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/view/view-item-image.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 22 | 23 | 25 | -------------------------------------------------------------------------------- /1-Project/frontend/src/shared/view/view-item-text.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 23 | 24 | 26 | -------------------------------------------------------------------------------- /1-Project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "build:production": "cd ./frontend && npm install && npm run build:production && rm -rf ./node_modules && cd ../backend && npm install", 6 | "start:production": "cd ./backend && npm run start:production" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /2-Basics/1 - NodeJS and Javascript/1-basics.js: -------------------------------------------------------------------------------- 1 | console.log(1 + 1); 2 | -------------------------------------------------------------------------------- /2-Basics/1 - NodeJS and Javascript/2-functions-and-classes.js: -------------------------------------------------------------------------------- 1 | function sum(a, b) { 2 | return a + b; 3 | } 4 | 5 | class Calculator { 6 | sum(a, b) { 7 | return a + b; 8 | } 9 | } 10 | 11 | console.log("First sum", sum(1, 1)); 12 | console.log("Second sum", new Calculator().sum(2, 2)); 13 | -------------------------------------------------------------------------------- /2-Basics/1 - NodeJS and Javascript/3-callbacks-and-arrow-functions.js: -------------------------------------------------------------------------------- 1 | class Prefixer { 2 | constructor(prefix) { 3 | this.prefix = prefix; 4 | } 5 | 6 | prefixArrayWithStandard(arr) { 7 | const that = this; 8 | const callback = function(value) { 9 | return that.prefix + value; 10 | }; 11 | 12 | return arr.map(callback); 13 | } 14 | 15 | prefixArrayWithArrow(arr) { 16 | const callback = value => { 17 | return this.prefix + value; 18 | }; 19 | 20 | return arr.map(callback); 21 | } 22 | } 23 | 24 | console.log( 25 | "standard", 26 | new Prefixer("scaffoldhub_").prefixArrayWithStandard(["1", "2"]) 27 | ); 28 | 29 | // console.log( 30 | // "arrow", 31 | // new Prefixer("scaffoldhub_").prefixArrayWithArrow(["1", "2"]) 32 | // ); 33 | -------------------------------------------------------------------------------- /2-Basics/1 - NodeJS and Javascript/4-spread-deconstruct-objects.js: -------------------------------------------------------------------------------- 1 | const userA = { 2 | name: "Felipe", 3 | age: 20 4 | }; 5 | 6 | const userB = { 7 | ...userA, 8 | age: 28 9 | }; 10 | 11 | console.log("userA", userA); 12 | console.log("userB", userB); 13 | 14 | // const age = userB.age; 15 | const { age: userBAge } = userB; 16 | console.log("age", userBAge); 17 | -------------------------------------------------------------------------------- /2-Basics/1 - NodeJS and Javascript/5-spread-deconstruct-arrays.js: -------------------------------------------------------------------------------- 1 | const numbers = [1, 2, 3]; 2 | 3 | const moreNumbers = [...numbers, 4, 5]; 4 | 5 | console.log("numbers", numbers); 6 | console.log("moreNumbers", moreNumbers); 7 | 8 | const [first, second, ...others] = moreNumbers; 9 | 10 | console.log("first", first); 11 | console.log("second", second); 12 | console.log("others", others); 13 | 14 | const numberWithNull = [1, 2, 3, 4, null, 5, null]; 15 | 16 | console.log("numberWithNull", numberWithNull); 17 | 18 | const numberWithoutNulls = numberWithNull.filter(Boolean); 19 | 20 | console.log("Boolean(null)", Boolean(null)); 21 | 22 | console.log("numberWithoutNulls", numberWithoutNulls); 23 | -------------------------------------------------------------------------------- /2-Basics/1 - NodeJS and Javascript/6-npm-modules.js: -------------------------------------------------------------------------------- 1 | const moment = require("moment"); 2 | 3 | console.log(moment().format("YYYY-MM-DD")); 4 | -------------------------------------------------------------------------------- /2-Basics/1 - NodeJS and Javascript/7-async-await.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios").default; 2 | 3 | (async function() { 4 | try { 5 | const response = await axios.get("https://randomuser.me/api/?results=1"); 6 | console.log(response.data); 7 | } catch (error) { 8 | console.error(error); 9 | } 10 | })(); 11 | -------------------------------------------------------------------------------- /2-Basics/1 - NodeJS and Javascript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "basics", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "1-basics.js", 6 | "scripts": { 7 | "start": "node 6-npm-modules.js" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "axios": "^0.18.0", 13 | "moment": "^2.24.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /2-Basics/2 - Vue/backend/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | -------------------------------------------------------------------------------- /2-Basics/2 - Vue/backend/db.json: -------------------------------------------------------------------------------- 1 | { 2 | "todo": [ 3 | { 4 | "id": 1, 5 | "text": "Create a Vue app" 6 | } 7 | ] 8 | } -------------------------------------------------------------------------------- /2-Basics/2 - Vue/backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "dependencies": { 7 | "json-server": "^0.15.0" 8 | }, 9 | "devDependencies": {}, 10 | "scripts": { 11 | "start": "json-server --watch db.json --delay 1000" 12 | }, 13 | "author": "", 14 | "license": "ISC" 15 | } 16 | -------------------------------------------------------------------------------- /2-Basics/2 - Vue/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | -------------------------------------------------------------------------------- /2-Basics/2 - Vue/frontend/README.md: -------------------------------------------------------------------------------- 1 | # frontend 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Run your tests 19 | ``` 20 | npm run test 21 | ``` 22 | 23 | ### Lints and fixes files 24 | ``` 25 | npm run lint 26 | ``` 27 | 28 | ### Customize configuration 29 | See [Configuration Reference](https://cli.vuejs.org/config/). 30 | -------------------------------------------------------------------------------- /2-Basics/2 - Vue/frontend/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /2-Basics/2 - Vue/frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/2-Basics/2 - Vue/frontend/public/favicon.ico -------------------------------------------------------------------------------- /2-Basics/2 - Vue/frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | frontend 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /2-Basics/2 - Vue/frontend/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | 17 | 19 | -------------------------------------------------------------------------------- /2-Basics/2 - Vue/frontend/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | 4 | Vue.config.productionTip = false 5 | 6 | new Vue({ 7 | render: h => h(App), 8 | }).$mount('#app') 9 | -------------------------------------------------------------------------------- /2-Basics/2 - Vue/frontend/src/todo/components/TodoForm.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 29 | 30 | 32 | -------------------------------------------------------------------------------- /2-Basics/2 - Vue/frontend/src/todo/components/TodoList.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 24 | 25 | 27 | -------------------------------------------------------------------------------- /2-Basics/2 - Vue/frontend/src/todo/todoService.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | const serverUrl = "http://localhost:3000"; 4 | 5 | export default { 6 | async list() { 7 | const response = await axios.get(`${serverUrl}/todo`); 8 | return response.data; 9 | }, 10 | 11 | async create(todo) { 12 | const response = await axios.post(`${serverUrl}/todo`, todo); 13 | return response.data; 14 | }, 15 | 16 | async destroy(id) { 17 | const response = await axios.delete(`${serverUrl}/todo/${id}`); 18 | return response.data; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /2-Basics/3 - Vue Router/link.txt: -------------------------------------------------------------------------------- 1 | https://jsfiddle.net/yyx990803/xgrjzsup/ -------------------------------------------------------------------------------- /2-Basics/4 - Element UI/backend/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | -------------------------------------------------------------------------------- /2-Basics/4 - Element UI/backend/db.json: -------------------------------------------------------------------------------- 1 | { 2 | "todo": [ 3 | { 4 | "text": "Create a Vue app", 5 | "id": 1 6 | } 7 | ] 8 | } -------------------------------------------------------------------------------- /2-Basics/4 - Element UI/backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "dependencies": { 7 | "json-server": "^0.15.0" 8 | }, 9 | "devDependencies": {}, 10 | "scripts": { 11 | "start": "json-server --watch db.json --delay 1000" 12 | }, 13 | "author": "", 14 | "license": "ISC" 15 | } 16 | -------------------------------------------------------------------------------- /2-Basics/4 - Element UI/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | -------------------------------------------------------------------------------- /2-Basics/4 - Element UI/frontend/README.md: -------------------------------------------------------------------------------- 1 | # frontend 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Run your tests 19 | ``` 20 | npm run test 21 | ``` 22 | 23 | ### Lints and fixes files 24 | ``` 25 | npm run lint 26 | ``` 27 | 28 | ### Customize configuration 29 | See [Configuration Reference](https://cli.vuejs.org/config/). 30 | -------------------------------------------------------------------------------- /2-Basics/4 - Element UI/frontend/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /2-Basics/4 - Element UI/frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/2-Basics/4 - Element UI/frontend/public/favicon.ico -------------------------------------------------------------------------------- /2-Basics/4 - Element UI/frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | frontend 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /2-Basics/4 - Element UI/frontend/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | 17 | 22 | -------------------------------------------------------------------------------- /2-Basics/4 - Element UI/frontend/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import './plugins/element.js' 4 | 5 | Vue.config.productionTip = false 6 | 7 | new Vue({ 8 | render: h => h(App), 9 | }).$mount('#app') 10 | -------------------------------------------------------------------------------- /2-Basics/4 - Element UI/frontend/src/plugins/element.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Element from 'element-ui' 3 | import 'element-ui/lib/theme-chalk/index.css' 4 | import locale from 'element-ui/lib/locale/lang/en' 5 | 6 | Vue.use(Element, { locale }) 7 | -------------------------------------------------------------------------------- /2-Basics/4 - Element UI/frontend/src/todo/components/TodoList.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 26 | 27 | 29 | -------------------------------------------------------------------------------- /2-Basics/4 - Element UI/frontend/src/todo/todoService.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | const serverUrl = "http://localhost:3000"; 4 | 5 | export default { 6 | async list() { 7 | const response = await axios.get(`${serverUrl}/todo`); 8 | return response.data; 9 | }, 10 | 11 | async create(todo) { 12 | const response = await axios.post(`${serverUrl}/todo`, todo); 13 | return response.data; 14 | }, 15 | 16 | async destroy(id) { 17 | const response = await axios.delete(`${serverUrl}/todo/${id}`); 18 | return response.data; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /2-Basics/5 - Vuex/backend/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | -------------------------------------------------------------------------------- /2-Basics/5 - Vuex/backend/db.json: -------------------------------------------------------------------------------- 1 | { 2 | "todo": [ 3 | { 4 | "id": 1, 5 | "text": "Create a Vue app" 6 | }, 7 | { 8 | "text": "Create a backend", 9 | "id": 2 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /2-Basics/5 - Vuex/backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "dependencies": { 7 | "json-server": "^0.15.0" 8 | }, 9 | "devDependencies": {}, 10 | "scripts": { 11 | "start": "json-server --watch db.json --delay 1000" 12 | }, 13 | "author": "", 14 | "license": "ISC" 15 | } 16 | -------------------------------------------------------------------------------- /2-Basics/5 - Vuex/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | -------------------------------------------------------------------------------- /2-Basics/5 - Vuex/frontend/README.md: -------------------------------------------------------------------------------- 1 | # frontend 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Run your tests 19 | ``` 20 | npm run test 21 | ``` 22 | 23 | ### Lints and fixes files 24 | ``` 25 | npm run lint 26 | ``` 27 | 28 | ### Customize configuration 29 | See [Configuration Reference](https://cli.vuejs.org/config/). 30 | -------------------------------------------------------------------------------- /2-Basics/5 - Vuex/frontend/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /2-Basics/5 - Vuex/frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/2-Basics/5 - Vuex/frontend/public/favicon.ico -------------------------------------------------------------------------------- /2-Basics/5 - Vuex/frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | frontend 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /2-Basics/5 - Vuex/frontend/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | 17 | 22 | -------------------------------------------------------------------------------- /2-Basics/5 - Vuex/frontend/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import App from "./App.vue"; 3 | import "./plugins/element.js"; 4 | import store from "./store"; 5 | 6 | Vue.config.productionTip = false; 7 | 8 | new Vue({ 9 | render: h => h(App), 10 | store 11 | }).$mount("#app"); 12 | -------------------------------------------------------------------------------- /2-Basics/5 - Vuex/frontend/src/plugins/element.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Element from 'element-ui' 3 | import 'element-ui/lib/theme-chalk/index.css' 4 | import locale from 'element-ui/lib/locale/lang/en' 5 | 6 | Vue.use(Element, { locale }) 7 | -------------------------------------------------------------------------------- /2-Basics/5 - Vuex/frontend/src/store.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuex from "vuex"; 3 | import todoStore from "./todo/todoStore"; 4 | 5 | Vue.use(Vuex); 6 | 7 | const store = new Vuex.Store({ 8 | modules: { 9 | todo: todoStore 10 | } 11 | }); 12 | 13 | export default store; 14 | -------------------------------------------------------------------------------- /2-Basics/5 - Vuex/frontend/src/todo/components/TodoPage.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 22 | 23 | 25 | -------------------------------------------------------------------------------- /2-Basics/5 - Vuex/frontend/src/todo/todoService.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | const serverUrl = "http://localhost:3000"; 4 | 5 | export default { 6 | async list() { 7 | const response = await axios.get(`${serverUrl}/todo`); 8 | return response.data; 9 | }, 10 | 11 | async create(todo) { 12 | const response = await axios.post(`${serverUrl}/todo`, todo); 13 | return response.data; 14 | }, 15 | 16 | async destroy(id) { 17 | const response = await axios.delete(`${serverUrl}/todo/${id}`); 18 | return response.data; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /2-Basics/6 - ExpressJS/backend/index.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const app = express(); 3 | const port = 3000; 4 | const bodyParser = require("body-parser"); 5 | const cors = require("cors"); 6 | 7 | app.use( 8 | cors({ 9 | origin: true 10 | }) 11 | ); 12 | 13 | app.get("/todo", (req, res) => { 14 | res.send([{ id: 1, text: "Create a Vue app" }]); 15 | }); 16 | 17 | app.post("/todo", bodyParser.json(), (req, res) => { 18 | console.log(req.body); 19 | res.sendStatus(200); 20 | }); 21 | 22 | app.delete("/todo/:id", (req, res) => { 23 | console.log(req.params.id); 24 | res.sendStatus(200); 25 | }); 26 | 27 | app.listen(port, () => console.log(`Listening on port ${port}`)); 28 | -------------------------------------------------------------------------------- /2-Basics/6 - ExpressJS/backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "body-parser": "^1.19.0", 13 | "cors": "^2.8.5", 14 | "express": "^4.17.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /2-Basics/7 - SQL and Sequelize/backend/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | database: { 3 | username: "postgres", 4 | dialect: "postgres", 5 | password: "", 6 | database: "todo", 7 | host: "localhost", 8 | logging: console.log 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /2-Basics/7 - SQL and Sequelize/backend/models/index.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const path = require("path"); 3 | const Sequelize = require("sequelize"); 4 | const basename = path.basename(module.filename); 5 | const config = require("../config"); 6 | const db = {}; 7 | 8 | let sequelize = new Sequelize( 9 | config.database.database, 10 | config.database.username, 11 | config.database.password, 12 | config.database 13 | ); 14 | 15 | fs.readdirSync(__dirname) 16 | .filter(function(file) { 17 | return ( 18 | file.indexOf(".") !== 0 && file !== basename && file.slice(-3) === ".js" 19 | ); 20 | }) 21 | .forEach(function(file) { 22 | const model = sequelize["import"](path.join(__dirname, file)); 23 | db[model.name] = model; 24 | }); 25 | 26 | Object.keys(db).forEach(function(modelName) { 27 | if (db[modelName].associate) { 28 | db[modelName].associate(db); 29 | } 30 | }); 31 | 32 | db.sequelize = sequelize; 33 | db.Sequelize = Sequelize; 34 | 35 | module.exports = db; 36 | -------------------------------------------------------------------------------- /2-Basics/7 - SQL and Sequelize/backend/models/todo.js: -------------------------------------------------------------------------------- 1 | module.exports = function(sequelize, DataTypes) { 2 | const todo = sequelize.define( 3 | "todo", 4 | { 5 | id: { 6 | type: DataTypes.UUID, 7 | defaultValue: DataTypes.UUIDV4, 8 | primaryKey: true 9 | }, 10 | text: { 11 | type: DataTypes.STRING(255), 12 | allowNull: false, 13 | validate: { 14 | len: [2, 255], 15 | notEmpty: true 16 | } 17 | } 18 | }, 19 | { 20 | timestamps: true, 21 | paranoid: true 22 | } 23 | ); 24 | 25 | return todo; 26 | }; 27 | -------------------------------------------------------------------------------- /2-Basics/7 - SQL and Sequelize/backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "body-parser": "^1.19.0", 13 | "cors": "^2.8.5", 14 | "express": "^4.17.1", 15 | "pg": "^7.11.0", 16 | "sequelize": "^5.9.4" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /2-Basics/8 - MongoDB and Mongoose/backend/models/todo.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const TodoSchema = new mongoose.Schema( 4 | { 5 | text: { 6 | type: String, 7 | required: true, 8 | minlength: 2, 9 | maxlength: 255 10 | } 11 | }, 12 | { timestamps: true } 13 | ); 14 | 15 | TodoSchema.virtual("id").get(function() { 16 | return this._id.toHexString(); 17 | }); 18 | 19 | TodoSchema.set("toJSON", { 20 | getters: true 21 | }); 22 | 23 | TodoSchema.set("toObject", { 24 | getters: true 25 | }); 26 | 27 | const Todo = mongoose.model("todo", TodoSchema); 28 | 29 | module.exports = Todo; 30 | -------------------------------------------------------------------------------- /2-Basics/8 - MongoDB and Mongoose/backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "body-parser": "^1.19.0", 13 | "cors": "^2.8.5", 14 | "express": "^4.17.1", 15 | "mongoose": "^5.6.4" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /3-Customization/backend-mongodb/config/localhost.js: -------------------------------------------------------------------------------- 1 | const os = require('os'); 2 | 3 | module.exports = { 4 | env: 'localhost', 5 | 6 | database: { 7 | // connection: 8 | // 'mongodb://localhost:27017,localhost:27018,localhost:27019/development?replicaSet=rs', 9 | // transactions: true, 10 | connection: 'mongodb://localhost:27017/development', 11 | transactions: false, 12 | }, 13 | 14 | email: { 15 | comment: 'See https://nodemailer.com', 16 | from: '', 17 | host: null, 18 | auth: { 19 | user: null, 20 | pass: null, 21 | }, 22 | }, 23 | 24 | clientUrl: 'http://localhost:8081', 25 | 26 | defaultUser: '', 27 | 28 | uploadDir: os.tmpdir(), 29 | 30 | authJwtSecret: '5fda55e7-9000-4c41-9dc0-8fbb094b2202', 31 | }; 32 | -------------------------------------------------------------------------------- /3-Customization/backend-mongodb/config/production.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: "production", 3 | 4 | database: { 5 | connection: "mongodb://mongo:27017/production", 6 | transactions: false 7 | }, 8 | 9 | email: { 10 | comment: "See https://nodemailer.com", 11 | from: "", 12 | host: null, 13 | auth: { 14 | user: null, 15 | pass: null 16 | } 17 | }, 18 | 19 | graphiql: false, 20 | 21 | clientUrl: "", 22 | 23 | defaultUser: null, 24 | 25 | uploadDir: "/storage", 26 | 27 | authJwtSecret: "5fda55e7-9000-4c41-9dc0-8fbb094b2202" 28 | }; 29 | -------------------------------------------------------------------------------- /3-Customization/backend-mongodb/src/api/loan/index.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | app.post(`/loan`, require('./loanCreate')); 3 | app.put(`/loan/:id`, require('./loanUpdate')); 4 | app.post(`/loan/import`, require('./loanImport')); 5 | app.delete(`/loan`, require('./loanDestroy')); 6 | app.get( 7 | `/loan/autocomplete`, 8 | require('./loanAutocomplete'), 9 | ); 10 | app.get(`/loan`, require('./loanList')); 11 | app.get(`/loan/:id`, require('./loanFind')); 12 | app.post(`/loan/email`, require('./loanEmail')); 13 | }; 14 | -------------------------------------------------------------------------------- /3-Customization/backend-mongodb/src/api/loan/loanEmail.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const LoanService = require('../../services/loanService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.loanEmail, 10 | ); 11 | 12 | await new LoanService(req).sendEmails(req.body.ids); 13 | 14 | const payload = true; 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /3-Customization/backend-mongodb/src/database/models/settings.js: -------------------------------------------------------------------------------- 1 | const database = require('../database'); 2 | const Schema = database.Schema; 3 | 4 | const SettingsSchema = new Schema( 5 | { 6 | theme: { type: String }, 7 | loanPeriodInDays: { type: Number }, 8 | createdBy: { 9 | type: Schema.Types.ObjectId, 10 | ref: 'user', 11 | }, 12 | updatedBy: { 13 | type: Schema.Types.ObjectId, 14 | ref: 'user', 15 | }, 16 | }, 17 | { timestamps: true }, 18 | ); 19 | 20 | SettingsSchema.virtual('id').get(function() { 21 | return this._id.toHexString(); 22 | }); 23 | 24 | SettingsSchema.set('toJSON', { 25 | getters: true, 26 | }); 27 | 28 | SettingsSchema.set('toObject', { 29 | getters: true, 30 | }); 31 | 32 | const Settings = database.model('settings', SettingsSchema); 33 | 34 | module.exports = Settings; 35 | -------------------------------------------------------------------------------- /3-Customization/backend-mongodb/src/emails/loanInProgressEmail.js: -------------------------------------------------------------------------------- 1 | const { i18n } = require('../i18n'); 2 | const moment = require('moment'); 3 | 4 | module.exports = class LoanInProgressEmail { 5 | constructor(language, loan) { 6 | this.language = language; 7 | this.to = loan.member.email; 8 | this.loan = loan; 9 | } 10 | 11 | get subject() { 12 | return i18n( 13 | this.language, 14 | 'emails.loan.inProgress.subject', 15 | this.loan.book.title, 16 | moment(this.loan.dueDate).diff(moment(), 'days'), 17 | ); 18 | } 19 | 20 | get html() { 21 | return i18n( 22 | this.language, 23 | 'emails.loan.inProgress.body', 24 | i18n(this.language, 'app.title'), 25 | this.loan.book.title, 26 | moment(this.loan.dueDate).diff(moment(), 'days'), 27 | this.loan.member.firstName, 28 | ); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /3-Customization/backend-mongodb/src/emails/loanOverdueEmail.js: -------------------------------------------------------------------------------- 1 | const { i18n } = require('../i18n'); 2 | const moment = require('moment'); 3 | 4 | module.exports = class LoanOverdueEmail { 5 | constructor(language, loan) { 6 | this.language = language; 7 | this.to = loan.member.email; 8 | this.loan = loan; 9 | } 10 | 11 | get subject() { 12 | return i18n( 13 | this.language, 14 | 'emails.loan.overdue.subject', 15 | this.loan.book.title, 16 | ); 17 | } 18 | 19 | get html() { 20 | return i18n( 21 | this.language, 22 | 'emails.loan.overdue.body', 23 | i18n(this.language, 'app.title'), 24 | this.loan.book.title, 25 | this.loan.member.firstName, 26 | ); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /3-Customization/backend-mongodb/src/security/roles.js: -------------------------------------------------------------------------------- 1 | class Roles { 2 | static get values() { 3 | return { 4 | librarian: 'librarian', 5 | member: 'member', 6 | }; 7 | } 8 | } 9 | 10 | module.exports = Roles; 11 | -------------------------------------------------------------------------------- /3-Customization/backend-sql/config/production.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: 'production', 3 | 4 | database: { 5 | username: 'postgres', 6 | dialect: 'postgres', 7 | password: '', 8 | database: 'postgres', 9 | host: 'postgres', 10 | logging: console.log, 11 | operatorsAliases: false, 12 | }, 13 | 14 | // database: { 15 | // username: 'root', 16 | // dialect: 'mysql', 17 | // password: '', 18 | // database: 'production', 19 | // host: 20 | // '', 21 | // logging: console.log, 22 | // operatorsAliases: false, 23 | // }, 24 | 25 | email: { 26 | comment: 'See https://nodemailer.com', 27 | from: '', 28 | host: null, 29 | auth: { 30 | user: null, 31 | pass: null, 32 | }, 33 | }, 34 | 35 | clientUrl: '', 36 | 37 | defaultUser: null, 38 | 39 | uploadDir: '/storage', 40 | 41 | authJwtSecret: '5fda55e7-9000-4c41-9dc0-8fbb094b2202', 42 | }; 43 | -------------------------------------------------------------------------------- /3-Customization/backend-sql/migrations/201907021900-add-loan-period-in-days-to-settings.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE public.settings 2 | ADD COLUMN "loanPeriodInDays" integer; -------------------------------------------------------------------------------- /3-Customization/backend-sql/src/api/loan/index.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | app.post(`/loan`, require('./loanCreate')); 3 | app.put(`/loan/:id`, require('./loanUpdate')); 4 | app.post(`/loan/import`, require('./loanImport')); 5 | app.delete(`/loan`, require('./loanDestroy')); 6 | app.get( 7 | `/loan/autocomplete`, 8 | require('./loanAutocomplete'), 9 | ); 10 | app.get(`/loan`, require('./loanList')); 11 | app.get(`/loan/:id`, require('./loanFind')); 12 | app.post(`/loan/email`, require('./loanEmail')); 13 | }; 14 | -------------------------------------------------------------------------------- /3-Customization/backend-sql/src/api/loan/loanEmail.js: -------------------------------------------------------------------------------- 1 | const PermissionChecker = require('../../services/iam/permissionChecker'); 2 | const permissions = require('../../security/permissions') 3 | .values; 4 | const LoanService = require('../../services/loanService'); 5 | 6 | module.exports = async (req, res) => { 7 | try { 8 | new PermissionChecker(req).validateHas( 9 | permissions.loanEmail, 10 | ); 11 | 12 | await new LoanService(req).sendEmails(req.body.ids); 13 | 14 | const payload = true; 15 | 16 | res.status(200).send(payload); 17 | } catch (error) { 18 | if ([400, 403, 404].includes(error.code)) { 19 | return res.status(error.code).send(error.message); 20 | } 21 | 22 | console.error(error); 23 | return res.status(500).send(error.message); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /3-Customization/backend-sql/src/database/models/settings.js: -------------------------------------------------------------------------------- 1 | module.exports = function(sequelize, DataTypes) { 2 | const settings = sequelize.define( 3 | 'settings', 4 | { 5 | id: { 6 | type: DataTypes.STRING, 7 | defaultValue: 'default', 8 | primaryKey: true, 9 | }, 10 | theme: { 11 | type: DataTypes.STRING(255), 12 | allowNull: false, 13 | }, 14 | loanPeriodInDays: { 15 | type: DataTypes.INTEGER, 16 | }, 17 | }, 18 | { 19 | timestamps: true, 20 | paranoid: true, 21 | }, 22 | ); 23 | 24 | settings.associate = (models) => { 25 | models.settings.belongsTo(models.user, { 26 | as: 'createdBy', 27 | }); 28 | 29 | models.settings.belongsTo(models.user, { 30 | as: 'updatedBy', 31 | }); 32 | }; 33 | 34 | return settings; 35 | }; 36 | -------------------------------------------------------------------------------- /3-Customization/backend-sql/src/emails/loanInProgressEmail.js: -------------------------------------------------------------------------------- 1 | const { i18n } = require('../i18n'); 2 | const moment = require('moment'); 3 | 4 | module.exports = class LoanInProgressEmail { 5 | constructor(language, loan) { 6 | this.language = language; 7 | this.to = loan.member.email; 8 | this.loan = loan; 9 | } 10 | 11 | get subject() { 12 | return i18n( 13 | this.language, 14 | 'emails.loan.inProgress.subject', 15 | this.loan.book.title, 16 | moment(this.loan.dueDate).diff(moment(), 'days'), 17 | ); 18 | } 19 | 20 | get html() { 21 | return i18n( 22 | this.language, 23 | 'emails.loan.inProgress.body', 24 | i18n(this.language, 'app.title'), 25 | this.loan.book.title, 26 | moment(this.loan.dueDate).diff(moment(), 'days'), 27 | this.loan.member.firstName, 28 | ); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /3-Customization/backend-sql/src/emails/loanOverdueEmail.js: -------------------------------------------------------------------------------- 1 | const { i18n } = require('../i18n'); 2 | const moment = require('moment'); 3 | 4 | module.exports = class LoanOverdueEmail { 5 | constructor(language, loan) { 6 | this.language = language; 7 | this.to = loan.member.email; 8 | this.loan = loan; 9 | } 10 | 11 | get subject() { 12 | return i18n( 13 | this.language, 14 | 'emails.loan.overdue.subject', 15 | this.loan.book.title, 16 | ); 17 | } 18 | 19 | get html() { 20 | return i18n( 21 | this.language, 22 | 'emails.loan.overdue.body', 23 | i18n(this.language, 'app.title'), 24 | this.loan.book.title, 25 | this.loan.member.firstName, 26 | ); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /3-Customization/backend-sql/src/security/roles.js: -------------------------------------------------------------------------------- 1 | class Roles { 2 | static get values() { 3 | return { 4 | librarian: 'librarian', 5 | member: 'member', 6 | }; 7 | } 8 | } 9 | 10 | module.exports = Roles; 11 | -------------------------------------------------------------------------------- /3-Customization/frontend/public/images/signin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/3-Customization/frontend/public/images/signin.jpg -------------------------------------------------------------------------------- /3-Customization/frontend/public/images/signup.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipepastorelima/vue-library/2ae549a2b9b06cc1124db3234bcd7bccdee21d6c/3-Customization/frontend/public/images/signup.jpg -------------------------------------------------------------------------------- /3-Customization/frontend/src/modules/book/book-importer-fields.js: -------------------------------------------------------------------------------- 1 | import { BookModel } from '@/modules/book/book-model'; 2 | 3 | const { fields } = BookModel; 4 | 5 | export default [ 6 | fields.isbn, 7 | fields.title, 8 | fields.author, 9 | fields.numberOfCopies, 10 | fields.images, 11 | ]; 12 | -------------------------------------------------------------------------------- /3-Customization/frontend/src/modules/book/book-list-exporter-fields.js: -------------------------------------------------------------------------------- 1 | import { BookModel } from '@/modules/book/book-model'; 2 | 3 | const { fields } = BookModel; 4 | 5 | export default [ 6 | fields.id, 7 | fields.isbn, 8 | fields.title, 9 | fields.author, 10 | fields.numberOfCopies, 11 | fields.images, 12 | fields.status, 13 | fields.createdAt 14 | ]; 15 | -------------------------------------------------------------------------------- /3-Customization/frontend/src/modules/book/components/book-status-tag.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 23 | 24 | 26 | -------------------------------------------------------------------------------- /3-Customization/frontend/src/modules/loan/components/loan-status-tag.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 24 | 25 | 27 | -------------------------------------------------------------------------------- /3-Customization/frontend/src/modules/loan/loan-importer-fields.js: -------------------------------------------------------------------------------- 1 | import { LoanModel } from '@/modules/loan/loan-model'; 2 | 3 | const { fields } = LoanModel; 4 | 5 | export default [ 6 | fields.book, 7 | fields.member, 8 | fields.issueDate, 9 | fields.dueDate, 10 | fields.returnDate, 11 | ]; 12 | -------------------------------------------------------------------------------- /3-Customization/frontend/src/modules/loan/loan-store.js: -------------------------------------------------------------------------------- 1 | import loanListStore from '@/modules/loan/loan-list-store'; 2 | import loanViewStore from '@/modules/loan/loan-view-store'; 3 | import loanImporterStore from '@/modules/loan/loan-importer-store'; 4 | import loanFormStore from '@/modules/loan/loan-form-store'; 5 | import loanDestroyStore from '@/modules/loan/loan-destroy-store'; 6 | import loanEmailStore from '@/modules/loan/loan-email-store'; 7 | 8 | export default { 9 | namespaced: true, 10 | 11 | modules: { 12 | email: loanEmailStore, 13 | destroy: loanDestroyStore, 14 | form: loanFormStore, 15 | list: loanListStore, 16 | view: loanViewStore, 17 | importer: loanImporterStore, 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /3-Customization/frontend/src/security/roles.js: -------------------------------------------------------------------------------- 1 | import { i18n } from '@/i18n'; 2 | import _values from 'lodash/values'; 3 | 4 | class Roles { 5 | static get values() { 6 | return { 7 | librarian: 'librarian', 8 | member: 'member', 9 | }; 10 | } 11 | 12 | static labelOf(roleId) { 13 | if (!this.values[roleId]) { 14 | return roleId; 15 | } 16 | 17 | return i18n(`roles.${roleId}.label`); 18 | } 19 | 20 | static descriptionOf(roleId) { 21 | if (!this.values[roleId]) { 22 | return roleId; 23 | } 24 | 25 | return i18n(`roles.${roleId}.description`); 26 | } 27 | 28 | static get selectOptions() { 29 | return _values(this.values).map((value) => ({ 30 | id: value, 31 | value: value, 32 | title: this.descriptionOf(value), 33 | label: this.labelOf(value), 34 | })); 35 | } 36 | } 37 | 38 | export default Roles; 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Build a Library web application with Vue, NodeJS, and SQL or MongoDB using ScaffoldHub 2 | 3 | DEMO: https://vue-library-demo.web.app/ 4 | 5 | The course uses ScaffoldHub.io (https://scaffoldhub.io) to create the initial application. After, the basics of Javascript, Vue, Vue Router, Vuex, ExpressJS, Sequelize (SQL) and Mongoose (MongoDB) are explained, and finally, how the application is customized to attend all the Library needs. 6 | 7 | Course Webpage: https://scaffoldhub.io/courses/vue-library 8 | 9 | ## Base Application 10 | 11 | The base project is at the 1-Project folder. 12 | 13 | Vue Element UI with SQL or MongoDB 14 | 15 | Version: 1.2.1 16 | 17 | ## Basics 18 | 19 | On the 2-Basics folder you'll find the source code for the basics section. 20 | 21 | ## Customization 22 | 23 | On the 3-Customization you can find the code that was modified from the base application. 24 | --------------------------------------------------------------------------------