├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .gitattributes ├── .gitignore ├── .husky └── pre-commit ├── .jhipster ├── Detail.json ├── Job.json ├── Redeem.json └── Type.json ├── .lintstagedrc.cjs ├── .mvn ├── jvm.config └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── .prettierignore ├── .prettierrc ├── .vscode └── settings.json ├── .yo-rc.json ├── JREADME.md ├── LICENSE ├── PRIVACY.md ├── README.md ├── TOS.md ├── angular.json ├── checkstyle.xml ├── cypress.config.ts ├── db.jdl ├── jest.conf.js ├── mvnw ├── mvnw.cmd ├── ngsw-config.json ├── npmw ├── npmw.cmd ├── package-lock.json ├── package.json ├── pom.xml ├── sonar-project.properties ├── src ├── main │ ├── docker │ │ ├── app.yml │ │ ├── grafana │ │ │ └── provisioning │ │ │ │ ├── dashboards │ │ │ │ ├── JVM.json │ │ │ │ └── dashboard.yml │ │ │ │ └── datasources │ │ │ │ └── datasource.yml │ │ ├── jhipster-control-center.yml │ │ ├── jib │ │ │ └── entrypoint.sh │ │ ├── mongodb-cluster.yml │ │ ├── mongodb.yml │ │ ├── mongodb │ │ │ ├── MongoDB.Dockerfile │ │ │ └── scripts │ │ │ │ └── init_replicaset.js │ │ ├── monitoring.yml │ │ ├── prometheus │ │ │ └── prometheus.yml │ │ ├── services.yml │ │ ├── sonar.yml │ │ └── swagger-editor.yml │ ├── java │ │ └── com │ │ │ └── camenduru │ │ │ └── web │ │ │ ├── ApplicationWebXml.java │ │ │ ├── GeneratedByJHipster.java │ │ │ ├── WebApp.java │ │ │ ├── aop │ │ │ └── logging │ │ │ │ ├── LoggingAspect.java │ │ │ │ └── package-info.java │ │ │ ├── config │ │ │ ├── ApplicationProperties.java │ │ │ ├── AsyncConfiguration.java │ │ │ ├── CRLFLogConverter.java │ │ │ ├── CacheConfiguration.java │ │ │ ├── Constants.java │ │ │ ├── DatabaseConfiguration.java │ │ │ ├── DateTimeFormatConfiguration.java │ │ │ ├── JacksonConfiguration.java │ │ │ ├── LocaleConfiguration.java │ │ │ ├── LoggingAspectConfiguration.java │ │ │ ├── LoggingConfiguration.java │ │ │ ├── OpenApiConfiguration.java │ │ │ ├── SecurityConfiguration.java │ │ │ ├── SecurityJwtConfiguration.java │ │ │ ├── StaticResourcesWebConfiguration.java │ │ │ ├── WebConfigurer.java │ │ │ ├── WebsocketConfiguration.java │ │ │ ├── WebsocketSecurityConfiguration.java │ │ │ ├── dbmigrations │ │ │ │ ├── InitialSetupMigration.java │ │ │ │ └── package-info.java │ │ │ └── package-info.java │ │ │ ├── domain │ │ │ ├── AbstractAuditingEntity.java │ │ │ ├── Authority.java │ │ │ ├── Detail.java │ │ │ ├── Job.java │ │ │ ├── Redeem.java │ │ │ ├── Type.java │ │ │ ├── User.java │ │ │ ├── enumeration │ │ │ │ ├── JobSource.java │ │ │ │ ├── JobStatus.java │ │ │ │ ├── Membership.java │ │ │ │ ├── RedeemStatus.java │ │ │ │ └── package-info.java │ │ │ └── package-info.java │ │ │ ├── management │ │ │ ├── SecurityMetersService.java │ │ │ └── package-info.java │ │ │ ├── package-info.java │ │ │ ├── repository │ │ │ ├── AuthorityRepository.java │ │ │ ├── DetailRepository.java │ │ │ ├── JobRepository.java │ │ │ ├── RedeemRepository.java │ │ │ ├── TypeRepository.java │ │ │ ├── UserRepository.java │ │ │ └── package-info.java │ │ │ ├── security │ │ │ ├── AuthoritiesConstants.java │ │ │ ├── DomainUserDetailsService.java │ │ │ ├── SecurityUtils.java │ │ │ ├── SpringSecurityAuditorAware.java │ │ │ ├── UserNotActivatedException.java │ │ │ └── package-info.java │ │ │ ├── service │ │ │ ├── EmailAlreadyUsedException.java │ │ │ ├── EmailServiceNotAllowedException.java │ │ │ ├── InvalidPasswordException.java │ │ │ ├── MailService.java │ │ │ ├── UserService.java │ │ │ ├── UsernameAlreadyUsedException.java │ │ │ ├── chat │ │ │ │ ├── ChatRequestBody.java │ │ │ │ ├── ChatRequestMessage.java │ │ │ │ └── ChatTextRespose.java │ │ │ ├── dto │ │ │ │ ├── AdminUserDTO.java │ │ │ │ ├── NotifyDTO.java │ │ │ │ ├── PasswordChangeDTO.java │ │ │ │ ├── UserDTO.java │ │ │ │ └── package-info.java │ │ │ ├── mapper │ │ │ │ ├── UserMapper.java │ │ │ │ └── package-info.java │ │ │ └── package-info.java │ │ │ └── web │ │ │ ├── filter │ │ │ ├── SpaWebFilter.java │ │ │ └── package-info.java │ │ │ ├── rest │ │ │ ├── AccountResource.java │ │ │ ├── AuthenticateController.java │ │ │ ├── AuthorityResource.java │ │ │ ├── DetailResource.java │ │ │ ├── JobResource.java │ │ │ ├── PublicUserResource.java │ │ │ ├── RedeemResource.java │ │ │ ├── TypeResource.java │ │ │ ├── UserResource.java │ │ │ ├── errors │ │ │ │ ├── BadRequestAlertException.java │ │ │ │ ├── EmailAlreadyUsedException.java │ │ │ │ ├── EmailServiceNotAllowedException.java │ │ │ │ ├── ErrorConstants.java │ │ │ │ ├── ExceptionTranslator.java │ │ │ │ ├── FieldErrorVM.java │ │ │ │ ├── InvalidPasswordException.java │ │ │ │ ├── LoginAlreadyUsedException.java │ │ │ │ └── package-info.java │ │ │ ├── package-info.java │ │ │ └── vm │ │ │ │ ├── KeyAndPasswordVM.java │ │ │ │ ├── LoginVM.java │ │ │ │ ├── ManagedUserVM.java │ │ │ │ └── package-info.java │ │ │ └── websocket │ │ │ ├── ActivityService.java │ │ │ ├── dto │ │ │ ├── ActivityDTO.java │ │ │ └── package-info.java │ │ │ └── package-info.java │ ├── resources │ │ ├── banner.txt │ │ ├── config │ │ │ ├── application-dev.yml │ │ │ ├── application-prod.yml │ │ │ ├── application-tls.yml │ │ │ ├── application.yml │ │ │ └── tls │ │ │ │ └── keystore.p12 │ │ ├── i18n │ │ │ ├── messages.properties │ │ │ └── messages_en.properties │ │ ├── logback-spring.xml │ │ ├── swagger │ │ │ └── api.yml │ │ └── templates │ │ │ ├── error.html │ │ │ └── mail │ │ │ ├── activationEmail.html │ │ │ ├── creationEmail.html │ │ │ └── passwordResetEmail.html │ └── webapp │ │ ├── 404.html │ │ ├── WEB-INF │ │ └── web.xml │ │ ├── app │ │ ├── account │ │ │ ├── account.route.ts │ │ │ ├── activate │ │ │ │ ├── activate.component.html │ │ │ │ ├── activate.component.spec.ts │ │ │ │ ├── activate.component.ts │ │ │ │ ├── activate.route.ts │ │ │ │ ├── activate.service.spec.ts │ │ │ │ └── activate.service.ts │ │ │ ├── password-reset │ │ │ │ ├── finish │ │ │ │ │ ├── password-reset-finish.component.html │ │ │ │ │ ├── password-reset-finish.component.spec.ts │ │ │ │ │ ├── password-reset-finish.component.ts │ │ │ │ │ ├── password-reset-finish.route.ts │ │ │ │ │ ├── password-reset-finish.service.spec.ts │ │ │ │ │ └── password-reset-finish.service.ts │ │ │ │ └── init │ │ │ │ │ ├── password-reset-init.component.html │ │ │ │ │ ├── password-reset-init.component.spec.ts │ │ │ │ │ ├── password-reset-init.component.ts │ │ │ │ │ ├── password-reset-init.route.ts │ │ │ │ │ ├── password-reset-init.service.spec.ts │ │ │ │ │ └── password-reset-init.service.ts │ │ │ ├── password │ │ │ │ ├── password-strength-bar │ │ │ │ │ ├── password-strength-bar.component.html │ │ │ │ │ ├── password-strength-bar.component.scss │ │ │ │ │ ├── password-strength-bar.component.spec.ts │ │ │ │ │ └── password-strength-bar.component.ts │ │ │ │ ├── password.component.html │ │ │ │ ├── password.component.spec.ts │ │ │ │ ├── password.component.ts │ │ │ │ ├── password.route.ts │ │ │ │ ├── password.service.spec.ts │ │ │ │ └── password.service.ts │ │ │ ├── register │ │ │ │ ├── register.component.html │ │ │ │ ├── register.component.spec.ts │ │ │ │ ├── register.component.ts │ │ │ │ ├── register.model.ts │ │ │ │ ├── register.route.ts │ │ │ │ ├── register.service.spec.ts │ │ │ │ └── register.service.ts │ │ │ └── settings │ │ │ │ ├── settings.component.html │ │ │ │ ├── settings.component.spec.ts │ │ │ │ ├── settings.component.ts │ │ │ │ └── settings.route.ts │ │ ├── admin │ │ │ ├── admin.routes.ts │ │ │ ├── configuration │ │ │ │ ├── configuration.component.html │ │ │ │ ├── configuration.component.spec.ts │ │ │ │ ├── configuration.component.ts │ │ │ │ ├── configuration.model.ts │ │ │ │ ├── configuration.service.spec.ts │ │ │ │ └── configuration.service.ts │ │ │ ├── docs │ │ │ │ ├── docs.component.html │ │ │ │ ├── docs.component.scss │ │ │ │ └── docs.component.ts │ │ │ ├── health │ │ │ │ ├── health.component.html │ │ │ │ ├── health.component.spec.ts │ │ │ │ ├── health.component.ts │ │ │ │ ├── health.model.ts │ │ │ │ ├── health.service.spec.ts │ │ │ │ ├── health.service.ts │ │ │ │ └── modal │ │ │ │ │ ├── health-modal.component.html │ │ │ │ │ ├── health-modal.component.spec.ts │ │ │ │ │ └── health-modal.component.ts │ │ │ ├── logs │ │ │ │ ├── log.model.ts │ │ │ │ ├── logs.component.html │ │ │ │ ├── logs.component.spec.ts │ │ │ │ ├── logs.component.ts │ │ │ │ ├── logs.service.spec.ts │ │ │ │ └── logs.service.ts │ │ │ ├── metrics │ │ │ │ ├── blocks │ │ │ │ │ ├── jvm-memory │ │ │ │ │ │ ├── jvm-memory.component.html │ │ │ │ │ │ └── jvm-memory.component.ts │ │ │ │ │ ├── jvm-threads │ │ │ │ │ │ ├── jvm-threads.component.html │ │ │ │ │ │ └── jvm-threads.component.ts │ │ │ │ │ ├── metrics-cache │ │ │ │ │ │ ├── metrics-cache.component.html │ │ │ │ │ │ └── metrics-cache.component.ts │ │ │ │ │ ├── metrics-datasource │ │ │ │ │ │ ├── metrics-datasource.component.html │ │ │ │ │ │ └── metrics-datasource.component.ts │ │ │ │ │ ├── metrics-endpoints-requests │ │ │ │ │ │ ├── metrics-endpoints-requests.component.html │ │ │ │ │ │ └── metrics-endpoints-requests.component.ts │ │ │ │ │ ├── metrics-garbagecollector │ │ │ │ │ │ ├── metrics-garbagecollector.component.html │ │ │ │ │ │ └── metrics-garbagecollector.component.ts │ │ │ │ │ ├── metrics-modal-threads │ │ │ │ │ │ ├── metrics-modal-threads.component.html │ │ │ │ │ │ ├── metrics-modal-threads.component.spec.ts │ │ │ │ │ │ └── metrics-modal-threads.component.ts │ │ │ │ │ ├── metrics-request │ │ │ │ │ │ ├── metrics-request.component.html │ │ │ │ │ │ └── metrics-request.component.ts │ │ │ │ │ └── metrics-system │ │ │ │ │ │ ├── metrics-system.component.html │ │ │ │ │ │ └── metrics-system.component.ts │ │ │ │ ├── metrics.component.html │ │ │ │ ├── metrics.component.spec.ts │ │ │ │ ├── metrics.component.ts │ │ │ │ ├── metrics.model.ts │ │ │ │ ├── metrics.service.spec.ts │ │ │ │ └── metrics.service.ts │ │ │ ├── tracker │ │ │ │ ├── tracker.component.html │ │ │ │ └── tracker.component.ts │ │ │ └── user-management │ │ │ │ ├── delete │ │ │ │ ├── user-management-delete-dialog.component.html │ │ │ │ ├── user-management-delete-dialog.component.spec.ts │ │ │ │ └── user-management-delete-dialog.component.ts │ │ │ │ ├── detail │ │ │ │ ├── user-management-detail.component.html │ │ │ │ ├── user-management-detail.component.spec.ts │ │ │ │ └── user-management-detail.component.ts │ │ │ │ ├── list │ │ │ │ ├── user-management.component.html │ │ │ │ ├── user-management.component.spec.ts │ │ │ │ └── user-management.component.ts │ │ │ │ ├── service │ │ │ │ ├── user-management.service.spec.ts │ │ │ │ └── user-management.service.ts │ │ │ │ ├── update │ │ │ │ ├── user-management-update.component.html │ │ │ │ ├── user-management-update.component.spec.ts │ │ │ │ └── user-management-update.component.ts │ │ │ │ ├── user-management.model.ts │ │ │ │ └── user-management.route.ts │ │ ├── app-page-title-strategy.ts │ │ ├── app.component.ts │ │ ├── app.config.ts │ │ ├── app.constants.ts │ │ ├── app.routes.ts │ │ ├── config │ │ │ ├── authority.constants.ts │ │ │ ├── datepicker-adapter.ts │ │ │ ├── dayjs.ts │ │ │ ├── error.constants.ts │ │ │ ├── font-awesome-icons.ts │ │ │ ├── input.constants.ts │ │ │ ├── language.constants.ts │ │ │ ├── navigation.constants.ts │ │ │ ├── pagination.constants.ts │ │ │ ├── translation.config.ts │ │ │ └── uib-pagination.config.ts │ │ ├── core │ │ │ ├── auth │ │ │ │ ├── account.model.ts │ │ │ │ ├── account.service.spec.ts │ │ │ │ ├── account.service.ts │ │ │ │ ├── auth-jwt.service.spec.ts │ │ │ │ ├── auth-jwt.service.ts │ │ │ │ ├── state-storage.service.ts │ │ │ │ └── user-route-access.service.ts │ │ │ ├── config │ │ │ │ ├── application-config.service.spec.ts │ │ │ │ └── application-config.service.ts │ │ │ ├── interceptor │ │ │ │ ├── auth-expired.interceptor.ts │ │ │ │ ├── auth.interceptor.ts │ │ │ │ ├── error-handler.interceptor.ts │ │ │ │ ├── index.ts │ │ │ │ └── notification.interceptor.ts │ │ │ ├── request │ │ │ │ ├── request-util.ts │ │ │ │ └── request.model.ts │ │ │ ├── tracker │ │ │ │ ├── tracker-activity.model.ts │ │ │ │ └── tracker.service.ts │ │ │ └── util │ │ │ │ ├── alert.service.spec.ts │ │ │ │ ├── alert.service.ts │ │ │ │ ├── data-util.service.spec.ts │ │ │ │ ├── data-util.service.ts │ │ │ │ ├── event-manager.service.spec.ts │ │ │ │ ├── event-manager.service.ts │ │ │ │ ├── operators.spec.ts │ │ │ │ ├── operators.ts │ │ │ │ ├── parse-links.service.spec.ts │ │ │ │ └── parse-links.service.ts │ │ ├── entities │ │ │ ├── admin │ │ │ │ └── authority │ │ │ │ │ ├── authority.model.ts │ │ │ │ │ ├── authority.routes.ts │ │ │ │ │ ├── authority.test-samples.ts │ │ │ │ │ ├── delete │ │ │ │ │ ├── authority-delete-dialog.component.html │ │ │ │ │ ├── authority-delete-dialog.component.spec.ts │ │ │ │ │ └── authority-delete-dialog.component.ts │ │ │ │ │ ├── detail │ │ │ │ │ ├── authority-detail.component.html │ │ │ │ │ ├── authority-detail.component.spec.ts │ │ │ │ │ └── authority-detail.component.ts │ │ │ │ │ ├── list │ │ │ │ │ ├── authority.component.html │ │ │ │ │ ├── authority.component.spec.ts │ │ │ │ │ └── authority.component.ts │ │ │ │ │ ├── route │ │ │ │ │ ├── authority-routing-resolve.service.spec.ts │ │ │ │ │ └── authority-routing-resolve.service.ts │ │ │ │ │ ├── service │ │ │ │ │ ├── authority.service.spec.ts │ │ │ │ │ └── authority.service.ts │ │ │ │ │ └── update │ │ │ │ │ ├── authority-form.service.spec.ts │ │ │ │ │ ├── authority-form.service.ts │ │ │ │ │ ├── authority-update.component.html │ │ │ │ │ ├── authority-update.component.spec.ts │ │ │ │ │ └── authority-update.component.ts │ │ │ ├── detail │ │ │ │ ├── delete │ │ │ │ │ ├── detail-delete-dialog.component.html │ │ │ │ │ ├── detail-delete-dialog.component.spec.ts │ │ │ │ │ └── detail-delete-dialog.component.ts │ │ │ │ ├── detail.model.ts │ │ │ │ ├── detail.routes.ts │ │ │ │ ├── detail.test-samples.ts │ │ │ │ ├── detail │ │ │ │ │ ├── detail-detail.component.html │ │ │ │ │ ├── detail-detail.component.spec.ts │ │ │ │ │ └── detail-detail.component.ts │ │ │ │ ├── list │ │ │ │ │ ├── detail.component.html │ │ │ │ │ ├── detail.component.spec.ts │ │ │ │ │ └── detail.component.ts │ │ │ │ ├── route │ │ │ │ │ ├── detail-routing-resolve.service.spec.ts │ │ │ │ │ └── detail-routing-resolve.service.ts │ │ │ │ ├── service │ │ │ │ │ ├── detail.service.spec.ts │ │ │ │ │ └── detail.service.ts │ │ │ │ └── update │ │ │ │ │ ├── detail-form.service.spec.ts │ │ │ │ │ ├── detail-form.service.ts │ │ │ │ │ ├── detail-update.component.html │ │ │ │ │ ├── detail-update.component.spec.ts │ │ │ │ │ └── detail-update.component.ts │ │ │ ├── entity-navbar-items.ts │ │ │ ├── entity.routes.ts │ │ │ ├── enumerations │ │ │ │ ├── job-source.model.ts │ │ │ │ ├── job-status.model.ts │ │ │ │ ├── membership.model.ts │ │ │ │ └── redeem-status.model.ts │ │ │ ├── job │ │ │ │ ├── delete │ │ │ │ │ ├── job-delete-dialog.component.html │ │ │ │ │ ├── job-delete-dialog.component.spec.ts │ │ │ │ │ └── job-delete-dialog.component.ts │ │ │ │ ├── detail │ │ │ │ │ ├── job-detail.component.html │ │ │ │ │ ├── job-detail.component.spec.ts │ │ │ │ │ └── job-detail.component.ts │ │ │ │ ├── job.model.ts │ │ │ │ ├── job.routes.ts │ │ │ │ ├── job.test-samples.ts │ │ │ │ ├── list │ │ │ │ │ ├── job.component.html │ │ │ │ │ ├── job.component.spec.ts │ │ │ │ │ └── job.component.ts │ │ │ │ ├── route │ │ │ │ │ ├── job-routing-resolve.service.spec.ts │ │ │ │ │ └── job-routing-resolve.service.ts │ │ │ │ ├── service │ │ │ │ │ ├── job.service.spec.ts │ │ │ │ │ └── job.service.ts │ │ │ │ └── update │ │ │ │ │ ├── job-form.service.spec.ts │ │ │ │ │ ├── job-form.service.ts │ │ │ │ │ ├── job-update.component.html │ │ │ │ │ ├── job-update.component.spec.ts │ │ │ │ │ └── job-update.component.ts │ │ │ ├── redeem │ │ │ │ ├── delete │ │ │ │ │ ├── redeem-delete-dialog.component.html │ │ │ │ │ ├── redeem-delete-dialog.component.spec.ts │ │ │ │ │ └── redeem-delete-dialog.component.ts │ │ │ │ ├── detail │ │ │ │ │ ├── redeem-detail.component.html │ │ │ │ │ ├── redeem-detail.component.spec.ts │ │ │ │ │ └── redeem-detail.component.ts │ │ │ │ ├── list │ │ │ │ │ ├── redeem.component.html │ │ │ │ │ ├── redeem.component.spec.ts │ │ │ │ │ └── redeem.component.ts │ │ │ │ ├── redeem.model.ts │ │ │ │ ├── redeem.routes.ts │ │ │ │ ├── redeem.test-samples.ts │ │ │ │ ├── route │ │ │ │ │ ├── redeem-routing-resolve.service.spec.ts │ │ │ │ │ └── redeem-routing-resolve.service.ts │ │ │ │ ├── service │ │ │ │ │ ├── redeem.service.spec.ts │ │ │ │ │ └── redeem.service.ts │ │ │ │ └── update │ │ │ │ │ ├── redeem-form.service.spec.ts │ │ │ │ │ ├── redeem-form.service.ts │ │ │ │ │ ├── redeem-update.component.html │ │ │ │ │ ├── redeem-update.component.spec.ts │ │ │ │ │ └── redeem-update.component.ts │ │ │ ├── type │ │ │ │ ├── delete │ │ │ │ │ ├── type-delete-dialog.component.html │ │ │ │ │ ├── type-delete-dialog.component.spec.ts │ │ │ │ │ └── type-delete-dialog.component.ts │ │ │ │ ├── detail │ │ │ │ │ ├── type-detail.component.html │ │ │ │ │ ├── type-detail.component.spec.ts │ │ │ │ │ └── type-detail.component.ts │ │ │ │ ├── list │ │ │ │ │ ├── type.component.html │ │ │ │ │ ├── type.component.spec.ts │ │ │ │ │ └── type.component.ts │ │ │ │ ├── route │ │ │ │ │ ├── type-routing-resolve.service.spec.ts │ │ │ │ │ └── type-routing-resolve.service.ts │ │ │ │ ├── service │ │ │ │ │ ├── type.service.spec.ts │ │ │ │ │ └── type.service.ts │ │ │ │ ├── type.model.ts │ │ │ │ ├── type.routes.ts │ │ │ │ ├── type.test-samples.ts │ │ │ │ └── update │ │ │ │ │ ├── type-form.service.spec.ts │ │ │ │ │ ├── type-form.service.ts │ │ │ │ │ ├── type-update.component.html │ │ │ │ │ ├── type-update.component.spec.ts │ │ │ │ │ └── type-update.component.ts │ │ │ └── user │ │ │ │ ├── service │ │ │ │ ├── user.service.spec.ts │ │ │ │ └── user.service.ts │ │ │ │ ├── user.model.ts │ │ │ │ └── user.test-samples.ts │ │ ├── home │ │ │ ├── home.component.html │ │ │ ├── home.component.scss │ │ │ ├── home.component.spec.ts │ │ │ └── home.component.ts │ │ ├── layouts │ │ │ ├── error │ │ │ │ ├── error.component.html │ │ │ │ ├── error.component.ts │ │ │ │ └── error.route.ts │ │ │ ├── footer │ │ │ │ ├── footer.component.html │ │ │ │ └── footer.component.ts │ │ │ ├── main │ │ │ │ ├── main.component.html │ │ │ │ ├── main.component.spec.ts │ │ │ │ └── main.component.ts │ │ │ ├── navbar │ │ │ │ ├── active-menu.directive.ts │ │ │ │ ├── navbar-item.model.d.ts │ │ │ │ ├── navbar.component.html │ │ │ │ ├── navbar.component.scss │ │ │ │ ├── navbar.component.spec.ts │ │ │ │ └── navbar.component.ts │ │ │ └── profiles │ │ │ │ ├── page-ribbon.component.scss │ │ │ │ ├── page-ribbon.component.spec.ts │ │ │ │ ├── page-ribbon.component.ts │ │ │ │ ├── profile-info.model.ts │ │ │ │ └── profile.service.ts │ │ ├── login │ │ │ ├── login.component.html │ │ │ ├── login.component.spec.ts │ │ │ ├── login.component.ts │ │ │ ├── login.model.ts │ │ │ └── login.service.ts │ │ └── shared │ │ │ ├── alert │ │ │ ├── alert-error.component.html │ │ │ ├── alert-error.component.spec.ts │ │ │ ├── alert-error.component.ts │ │ │ ├── alert-error.model.ts │ │ │ ├── alert.component.html │ │ │ ├── alert.component.spec.ts │ │ │ └── alert.component.ts │ │ │ ├── auth │ │ │ ├── has-any-authority.directive.spec.ts │ │ │ └── has-any-authority.directive.ts │ │ │ ├── date │ │ │ ├── duration.pipe.ts │ │ │ ├── format-medium-date.pipe.spec.ts │ │ │ ├── format-medium-date.pipe.ts │ │ │ ├── format-medium-datetime.pipe.spec.ts │ │ │ ├── format-medium-datetime.pipe.ts │ │ │ └── index.ts │ │ │ ├── filter │ │ │ ├── filter.component.html │ │ │ ├── filter.component.ts │ │ │ ├── filter.model.spec.ts │ │ │ ├── filter.model.ts │ │ │ └── index.ts │ │ │ ├── language │ │ │ ├── find-language-from-key.pipe.ts │ │ │ ├── index.ts │ │ │ ├── translate.directive.spec.ts │ │ │ ├── translate.directive.ts │ │ │ └── translation.module.ts │ │ │ ├── pagination │ │ │ ├── index.ts │ │ │ ├── item-count.component.spec.ts │ │ │ └── item-count.component.ts │ │ │ ├── shared.module.ts │ │ │ ├── sort │ │ │ ├── index.ts │ │ │ ├── sort-by.directive.spec.ts │ │ │ ├── sort-by.directive.ts │ │ │ ├── sort-state.ts │ │ │ ├── sort.directive.spec.ts │ │ │ ├── sort.directive.ts │ │ │ ├── sort.service.spec.ts │ │ │ └── sort.service.ts │ │ │ └── widgets │ │ │ ├── MyWidgetRegistry.ts │ │ │ ├── button.widget.html │ │ │ ├── button.widget.ts │ │ │ ├── chat.widget.html │ │ │ ├── chat.widget.ts │ │ │ ├── readme.widget.html │ │ │ └── readme.widget.ts │ │ ├── bootstrap.ts │ │ ├── content │ │ ├── css │ │ │ └── loading.css │ │ ├── images │ │ │ ├── generating.jpg │ │ │ ├── logo-jhipster.png │ │ │ └── logo.png │ │ └── scss │ │ │ ├── _bootstrap-variables.scss │ │ │ ├── global.scss │ │ │ └── vendor.scss │ │ ├── declarations.d.ts │ │ ├── favicon.ico │ │ ├── i18n │ │ └── en │ │ │ ├── activate.json │ │ │ ├── adminAuthority.json │ │ │ ├── configuration.json │ │ │ ├── detail.json │ │ │ ├── error.json │ │ │ ├── global.json │ │ │ ├── health.json │ │ │ ├── home.json │ │ │ ├── job.json │ │ │ ├── jobSource.json │ │ │ ├── jobStatus.json │ │ │ ├── login.json │ │ │ ├── logs.json │ │ │ ├── membership.json │ │ │ ├── metrics.json │ │ │ ├── password.json │ │ │ ├── redeem.json │ │ │ ├── redeemStatus.json │ │ │ ├── register.json │ │ │ ├── reset.json │ │ │ ├── sessions.json │ │ │ ├── settings.json │ │ │ ├── tracker.json │ │ │ ├── type.json │ │ │ └── user-management.json │ │ ├── index.html │ │ ├── main.ts │ │ ├── manifest.webapp │ │ ├── robots.txt │ │ ├── sockjs-client.polyfill.ts │ │ └── swagger-ui │ │ ├── dist │ │ └── images │ │ │ └── throbber.gif │ │ └── index.html └── test │ ├── java │ └── com │ │ └── camenduru │ │ └── web │ │ ├── IntegrationTest.java │ │ ├── TechnicalStructureTest.java │ │ ├── config │ │ ├── AsyncSyncConfiguration.java │ │ ├── CRLFLogConverterTest.java │ │ ├── EmbeddedMongo.java │ │ ├── MongoDbTestContainer.java │ │ ├── SpringBootTestClassOrderer.java │ │ ├── StaticResourcesWebConfigurerTest.java │ │ ├── TestContainersSpringContextCustomizerFactory.java │ │ ├── WebConfigurerTest.java │ │ └── WebConfigurerTestController.java │ │ ├── domain │ │ ├── AssertUtils.java │ │ ├── AuthorityAsserts.java │ │ ├── AuthorityTest.java │ │ ├── AuthorityTestSamples.java │ │ ├── DetailAsserts.java │ │ ├── DetailTest.java │ │ ├── DetailTestSamples.java │ │ ├── JobAsserts.java │ │ ├── JobTest.java │ │ ├── JobTestSamples.java │ │ ├── RedeemAsserts.java │ │ ├── RedeemTest.java │ │ ├── RedeemTestSamples.java │ │ ├── TypeAsserts.java │ │ ├── TypeTest.java │ │ └── TypeTestSamples.java │ │ ├── management │ │ └── SecurityMetersServiceTests.java │ │ ├── security │ │ ├── DomainUserDetailsServiceIT.java │ │ ├── SecurityUtilsUnitTest.java │ │ └── jwt │ │ │ ├── AuthenticationIntegrationTest.java │ │ │ ├── JwtAuthenticationTestUtils.java │ │ │ ├── TokenAuthenticationIT.java │ │ │ └── TokenAuthenticationSecurityMetersIT.java │ │ ├── service │ │ ├── MailServiceIT.java │ │ ├── UserServiceIT.java │ │ └── mapper │ │ │ └── UserMapperTest.java │ │ └── web │ │ ├── filter │ │ └── SpaWebFilterIT.java │ │ └── rest │ │ ├── AccountResourceIT.java │ │ ├── AuthenticateControllerIT.java │ │ ├── AuthorityResourceIT.java │ │ ├── DetailResourceIT.java │ │ ├── JobResourceIT.java │ │ ├── PublicUserResourceIT.java │ │ ├── RedeemResourceIT.java │ │ ├── TestUtil.java │ │ ├── TypeResourceIT.java │ │ ├── UserResourceIT.java │ │ ├── WithUnauthenticatedMockUser.java │ │ └── errors │ │ ├── ExceptionTranslatorIT.java │ │ └── ExceptionTranslatorTestController.java │ ├── javascript │ └── cypress │ │ ├── .eslintrc.json │ │ ├── e2e │ │ ├── account │ │ │ ├── login-page.cy.ts │ │ │ ├── password-page.cy.ts │ │ │ ├── register-page.cy.ts │ │ │ ├── reset-password-page.cy.ts │ │ │ └── settings-page.cy.ts │ │ ├── administration │ │ │ └── administration.cy.ts │ │ ├── entity │ │ │ ├── authority.cy.ts │ │ │ ├── detail.cy.ts │ │ │ ├── job.cy.ts │ │ │ ├── redeem.cy.ts │ │ │ └── type.cy.ts │ │ └── lighthouse.audits.ts │ │ ├── fixtures │ │ └── integration-test.png │ │ ├── plugins │ │ ├── global.d.ts │ │ └── index.ts │ │ ├── support │ │ ├── account.ts │ │ ├── commands.ts │ │ ├── entity.ts │ │ ├── index.ts │ │ ├── management.ts │ │ └── navbar.ts │ │ └── tsconfig.json │ └── resources │ ├── META-INF │ └── spring.factories │ ├── config │ └── application.yml │ ├── i18n │ └── messages_en.properties │ ├── junit-platform.properties │ ├── logback.xml │ └── templates │ └── mail │ ├── activationEmail.html │ ├── creationEmail.html │ ├── passwordResetEmail.html │ └── testEmail.html ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.spec.json ├── web.service └── webpack ├── environment.js ├── logo-jhipster.png ├── proxy.conf.js └── webpack.custom.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | # We recommend you to keep these unchanged 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | 15 | # Change these settings to your own preference 16 | indent_style = space 17 | indent_size = 4 18 | 19 | [*.{ts,tsx,js,jsx,json,css,scss,yml,html,vue}] 20 | indent_size = 2 21 | 22 | [*.md] 23 | trim_trailing_whitespace = false 24 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | src/main/docker/ 3 | jest.conf.js 4 | webpack/ 5 | target/ 6 | build/ 7 | node/ 8 | coverage/ 9 | postcss.config.js 10 | target/classes/static/ 11 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | 5 | "$(dirname "$0")/../npmw" exec --no-install lint-staged 6 | -------------------------------------------------------------------------------- /.lintstagedrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | '{,**/}*.{md,json,yml,html,cjs,mjs,js,ts,tsx,css,scss,java}': ['prettier --write'], 3 | }; 4 | -------------------------------------------------------------------------------- /.mvn/jvm.config: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camenduru/web/bab4f7ee8bdc6592ed11e1d966351e7fabdd62f7/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar 19 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | .git 4 | target/ 5 | 6 | # Generated by jhipster:client 7 | target/classes/static/ 8 | 9 | # Generated by jhipster:maven 10 | target 11 | .mvn 12 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | # Prettier configuration 2 | 3 | printWidth: 140 4 | singleQuote: true 5 | tabWidth: 2 6 | useTabs: false 7 | 8 | # js and ts rules: 9 | arrowParens: avoid 10 | 11 | # jsx and tsx rules: 12 | bracketSameLine: false 13 | 14 | plugins: 15 | - prettier-plugin-packagejson 16 | - prettier-plugin-java 17 | 18 | # java rules: 19 | overrides: 20 | - files: "*.java" 21 | options: 22 | tabWidth: 4 23 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "java.compile.nullAnalysis.mode": "automatic", 3 | "java.configuration.updateBuildConfiguration": "interactive" 4 | } 5 | -------------------------------------------------------------------------------- /PRIVACY.md: -------------------------------------------------------------------------------- 1 | ## Tost's data retention policy 2 | 3 | - Tost does not store any inference data; all data expires within 12 hours. 4 | -------------------------------------------------------------------------------- /TOS.md: -------------------------------------------------------------------------------- 1 | ## Restrictions on your use of Tost’s services 2 | 3 | When using our services, you must comply with these terms and all applicable laws, rules, and regulations, and you must only use the services for authorized and acceptable purposes. Fundamentally, do not do, try to do, or encourage or help others to do any of the following: 4 | 5 | - Don’t use the services to do harm to yourself or others. Among other things, this includes trying to gain access to another user’s account or any non-public portions of the services, infringing anyone else’s intellectual property rights or any other proprietary rights, exploiting, harassing, bullying, spamming, auto-messaging, or auto-dialing people through our services. 6 | - Don’t use the services to do harm to Tost. Among other things, this includes trying to gain access to or attacking our systems, scraping our services without our written consent, transmitting viruses or other malicious code to our services, abusing or defrauding us or our payment systems, copying our product or using our intellectual property without permission, and misusing our reporting or customer service mechanisms. 7 | - Don’t use the services to do anything else that’s illegal. This includes using the services to plan or commit any crime or do anything else that is illegal. 8 | -------------------------------------------------------------------------------- /checkstyle.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'cypress'; 2 | 3 | export default defineConfig({ 4 | video: false, 5 | fixturesFolder: 'src/test/javascript/cypress/fixtures', 6 | screenshotsFolder: 'target/cypress/screenshots', 7 | downloadsFolder: 'target/cypress/downloads', 8 | videosFolder: 'target/cypress/videos', 9 | chromeWebSecurity: true, 10 | viewportWidth: 1200, 11 | viewportHeight: 720, 12 | retries: 2, 13 | env: { 14 | authenticationUrl: '/api/authenticate', 15 | jwtStorageName: 'jhi-authenticationToken', 16 | }, 17 | e2e: { 18 | // We've imported your old cypress plugins here. 19 | // You may want to clean this up later by importing these. 20 | async setupNodeEvents(on, config) { 21 | // eslint-disable-next-line @typescript-eslint/no-unsafe-return 22 | return (await import('./src/test/javascript/cypress/plugins/index')).default(on, config); 23 | }, 24 | baseUrl: 'http://localhost:8080/', 25 | specPattern: 'src/test/javascript/cypress/e2e/**/*.cy.ts', 26 | supportFile: 'src/test/javascript/cypress/support/index.ts', 27 | experimentalRunAllSpecs: true, 28 | }, 29 | }); 30 | -------------------------------------------------------------------------------- /jest.conf.js: -------------------------------------------------------------------------------- 1 | const { pathsToModuleNameMapper } = require('ts-jest'); 2 | 3 | const { 4 | compilerOptions: { paths = {}, baseUrl = './' }, 5 | } = require('./tsconfig.json'); 6 | const environment = require('./webpack/environment'); 7 | 8 | module.exports = { 9 | transformIgnorePatterns: ['!node_modules/'], 10 | resolver: 'jest-preset-angular/build/resolvers/ng-jest-resolver.js', 11 | globals: { 12 | ...environment, 13 | }, 14 | roots: ['', `/${baseUrl}`], 15 | modulePaths: [`/${baseUrl}`], 16 | setupFiles: ['jest-date-mock'], 17 | cacheDirectory: '/target/jest-cache', 18 | coverageDirectory: '/target/test-results/', 19 | moduleNameMapper: pathsToModuleNameMapper(paths, { prefix: `/${baseUrl}/` }), 20 | reporters: [ 21 | 'default', 22 | ['jest-junit', { outputDirectory: '/target/test-results/', outputName: 'TESTS-results-jest.xml' }], 23 | ['jest-sonar', { outputDirectory: './target/test-results/jest', outputName: 'TESTS-results-sonar.xml' }], 24 | ], 25 | testMatch: ['/src/main/webapp/app/**/@(*.)@(spec.ts)'], 26 | testEnvironmentOptions: { 27 | url: 'http://localhost:8080', 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /ngsw-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/service-worker/config/schema.json", 3 | "index": "/index.html", 4 | "assetGroups": [ 5 | { 6 | "name": "app", 7 | "installMode": "prefetch", 8 | "resources": { 9 | "files": ["/favicon.ico", "/index.html", "/manifest.webapp", "/*.css", "/*.js"] 10 | } 11 | }, 12 | { 13 | "name": "assets", 14 | "installMode": "lazy", 15 | "updateMode": "prefetch", 16 | "resources": { 17 | "files": ["/content/**", "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)"] 18 | } 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /npmw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | basedir=`dirname "$0"` 4 | 5 | if [ -f "$basedir/mvnw" ]; then 6 | bindir="$basedir/target/node" 7 | repodir="$basedir/target/node/node_modules" 8 | installCommand="$basedir/mvnw --batch-mode -ntp -Pwebapp frontend:install-node-and-npm@install-node-and-npm" 9 | 10 | PATH="$basedir/$builddir/:$PATH" 11 | NPM_EXE="$basedir/$builddir/node_modules/npm/bin/npm-cli.js" 12 | NODE_EXE="$basedir/$builddir/node" 13 | elif [ -f "$basedir/gradlew" ]; then 14 | bindir="$basedir/build/node/bin" 15 | repodir="$basedir/build/node/lib/node_modules" 16 | installCommand="$basedir/gradlew npmSetup" 17 | else 18 | echo "Using npm installed globally" 19 | exec npm "$@" 20 | fi 21 | 22 | NPM_EXE="$repodir/npm/bin/npm-cli.js" 23 | NODE_EXE="$bindir/node" 24 | 25 | if [ ! -x "$NPM_EXE" ] || [ ! -x "$NODE_EXE" ]; then 26 | $installCommand || true 27 | fi 28 | 29 | if [ -x "$NODE_EXE" ]; then 30 | echo "Using node installed locally $($NODE_EXE --version)" 31 | PATH="$bindir:$PATH" 32 | else 33 | NODE_EXE='node' 34 | fi 35 | 36 | if [ ! -x "$NPM_EXE" ]; then 37 | echo "Local npm not found, using npm installed globally" 38 | npm "$@" 39 | else 40 | echo "Using npm installed locally $($NODE_EXE $NPM_EXE --version)" 41 | $NODE_EXE $NPM_EXE "$@" 42 | fi 43 | -------------------------------------------------------------------------------- /npmw.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | setlocal 4 | 5 | set NPMW_DIR=%~dp0 6 | 7 | if exist "%NPMW_DIR%mvnw.cmd" ( 8 | set NODE_EXE=^"^" 9 | set NODE_PATH=%NPMW_DIR%target\node\ 10 | set NPM_EXE=^"%NPMW_DIR%target\node\npm.cmd^" 11 | set INSTALL_NPM_COMMAND=^"%NPMW_DIR%mvnw.cmd^" -Pwebapp frontend:install-node-and-npm@install-node-and-npm 12 | ) else ( 13 | set NODE_EXE=^"%NPMW_DIR%build\node\bin\node.exe^" 14 | set NODE_PATH=%NPMW_DIR%build\node\bin\ 15 | set NPM_EXE=^"%NPMW_DIR%build\node\lib\node_modules\npm\bin\npm-cli.js^" 16 | set INSTALL_NPM_COMMAND=^"%NPMW_DIR%gradlew.bat^" npmSetup 17 | ) 18 | 19 | if not exist %NPM_EXE% ( 20 | call %INSTALL_NPM_COMMAND% 21 | ) 22 | 23 | if exist %NODE_EXE% ( 24 | Rem execute local npm with local node, whilst adding local node location to the PATH for this CMD session 25 | endlocal & echo "%PATH%"|find /i "%NODE_PATH%;">nul || set "PATH=%NODE_PATH%;%PATH%" & call %NODE_EXE% %NPM_EXE% %* 26 | ) else if exist %NPM_EXE% ( 27 | Rem execute local npm, whilst adding local npm location to the PATH for this CMD session 28 | endlocal & echo "%PATH%"|find /i "%NODE_PATH%;">nul || set "PATH=%NODE_PATH%;%PATH%" & call %NPM_EXE% %* 29 | ) else ( 30 | call npm %* 31 | ) 32 | -------------------------------------------------------------------------------- /src/main/docker/app.yml: -------------------------------------------------------------------------------- 1 | # This configuration is intended for development purpose, it's **your** responsibility to harden it for production 2 | name: web 3 | services: 4 | app: 5 | image: web 6 | environment: 7 | - _JAVA_OPTIONS=-Xmx512m -Xms256m 8 | - SPRING_PROFILES_ACTIVE=prod,api-docs 9 | - MANAGEMENT_PROMETHEUS_METRICS_EXPORT_ENABLED=true 10 | - SPRING_DATA_MONGODB_URI=mongodb://mongodb:27017/web 11 | ports: 12 | - 127.0.0.1:8080:8080 13 | healthcheck: 14 | test: 15 | - CMD 16 | - curl 17 | - -f 18 | - http://localhost:8080/management/health 19 | interval: 5s 20 | timeout: 5s 21 | retries: 40 22 | depends_on: 23 | mongodb: 24 | condition: service_healthy 25 | mongodb: 26 | extends: 27 | file: ./mongodb.yml 28 | service: mongodb 29 | -------------------------------------------------------------------------------- /src/main/docker/grafana/provisioning/dashboards/dashboard.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | providers: 4 | - name: 'Prometheus' 5 | orgId: 1 6 | folder: '' 7 | type: file 8 | disableDeletion: false 9 | editable: true 10 | options: 11 | path: /etc/grafana/provisioning/dashboards 12 | -------------------------------------------------------------------------------- /src/main/docker/mongodb-cluster.yml: -------------------------------------------------------------------------------- 1 | # This configuration is intended for development purpose, it's **your** responsibility to harden it for production 2 | name: web 3 | services: 4 | mongodb: 5 | image: mongo:7.0.6 6 | # If you want to expose these ports outside your dev PC, 7 | # remove the "127.0.0.1:" prefix 8 | ports: 9 | - 127.0.0.1:27017:27017 10 | command: mongos --configdb csvr/web-mongodb-config --bind_ip 0.0.0.0 11 | mongodb-node: 12 | build: 13 | context: . 14 | dockerfile: mongodb/MongoDB.Dockerfile 15 | command: mongod --shardsvr --replSet rs1 16 | mongodb-config: 17 | image: mongo:7.0.6 18 | container_name: web-mongodb-config 19 | command: mongod --configsvr --dbpath /data/db --replSet csvr 20 | -------------------------------------------------------------------------------- /src/main/docker/mongodb.yml: -------------------------------------------------------------------------------- 1 | # This configuration is intended for development purpose, it's **your** responsibility to harden it for production 2 | name: web 3 | services: 4 | mongodb: 5 | image: mongo:7.0.6 6 | # If you want to expose these ports outside your dev PC, 7 | # remove the "127.0.0.1:" prefix 8 | ports: 9 | - 127.0.0.1:27017:27017 10 | # volumes: 11 | # - ~/volumes/jhipster/web/mongodb/:/data/db/ 12 | healthcheck: 13 | test: ['CMD', 'echo', '''db.runCommand("ping").ok''', '|', 'mongo', 'localhost:27017/test', '--quiet'] 14 | interval: 5s 15 | timeout: 5s 16 | retries: 10 17 | -------------------------------------------------------------------------------- /src/main/docker/mongodb/MongoDB.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mongo:7.0.6 2 | ADD mongodb/scripts/init_replicaset.js init_replicaset.js 3 | -------------------------------------------------------------------------------- /src/main/docker/mongodb/scripts/init_replicaset.js: -------------------------------------------------------------------------------- 1 | var status = rs.status(); 2 | if (status.errmsg === 'no replset config has been received') { 3 | rs.initiate(); 4 | } 5 | for (var i = 1; i <= param; i++) { 6 | if (i !== 1) rs.add(folder + '_web-mongodb-node_' + i + ':27018'); 7 | } 8 | var cfg = rs.conf(); 9 | cfg.members[0].host = folder + '_web-mongodb-node_1:27018'; 10 | rs.reconfig(cfg); 11 | -------------------------------------------------------------------------------- /src/main/docker/services.yml: -------------------------------------------------------------------------------- 1 | # This configuration is intended for development purpose, it's **your** responsibility to harden it for production 2 | name: web 3 | services: 4 | mongodb: 5 | extends: 6 | file: ./mongodb.yml 7 | service: mongodb 8 | -------------------------------------------------------------------------------- /src/main/docker/sonar.yml: -------------------------------------------------------------------------------- 1 | # This configuration is intended for development purpose, it's **your** responsibility to harden it for production 2 | name: web 3 | services: 4 | sonar: 5 | container_name: sonarqube 6 | image: sonarqube:10.4.1-community 7 | # Forced authentication redirect for UI is turned off for out of the box experience while trying out SonarQube 8 | # For real use cases delete SONAR_FORCEAUTHENTICATION variable or set SONAR_FORCEAUTHENTICATION=true 9 | environment: 10 | - SONAR_FORCEAUTHENTICATION=false 11 | # If you want to expose these ports outside your dev PC, 12 | # remove the "127.0.0.1:" prefix 13 | ports: 14 | - 127.0.0.1:9001:9000 15 | - 127.0.0.1:9000:9000 16 | -------------------------------------------------------------------------------- /src/main/docker/swagger-editor.yml: -------------------------------------------------------------------------------- 1 | # This configuration is intended for development purpose, it's **your** responsibility to harden it for production 2 | name: web 3 | services: 4 | swagger-editor: 5 | image: swaggerapi/swagger-editor:latest 6 | ports: 7 | - 127.0.0.1:7742:8080 8 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/ApplicationWebXml.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web; 2 | 3 | import org.springframework.boot.builder.SpringApplicationBuilder; 4 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; 5 | import tech.jhipster.config.DefaultProfileUtil; 6 | 7 | /** 8 | * This is a helper Java class that provides an alternative to creating a {@code web.xml}. 9 | * This will be invoked only when the application is deployed to a Servlet container like Tomcat, JBoss etc. 10 | */ 11 | public class ApplicationWebXml extends SpringBootServletInitializer { 12 | 13 | @Override 14 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 15 | // set a default to use when no profile is configured. 16 | DefaultProfileUtil.addDefaultProfile(application.application()); 17 | return application.sources(WebApp.class); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/GeneratedByJHipster.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web; 2 | 3 | import jakarta.annotation.Generated; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | @Generated(value = "JHipster", comments = "Generated by JHipster 8.3.0") 10 | @Retention(RetentionPolicy.SOURCE) 11 | @Target({ ElementType.TYPE }) 12 | public @interface GeneratedByJHipster { 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/aop/logging/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Logging aspect. 3 | */ 4 | package com.camenduru.web.aop.logging; 5 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/config/ApplicationProperties.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | /** 6 | * Properties specific to Web. 7 | *

8 | * Properties are configured in the {@code application.yml} file. 9 | * See {@link tech.jhipster.config.JHipsterProperties} for a good example. 10 | */ 11 | @ConfigurationProperties(prefix = "application", ignoreUnknownFields = false) 12 | public class ApplicationProperties { 13 | // jhipster-needle-application-properties-property 14 | 15 | // jhipster-needle-application-properties-property-getter 16 | 17 | // jhipster-needle-application-properties-property-class 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/config/Constants.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.config; 2 | 3 | /** 4 | * Application constants. 5 | */ 6 | public final class Constants { 7 | 8 | // Regex for acceptable logins 9 | public static final String LOGIN_REGEX = "^(?>[a-zA-Z0-9!$&*+=?^_`{|}~.-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*)|(?>[_.@A-Za-z0-9-]+)$"; 10 | 11 | public static final String SYSTEM = "system"; 12 | public static final String DEFAULT_LANGUAGE = "en"; 13 | 14 | private Constants() {} 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/config/DateTimeFormatConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.format.FormatterRegistry; 5 | import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar; 6 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 7 | 8 | /** 9 | * Configure the converters to use the ISO format for dates by default. 10 | */ 11 | @Configuration 12 | public class DateTimeFormatConfiguration implements WebMvcConfigurer { 13 | 14 | @Override 15 | public void addFormatters(FormatterRegistry registry) { 16 | DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar(); 17 | registrar.setUseIsoFormat(true); 18 | registrar.registerFormatters(registry); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/config/JacksonConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.config; 2 | 3 | import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; 4 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | @Configuration 9 | public class JacksonConfiguration { 10 | 11 | /** 12 | * Support for Java date and time API. 13 | * @return the corresponding Jackson module. 14 | */ 15 | @Bean 16 | public JavaTimeModule javaTimeModule() { 17 | return new JavaTimeModule(); 18 | } 19 | 20 | @Bean 21 | public Jdk8Module jdk8TimeModule() { 22 | return new Jdk8Module(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/config/LocaleConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.servlet.LocaleResolver; 6 | import org.springframework.web.servlet.config.annotation.*; 7 | import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; 8 | import tech.jhipster.config.locale.AngularCookieLocaleResolver; 9 | 10 | @Configuration 11 | public class LocaleConfiguration implements WebMvcConfigurer { 12 | 13 | @Bean 14 | public LocaleResolver localeResolver() { 15 | return new AngularCookieLocaleResolver("NG_TRANSLATE_LANG_KEY"); 16 | } 17 | 18 | @Override 19 | public void addInterceptors(InterceptorRegistry registry) { 20 | LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor(); 21 | localeChangeInterceptor.setParamName("language"); 22 | registry.addInterceptor(localeChangeInterceptor); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/config/LoggingAspectConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.config; 2 | 3 | import com.camenduru.web.aop.logging.LoggingAspect; 4 | import org.springframework.context.annotation.*; 5 | import org.springframework.core.env.Environment; 6 | import tech.jhipster.config.JHipsterConstants; 7 | 8 | @Configuration 9 | @EnableAspectJAutoProxy 10 | public class LoggingAspectConfiguration { 11 | 12 | @Bean 13 | @Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) 14 | public LoggingAspect loggingAspect(Environment env) { 15 | return new LoggingAspect(env); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/config/dbmigrations/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This package file was generated by JHipster 3 | */ 4 | package com.camenduru.web.config.dbmigrations; 5 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/config/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Application configuration. 3 | */ 4 | package com.camenduru.web.config; 5 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/domain/enumeration/JobSource.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.domain.enumeration; 2 | 3 | /** 4 | * The JobSource enumeration. 5 | */ 6 | public enum JobSource { 7 | WEB, 8 | IOS, 9 | ANDROID, 10 | DISCORD, 11 | PAYPAL, 12 | PATREON, 13 | OTHER, 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/domain/enumeration/JobStatus.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.domain.enumeration; 2 | 3 | /** 4 | * The JobStatus enumeration. 5 | */ 6 | public enum JobStatus { 7 | POSITIVE, 8 | NEGATIVE, 9 | WAITING, 10 | WORKING, 11 | DONE, 12 | FAILED, 13 | CANCELED, 14 | EXPIRED, 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/domain/enumeration/Membership.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.domain.enumeration; 2 | 3 | /** 4 | * The Membership enumeration. 5 | */ 6 | public enum Membership { 7 | FREE, 8 | PAID, 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/domain/enumeration/RedeemStatus.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.domain.enumeration; 2 | 3 | /** 4 | * The RedeemStatus enumeration. 5 | */ 6 | public enum RedeemStatus { 7 | WAITING, 8 | USED, 9 | FAILED, 10 | CANCELED, 11 | EXPIRED, 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/domain/enumeration/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This package file was generated by JHipster 3 | */ 4 | package com.camenduru.web.domain.enumeration; 5 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/domain/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Domain objects. 3 | */ 4 | package com.camenduru.web.domain; 5 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/management/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Application management. 3 | */ 4 | package com.camenduru.web.management; 5 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Application root. 3 | */ 4 | package com.camenduru.web; 5 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/repository/AuthorityRepository.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.repository; 2 | 3 | import com.camenduru.web.domain.Authority; 4 | import org.springframework.data.mongodb.repository.MongoRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | /** 8 | * Spring Data MongoDB repository for the Authority entity. 9 | */ 10 | @SuppressWarnings("unused") 11 | @Repository 12 | public interface AuthorityRepository extends MongoRepository {} 13 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/repository/RedeemRepository.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.repository; 2 | 3 | import com.camenduru.web.domain.Redeem; 4 | import java.util.List; 5 | import java.util.Optional; 6 | import org.springframework.data.domain.Page; 7 | import org.springframework.data.domain.Pageable; 8 | import org.springframework.data.mongodb.repository.MongoRepository; 9 | import org.springframework.data.mongodb.repository.Query; 10 | import org.springframework.stereotype.Repository; 11 | 12 | /** 13 | * Spring Data MongoDB repository for the Redeem entity. 14 | */ 15 | @Repository 16 | public interface RedeemRepository extends MongoRepository { 17 | @Query("{}") 18 | Page findAllWithEagerRelationships(Pageable pageable); 19 | 20 | @Query("{}") 21 | List findAllWithEagerRelationships(); 22 | 23 | @Query("{'id': ?0}") 24 | Optional findOneWithEagerRelationships(String id); 25 | 26 | @Query("{'code': ?0}") 27 | Redeem findOneWithCode(String code); 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/repository/TypeRepository.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.repository; 2 | 3 | import com.camenduru.web.domain.Type; 4 | import java.util.Optional; 5 | import org.springframework.data.mongodb.repository.MongoRepository; 6 | import org.springframework.data.mongodb.repository.Query; 7 | import org.springframework.stereotype.Repository; 8 | 9 | /** 10 | * Spring Data MongoDB repository for the Type entity. 11 | */ 12 | @Repository 13 | public interface TypeRepository extends MongoRepository { 14 | @Query("{'type': ?0}") 15 | Optional findByType(String type); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.repository; 2 | 3 | import com.camenduru.web.domain.User; 4 | import java.time.Instant; 5 | import java.util.List; 6 | import java.util.Optional; 7 | import org.springframework.cache.annotation.Cacheable; 8 | import org.springframework.data.domain.*; 9 | import org.springframework.data.mongodb.repository.MongoRepository; 10 | import org.springframework.stereotype.Repository; 11 | 12 | /** 13 | * Spring Data MongoDB repository for the {@link User} entity. 14 | */ 15 | @Repository 16 | public interface UserRepository extends MongoRepository { 17 | String USERS_BY_LOGIN_CACHE = "usersByLogin"; 18 | 19 | String USERS_BY_EMAIL_CACHE = "usersByEmail"; 20 | Optional findOneByActivationKey(String activationKey); 21 | List findAllByActivatedIsFalseAndActivationKeyIsNotNullAndCreatedDateBefore(Instant dateTime); 22 | Optional findOneByResetKey(String resetKey); 23 | 24 | @Cacheable(cacheNames = USERS_BY_EMAIL_CACHE) 25 | Optional findOneByEmailIgnoreCase(String email); 26 | 27 | @Cacheable(cacheNames = USERS_BY_LOGIN_CACHE) 28 | Optional findOneByLogin(String login); 29 | 30 | Page findAllByIdNotNullAndActivatedIsTrue(Pageable pageable); 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/repository/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Repository layer. 3 | */ 4 | package com.camenduru.web.repository; 5 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/security/AuthoritiesConstants.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.security; 2 | 3 | /** 4 | * Constants for Spring Security authorities. 5 | */ 6 | public final class AuthoritiesConstants { 7 | 8 | public static final String ADMIN = "ROLE_ADMIN"; 9 | 10 | public static final String USER = "ROLE_USER"; 11 | 12 | public static final String ANONYMOUS = "ROLE_ANONYMOUS"; 13 | 14 | private AuthoritiesConstants() {} 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/security/SpringSecurityAuditorAware.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.security; 2 | 3 | import com.camenduru.web.config.Constants; 4 | import java.util.Optional; 5 | import org.springframework.data.domain.AuditorAware; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * Implementation of {@link AuditorAware} based on Spring Security. 10 | */ 11 | @Component 12 | public class SpringSecurityAuditorAware implements AuditorAware { 13 | 14 | @Override 15 | public Optional getCurrentAuditor() { 16 | return Optional.of(SecurityUtils.getCurrentUserLogin().orElse(Constants.SYSTEM)); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/security/UserNotActivatedException.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.security; 2 | 3 | import org.springframework.security.core.AuthenticationException; 4 | 5 | /** 6 | * This exception is thrown in case of a not activated user trying to authenticate. 7 | */ 8 | public class UserNotActivatedException extends AuthenticationException { 9 | 10 | private static final long serialVersionUID = 1L; 11 | 12 | public UserNotActivatedException(String message) { 13 | super(message); 14 | } 15 | 16 | public UserNotActivatedException(String message, Throwable t) { 17 | super(message, t); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/security/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Application security utilities. 3 | */ 4 | package com.camenduru.web.security; 5 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/service/EmailAlreadyUsedException.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.service; 2 | 3 | public class EmailAlreadyUsedException extends RuntimeException { 4 | 5 | private static final long serialVersionUID = 1L; 6 | 7 | public EmailAlreadyUsedException() { 8 | super("Email is already in use!"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/service/EmailServiceNotAllowedException.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.service; 2 | 3 | public class EmailServiceNotAllowedException extends RuntimeException { 4 | 5 | private static final long serialVersionUID = 1L; 6 | 7 | public EmailServiceNotAllowedException() { 8 | super("Email service is not allowed!"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/service/InvalidPasswordException.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.service; 2 | 3 | public class InvalidPasswordException extends RuntimeException { 4 | 5 | private static final long serialVersionUID = 1L; 6 | 7 | public InvalidPasswordException() { 8 | super("Incorrect password"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/service/UsernameAlreadyUsedException.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.service; 2 | 3 | public class UsernameAlreadyUsedException extends RuntimeException { 4 | 5 | private static final long serialVersionUID = 1L; 6 | 7 | public UsernameAlreadyUsedException() { 8 | super("Login name already used!"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/service/chat/ChatRequestBody.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.service.chat; 2 | 3 | public class ChatRequestBody { 4 | 5 | private ChatRequestMessage[] messages; 6 | private String model; 7 | private Boolean stream; 8 | 9 | public ChatRequestMessage[] getMessages() { 10 | return this.messages; 11 | } 12 | 13 | public String getModel() { 14 | return this.model; 15 | } 16 | 17 | public Boolean getStream() { 18 | return this.stream; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/service/chat/ChatRequestMessage.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.service.chat; 2 | 3 | public class ChatRequestMessage { 4 | 5 | private String role; 6 | private String text; 7 | 8 | public String getRole() { 9 | return this.role; 10 | } 11 | 12 | public String getText() { 13 | return this.text; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/service/chat/ChatTextRespose.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.service.chat; 2 | 3 | public class ChatTextRespose { 4 | 5 | private String text; 6 | 7 | public ChatTextRespose(String text) { 8 | if (text != null) { 9 | this.text = text; 10 | } 11 | } 12 | 13 | public String getText() { 14 | return text; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/service/dto/NotifyDTO.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.service.dto; 2 | 3 | public class NotifyDTO { 4 | 5 | private String jobId; 6 | private String result; 7 | 8 | public String getJobId() { 9 | return jobId; 10 | } 11 | 12 | public void setJobid(String jobId) { 13 | this.jobId = jobId; 14 | } 15 | 16 | public String getResult() { 17 | return result; 18 | } 19 | 20 | public void setResult(String result) { 21 | this.result = result; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/service/dto/PasswordChangeDTO.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.service.dto; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * A DTO representing a password change required data - current and new password. 7 | */ 8 | public class PasswordChangeDTO implements Serializable { 9 | 10 | private static final long serialVersionUID = 1L; 11 | 12 | private String currentPassword; 13 | private String newPassword; 14 | 15 | public PasswordChangeDTO() { 16 | // Empty constructor needed for Jackson. 17 | } 18 | 19 | public PasswordChangeDTO(String currentPassword, String newPassword) { 20 | this.currentPassword = currentPassword; 21 | this.newPassword = newPassword; 22 | } 23 | 24 | public String getCurrentPassword() { 25 | return currentPassword; 26 | } 27 | 28 | public void setCurrentPassword(String currentPassword) { 29 | this.currentPassword = currentPassword; 30 | } 31 | 32 | public String getNewPassword() { 33 | return newPassword; 34 | } 35 | 36 | public void setNewPassword(String newPassword) { 37 | this.newPassword = newPassword; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/service/dto/UserDTO.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.service.dto; 2 | 3 | import com.camenduru.web.domain.User; 4 | import java.io.Serializable; 5 | 6 | /** 7 | * A DTO representing a user, with only the public attributes. 8 | */ 9 | public class UserDTO implements Serializable { 10 | 11 | private static final long serialVersionUID = 1L; 12 | 13 | private String id; 14 | 15 | private String login; 16 | 17 | public UserDTO() { 18 | // Empty constructor needed for Jackson. 19 | } 20 | 21 | public UserDTO(User user) { 22 | this.id = user.getId(); 23 | // Customize it here if you need, or not, firstName/lastName/etc 24 | this.login = user.getLogin(); 25 | } 26 | 27 | public String getId() { 28 | return id; 29 | } 30 | 31 | public void setId(String id) { 32 | this.id = id; 33 | } 34 | 35 | public String getLogin() { 36 | return login; 37 | } 38 | 39 | public void setLogin(String login) { 40 | this.login = login; 41 | } 42 | 43 | // prettier-ignore 44 | @Override 45 | public String toString() { 46 | return "UserDTO{" + 47 | "id='" + id + '\'' + 48 | ", login='" + login + '\'' + 49 | "}"; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/service/dto/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Data transfer objects for rest mapping. 3 | */ 4 | package com.camenduru.web.service.dto; 5 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/service/mapper/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Data transfer objects mappers. 3 | */ 4 | package com.camenduru.web.service.mapper; 5 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/service/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Service layer. 3 | */ 4 | package com.camenduru.web.service; 5 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/web/filter/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Request chain filters. 3 | */ 4 | package com.camenduru.web.web.filter; 5 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/web/rest/errors/EmailAlreadyUsedException.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.web.rest.errors; 2 | 3 | @SuppressWarnings("java:S110") // Inheritance tree of classes should not be too deep 4 | public class EmailAlreadyUsedException extends BadRequestAlertException { 5 | 6 | private static final long serialVersionUID = 1L; 7 | 8 | public EmailAlreadyUsedException() { 9 | super(ErrorConstants.EMAIL_ALREADY_USED_TYPE, "Email is already in use!", "userManagement", "emailexists"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/web/rest/errors/EmailServiceNotAllowedException.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.web.rest.errors; 2 | 3 | @SuppressWarnings("java:S110") // Inheritance tree of classes should not be too deep 4 | public class EmailServiceNotAllowedException extends BadRequestAlertException { 5 | 6 | private static final long serialVersionUID = 1L; 7 | 8 | public EmailServiceNotAllowedException() { 9 | super(ErrorConstants.EMAIL_SERVICE_NOT_ALLOWED_TYPE, "Email service is not allowed!", "userManagement", "emailservicenotallowed"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/web/rest/errors/ErrorConstants.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.web.rest.errors; 2 | 3 | import java.net.URI; 4 | 5 | public final class ErrorConstants { 6 | 7 | public static final String ERR_CONCURRENCY_FAILURE = "error.concurrencyFailure"; 8 | public static final String ERR_VALIDATION = "error.validation"; 9 | public static final String PROBLEM_BASE_URL = "http://localhost:8080/problem"; 10 | public static final URI DEFAULT_TYPE = URI.create(PROBLEM_BASE_URL + "/problem-with-message"); 11 | public static final URI CONSTRAINT_VIOLATION_TYPE = URI.create(PROBLEM_BASE_URL + "/constraint-violation"); 12 | public static final URI INVALID_PASSWORD_TYPE = URI.create(PROBLEM_BASE_URL + "/invalid-password"); 13 | public static final URI EMAIL_ALREADY_USED_TYPE = URI.create(PROBLEM_BASE_URL + "/email-already-used"); 14 | public static final URI EMAIL_SERVICE_NOT_ALLOWED_TYPE = URI.create(PROBLEM_BASE_URL + "/email-service-not-allowed"); 15 | public static final URI LOGIN_ALREADY_USED_TYPE = URI.create(PROBLEM_BASE_URL + "/login-already-used"); 16 | 17 | private ErrorConstants() {} 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/web/rest/errors/FieldErrorVM.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.web.rest.errors; 2 | 3 | import java.io.Serializable; 4 | 5 | public class FieldErrorVM implements Serializable { 6 | 7 | private static final long serialVersionUID = 1L; 8 | 9 | private final String objectName; 10 | 11 | private final String field; 12 | 13 | private final String message; 14 | 15 | public FieldErrorVM(String dto, String field, String message) { 16 | this.objectName = dto; 17 | this.field = field; 18 | this.message = message; 19 | } 20 | 21 | public String getObjectName() { 22 | return objectName; 23 | } 24 | 25 | public String getField() { 26 | return field; 27 | } 28 | 29 | public String getMessage() { 30 | return message; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/web/rest/errors/InvalidPasswordException.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.web.rest.errors; 2 | 3 | import org.springframework.http.HttpStatus; 4 | import org.springframework.web.ErrorResponseException; 5 | import tech.jhipster.web.rest.errors.ProblemDetailWithCause.ProblemDetailWithCauseBuilder; 6 | 7 | @SuppressWarnings("java:S110") // Inheritance tree of classes should not be too deep 8 | public class InvalidPasswordException extends ErrorResponseException { 9 | 10 | private static final long serialVersionUID = 1L; 11 | 12 | public InvalidPasswordException() { 13 | super( 14 | HttpStatus.BAD_REQUEST, 15 | ProblemDetailWithCauseBuilder.instance() 16 | .withStatus(HttpStatus.BAD_REQUEST.value()) 17 | .withType(ErrorConstants.INVALID_PASSWORD_TYPE) 18 | .withTitle("Incorrect password") 19 | .build(), 20 | null 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/web/rest/errors/LoginAlreadyUsedException.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.web.rest.errors; 2 | 3 | @SuppressWarnings("java:S110") // Inheritance tree of classes should not be too deep 4 | public class LoginAlreadyUsedException extends BadRequestAlertException { 5 | 6 | private static final long serialVersionUID = 1L; 7 | 8 | public LoginAlreadyUsedException() { 9 | super(ErrorConstants.LOGIN_ALREADY_USED_TYPE, "Login name already used!", "userManagement", "userexists"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/web/rest/errors/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Rest layer error handling. 3 | */ 4 | package com.camenduru.web.web.rest.errors; 5 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/web/rest/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Rest layer. 3 | */ 4 | package com.camenduru.web.web.rest; 5 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/web/rest/vm/KeyAndPasswordVM.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.web.rest.vm; 2 | 3 | /** 4 | * View Model object for storing the user's key and password. 5 | */ 6 | public class KeyAndPasswordVM { 7 | 8 | private String key; 9 | 10 | private String newPassword; 11 | 12 | public String getKey() { 13 | return key; 14 | } 15 | 16 | public void setKey(String key) { 17 | this.key = key; 18 | } 19 | 20 | public String getNewPassword() { 21 | return newPassword; 22 | } 23 | 24 | public void setNewPassword(String newPassword) { 25 | this.newPassword = newPassword; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/web/rest/vm/ManagedUserVM.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.web.rest.vm; 2 | 3 | import com.camenduru.web.service.dto.AdminUserDTO; 4 | import jakarta.validation.constraints.Size; 5 | 6 | /** 7 | * View Model extending the AdminUserDTO, which is meant to be used in the user management UI. 8 | */ 9 | public class ManagedUserVM extends AdminUserDTO { 10 | 11 | public static final int PASSWORD_MIN_LENGTH = 4; 12 | 13 | public static final int PASSWORD_MAX_LENGTH = 100; 14 | 15 | @Size(min = PASSWORD_MIN_LENGTH, max = PASSWORD_MAX_LENGTH) 16 | private String password; 17 | 18 | public ManagedUserVM() { 19 | // Empty constructor needed for Jackson. 20 | } 21 | 22 | public String getPassword() { 23 | return password; 24 | } 25 | 26 | public void setPassword(String password) { 27 | this.password = password; 28 | } 29 | 30 | // prettier-ignore 31 | @Override 32 | public String toString() { 33 | return "ManagedUserVM{" + super.toString() + "} "; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/web/rest/vm/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Rest layer visual models. 3 | */ 4 | package com.camenduru.web.web.rest.vm; 5 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/web/websocket/dto/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This package file was generated by JHipster 3 | */ 4 | package com.camenduru.web.web.websocket.dto; 5 | -------------------------------------------------------------------------------- /src/main/java/com/camenduru/web/web/websocket/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This package file was generated by JHipster 3 | */ 4 | package com.camenduru.web.web.websocket; 5 | -------------------------------------------------------------------------------- /src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | 2 | ${AnsiColor.GREEN} ██╗${AnsiColor.RED} ██╗ ██╗ ████████╗ ███████╗ ██████╗ ████████╗ ████████╗ ███████╗ 3 | ${AnsiColor.GREEN} ██║${AnsiColor.RED} ██║ ██║ ╚══██╔══╝ ██╔═══██╗ ██╔════╝ ╚══██╔══╝ ██╔═════╝ ██╔═══██╗ 4 | ${AnsiColor.GREEN} ██║${AnsiColor.RED} ████████║ ██║ ███████╔╝ ╚█████╗ ██║ ██████╗ ███████╔╝ 5 | ${AnsiColor.GREEN}██╗ ██║${AnsiColor.RED} ██╔═══██║ ██║ ██╔════╝ ╚═══██╗ ██║ ██╔═══╝ ██╔══██║ 6 | ${AnsiColor.GREEN}╚██████╔╝${AnsiColor.RED} ██║ ██║ ████████╗ ██║ ██████╔╝ ██║ ████████╗ ██║ ╚██╗ 7 | ${AnsiColor.GREEN} ╚═════╝ ${AnsiColor.RED} ╚═╝ ╚═╝ ╚═══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══════╝ ╚═╝ ╚═╝ 8 | 9 | ${AnsiColor.BRIGHT_BLUE}:: JHipster 🤓 :: Running Spring Boot ${spring-boot.version} :: Startup profile(s) ${spring.profiles.active} :: 10 | :: https://www.jhipster.tech ::${AnsiColor.DEFAULT} 11 | -------------------------------------------------------------------------------- /src/main/resources/config/application-tls.yml: -------------------------------------------------------------------------------- 1 | # =================================================================== 2 | # Activate this profile to enable TLS and HTTP/2. 3 | # 4 | # JHipster has generated a self-signed certificate, which will be used to encrypt traffic. 5 | # As your browser will not understand this certificate, you will need to import it. 6 | # 7 | # Another (easiest) solution with Chrome is to enable the "allow-insecure-localhost" flag 8 | # at chrome://flags/#allow-insecure-localhost 9 | # =================================================================== 10 | server: 11 | ssl: 12 | key-store: classpath:config/tls/keystore.p12 13 | key-store-password: password 14 | key-store-type: PKCS12 15 | key-alias: selfsigned 16 | ciphers: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 17 | enabled-protocols: TLSv1.2 18 | http2: 19 | enabled: true 20 | -------------------------------------------------------------------------------- /src/main/resources/config/tls/keystore.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camenduru/web/bab4f7ee8bdc6592ed11e1d966351e7fabdd62f7/src/main/resources/config/tls/keystore.p12 -------------------------------------------------------------------------------- /src/main/resources/i18n/messages.properties: -------------------------------------------------------------------------------- 1 | # Error page 2 | error.title=Your request cannot be processed 3 | error.subtitle=Sorry, an error has occurred. 4 | error.status=Status: 5 | error.message=Message: 6 | 7 | # Activation email 8 | email.activation.title=Tost account activation 9 | email.activation.greeting=Dear {0} 10 | email.activation.text1=Your Tost account has been created, please click on the URL below to activate it: 11 | email.activation.text2=Regards, 12 | email.signature=Tost Team. 13 | 14 | # Creation email 15 | email.creation.text1=Your Tost account has been created, please click on the URL below to access it: 16 | 17 | # Reset email 18 | email.reset.title=Tost password reset 19 | email.reset.greeting=Dear {0} 20 | email.reset.text1=For your Tost account a password reset was requested, please click on the URL below to reset it: 21 | email.reset.text2=Regards, 22 | -------------------------------------------------------------------------------- /src/main/resources/i18n/messages_en.properties: -------------------------------------------------------------------------------- 1 | # Error page 2 | error.title=Your request cannot be processed 3 | error.subtitle=Sorry, an error has occurred. 4 | error.status=Status: 5 | error.message=Message: 6 | 7 | # Activation email 8 | email.activation.title=Tost account activation 9 | email.activation.greeting=Dear {0} 10 | email.activation.text1=Your Tost account has been created, please click on the URL below to activate it: 11 | email.activation.text2=Regards, 12 | email.signature=Tost Team. 13 | 14 | # Creation email 15 | email.creation.text1=Your Tost account has been created, please click on the URL below to access it: 16 | 17 | # Reset email 18 | email.reset.title=Tost password reset 19 | email.reset.greeting=Dear {0} 20 | email.reset.text1=For your Tost account a password reset was requested, please click on the URL below to reset it: 21 | email.reset.text2=Regards, 22 | -------------------------------------------------------------------------------- /src/main/resources/templates/mail/activationEmail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | JHipster activation 5 | 6 | 7 | 8 | 9 |

Dear

10 |

Your JHipster account has been created, please click on the URL below to activate it:

11 |

12 | Activation link 13 |

14 |

15 | Regards, 16 |
17 | JHipster. 18 |

19 | 20 | 21 | -------------------------------------------------------------------------------- /src/main/resources/templates/mail/creationEmail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | JHipster creation 5 | 6 | 7 | 8 | 9 |

Dear

10 |

Your JHipster account has been created, please click on the URL below to access it:

11 |

12 | Login link 13 |

14 |

15 | Regards, 16 |
17 | JHipster. 18 |

19 | 20 | 21 | -------------------------------------------------------------------------------- /src/main/resources/templates/mail/passwordResetEmail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | JHipster password reset 5 | 6 | 7 | 8 | 9 |

Dear

10 |

11 | For your JHipster account a password reset was requested, please click on the URL below to reset it: 12 |

13 |

14 | Login link 15 |

16 |

17 | Regards, 18 |
19 | JHipster. 20 |

21 | 22 | 23 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | html 10 | text/html;charset=utf-8 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/main/webapp/app/account/account.route.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | 3 | import activateRoute from './activate/activate.route'; 4 | import passwordRoute from './password/password.route'; 5 | import passwordResetFinishRoute from './password-reset/finish/password-reset-finish.route'; 6 | import passwordResetInitRoute from './password-reset/init/password-reset-init.route'; 7 | import registerRoute from './register/register.route'; 8 | import settingsRoute from './settings/settings.route'; 9 | 10 | const accountRoutes: Routes = [ 11 | activateRoute, 12 | passwordRoute, 13 | passwordResetFinishRoute, 14 | passwordResetInitRoute, 15 | registerRoute, 16 | settingsRoute, 17 | ]; 18 | 19 | export default accountRoutes; 20 | -------------------------------------------------------------------------------- /src/main/webapp/app/account/activate/activate.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Activation

5 | @if (success()) { 6 |
7 | Your user account has been activated. Please 8 | sign in. 9 |
10 | } 11 | @if (error()) { 12 |
13 | Your user could not be activated. Please use the registration form to sign up. 14 |
15 | } 16 |
17 |
18 |
19 | -------------------------------------------------------------------------------- /src/main/webapp/app/account/activate/activate.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, inject, OnInit, signal } from '@angular/core'; 2 | import { ActivatedRoute, RouterModule } from '@angular/router'; 3 | import { mergeMap } from 'rxjs/operators'; 4 | 5 | import SharedModule from 'app/shared/shared.module'; 6 | import { ActivateService } from './activate.service'; 7 | 8 | @Component({ 9 | standalone: true, 10 | selector: 'jhi-activate', 11 | imports: [SharedModule, RouterModule], 12 | templateUrl: './activate.component.html', 13 | }) 14 | export default class ActivateComponent implements OnInit { 15 | error = signal(false); 16 | success = signal(false); 17 | 18 | private activateService = inject(ActivateService); 19 | private route = inject(ActivatedRoute); 20 | 21 | ngOnInit(): void { 22 | this.route.queryParams.pipe(mergeMap(params => this.activateService.get(params.key))).subscribe({ 23 | next: () => this.success.set(true), 24 | error: () => this.error.set(true), 25 | }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/webapp/app/account/activate/activate.route.ts: -------------------------------------------------------------------------------- 1 | import { Route } from '@angular/router'; 2 | 3 | import ActivateComponent from './activate.component'; 4 | 5 | const activateRoute: Route = { 6 | path: 'activate', 7 | component: ActivateComponent, 8 | title: 'activate.title', 9 | }; 10 | 11 | export default activateRoute; 12 | -------------------------------------------------------------------------------- /src/main/webapp/app/account/activate/activate.service.ts: -------------------------------------------------------------------------------- 1 | import { inject, Injectable } from '@angular/core'; 2 | import { HttpClient, HttpParams } from '@angular/common/http'; 3 | import { Observable } from 'rxjs'; 4 | 5 | import { ApplicationConfigService } from 'app/core/config/application-config.service'; 6 | 7 | @Injectable({ providedIn: 'root' }) 8 | export class ActivateService { 9 | private http = inject(HttpClient); 10 | private applicationConfigService = inject(ApplicationConfigService); 11 | 12 | get(key: string): Observable<{}> { 13 | return this.http.get(this.applicationConfigService.getEndpointFor('api/activate'), { 14 | params: new HttpParams().set('key', key), 15 | }); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/webapp/app/account/password-reset/finish/password-reset-finish.route.ts: -------------------------------------------------------------------------------- 1 | import { Route } from '@angular/router'; 2 | 3 | import PasswordResetFinishComponent from './password-reset-finish.component'; 4 | 5 | const passwordResetFinishRoute: Route = { 6 | path: 'reset/finish', 7 | component: PasswordResetFinishComponent, 8 | title: 'global.menu.account.password', 9 | }; 10 | 11 | export default passwordResetFinishRoute; 12 | -------------------------------------------------------------------------------- /src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.ts: -------------------------------------------------------------------------------- 1 | import { inject, Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import { Observable } from 'rxjs'; 4 | 5 | import { ApplicationConfigService } from 'app/core/config/application-config.service'; 6 | 7 | @Injectable({ providedIn: 'root' }) 8 | export class PasswordResetFinishService { 9 | private http = inject(HttpClient); 10 | private applicationConfigService = inject(ApplicationConfigService); 11 | 12 | save(key: string, newPassword: string): Observable<{}> { 13 | return this.http.post(this.applicationConfigService.getEndpointFor('api/account/reset-password/finish'), { key, newPassword }); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/webapp/app/account/password-reset/init/password-reset-init.route.ts: -------------------------------------------------------------------------------- 1 | import { Route } from '@angular/router'; 2 | 3 | import PasswordResetInitComponent from './password-reset-init.component'; 4 | 5 | const passwordResetInitRoute: Route = { 6 | path: 'reset/request', 7 | component: PasswordResetInitComponent, 8 | title: 'global.menu.account.password', 9 | }; 10 | 11 | export default passwordResetInitRoute; 12 | -------------------------------------------------------------------------------- /src/main/webapp/app/account/password-reset/init/password-reset-init.service.ts: -------------------------------------------------------------------------------- 1 | import { inject, Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import { Observable } from 'rxjs'; 4 | 5 | import { ApplicationConfigService } from 'app/core/config/application-config.service'; 6 | 7 | @Injectable({ providedIn: 'root' }) 8 | export class PasswordResetInitService { 9 | private http = inject(HttpClient); 10 | private applicationConfigService = inject(ApplicationConfigService); 11 | 12 | save(mail: string): Observable<{}> { 13 | return this.http.post(this.applicationConfigService.getEndpointFor('api/account/reset-password/init'), mail); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/webapp/app/account/password/password-strength-bar/password-strength-bar.component.html: -------------------------------------------------------------------------------- 1 |
2 | Password strength: 3 |
    4 |
  • 5 |
  • 6 |
  • 7 |
  • 8 |
  • 9 |
10 |
11 | -------------------------------------------------------------------------------- /src/main/webapp/app/account/password/password-strength-bar/password-strength-bar.component.scss: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | start Password strength bar style 3 | ========================================================================== */ 4 | ul#strength { 5 | display: inline; 6 | list-style: none; 7 | margin: 0; 8 | margin-left: 15px; 9 | padding: 0; 10 | vertical-align: 2px; 11 | } 12 | 13 | .point { 14 | background: #ddd; 15 | border-radius: 2px; 16 | display: inline-block; 17 | height: 5px; 18 | margin-right: 1px; 19 | width: 20px; 20 | &:last-child { 21 | margin: 0 !important; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/webapp/app/account/password/password.route.ts: -------------------------------------------------------------------------------- 1 | import { Route } from '@angular/router'; 2 | 3 | import { UserRouteAccessService } from 'app/core/auth/user-route-access.service'; 4 | import PasswordComponent from './password.component'; 5 | 6 | const passwordRoute: Route = { 7 | path: 'password', 8 | component: PasswordComponent, 9 | title: 'global.menu.account.password', 10 | canActivate: [UserRouteAccessService], 11 | }; 12 | 13 | export default passwordRoute; 14 | -------------------------------------------------------------------------------- /src/main/webapp/app/account/password/password.service.ts: -------------------------------------------------------------------------------- 1 | import { inject, Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import { Observable } from 'rxjs'; 4 | 5 | import { ApplicationConfigService } from 'app/core/config/application-config.service'; 6 | 7 | @Injectable({ providedIn: 'root' }) 8 | export class PasswordService { 9 | private http = inject(HttpClient); 10 | private applicationConfigService = inject(ApplicationConfigService); 11 | 12 | save(newPassword: string, currentPassword: string): Observable<{}> { 13 | return this.http.post(this.applicationConfigService.getEndpointFor('api/account/change-password'), { currentPassword, newPassword }); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/webapp/app/account/register/register.model.ts: -------------------------------------------------------------------------------- 1 | export class Registration { 2 | constructor( 3 | public login: string, 4 | public email: string, 5 | public password: string, 6 | public langKey: string, 7 | ) {} 8 | } 9 | -------------------------------------------------------------------------------- /src/main/webapp/app/account/register/register.route.ts: -------------------------------------------------------------------------------- 1 | import { Route } from '@angular/router'; 2 | 3 | import RegisterComponent from './register.component'; 4 | 5 | const registerRoute: Route = { 6 | path: 'register', 7 | component: RegisterComponent, 8 | title: 'register.title', 9 | }; 10 | 11 | export default registerRoute; 12 | -------------------------------------------------------------------------------- /src/main/webapp/app/account/register/register.service.ts: -------------------------------------------------------------------------------- 1 | import { inject, Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import { Observable } from 'rxjs'; 4 | 5 | import { ApplicationConfigService } from 'app/core/config/application-config.service'; 6 | import { Registration } from './register.model'; 7 | 8 | @Injectable({ providedIn: 'root' }) 9 | export class RegisterService { 10 | private http = inject(HttpClient); 11 | private applicationConfigService = inject(ApplicationConfigService); 12 | 13 | save(registration: Registration): Observable<{}> { 14 | return this.http.post(this.applicationConfigService.getEndpointFor('api/register'), registration); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/webapp/app/account/settings/settings.route.ts: -------------------------------------------------------------------------------- 1 | import { Route } from '@angular/router'; 2 | 3 | import { UserRouteAccessService } from 'app/core/auth/user-route-access.service'; 4 | import SettingsComponent from './settings.component'; 5 | 6 | const settingsRoute: Route = { 7 | path: 'settings', 8 | component: SettingsComponent, 9 | title: 'global.menu.account.settings', 10 | canActivate: [UserRouteAccessService], 11 | }; 12 | 13 | export default settingsRoute; 14 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/configuration/configuration.model.ts: -------------------------------------------------------------------------------- 1 | export interface ConfigProps { 2 | contexts: Contexts; 3 | } 4 | 5 | export interface Contexts { 6 | [key: string]: Context; 7 | } 8 | 9 | export interface Context { 10 | beans: Beans; 11 | parentId?: any; 12 | } 13 | 14 | export interface Beans { 15 | [key: string]: Bean; 16 | } 17 | 18 | export interface Bean { 19 | prefix: string; 20 | properties: any; 21 | } 22 | 23 | export interface Env { 24 | activeProfiles?: string[]; 25 | propertySources: PropertySource[]; 26 | } 27 | 28 | export interface PropertySource { 29 | name: string; 30 | properties: Properties; 31 | } 32 | 33 | export interface Properties { 34 | [key: string]: Property; 35 | } 36 | 37 | export interface Property { 38 | value: string; 39 | origin?: string; 40 | } 41 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/docs/docs.component.html: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/docs/docs.component.scss: -------------------------------------------------------------------------------- 1 | @import 'bootstrap/scss/functions'; 2 | @import 'bootswatch/dist/darkly/variables'; 3 | @import 'bootstrap/scss/variables'; 4 | 5 | iframe { 6 | background: white; 7 | } 8 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/docs/docs.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | standalone: true, 5 | selector: 'jhi-docs', 6 | templateUrl: './docs.component.html', 7 | styleUrl: './docs.component.scss', 8 | }) 9 | export default class DocsComponent {} 10 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/health/health.model.ts: -------------------------------------------------------------------------------- 1 | export type HealthStatus = 'UP' | 'DOWN' | 'UNKNOWN' | 'OUT_OF_SERVICE'; 2 | 3 | export type HealthKey = 'diskSpace' | 'mail' | 'ping' | 'livenessState' | 'readinessState' | 'mongo'; 4 | 5 | export interface Health { 6 | status: HealthStatus; 7 | components: { 8 | [key in HealthKey]?: HealthDetails; 9 | }; 10 | } 11 | 12 | export interface HealthDetails { 13 | status: HealthStatus; 14 | details?: { [key: string]: unknown }; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/health/health.service.ts: -------------------------------------------------------------------------------- 1 | import { inject, Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import { Observable } from 'rxjs'; 4 | 5 | import { ApplicationConfigService } from 'app/core/config/application-config.service'; 6 | import { Health } from './health.model'; 7 | 8 | @Injectable({ providedIn: 'root' }) 9 | export class HealthService { 10 | private http = inject(HttpClient); 11 | private applicationConfigService = inject(ApplicationConfigService); 12 | 13 | checkHealth(): Observable { 14 | return this.http.get(this.applicationConfigService.getEndpointFor('management/health')); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/health/modal/health-modal.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, inject } from '@angular/core'; 2 | import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; 3 | 4 | import SharedModule from 'app/shared/shared.module'; 5 | import { HealthKey, HealthDetails } from '../health.model'; 6 | 7 | @Component({ 8 | standalone: true, 9 | selector: 'jhi-health-modal', 10 | templateUrl: './health-modal.component.html', 11 | imports: [SharedModule], 12 | }) 13 | export default class HealthModalComponent { 14 | health?: { key: HealthKey; value: HealthDetails }; 15 | 16 | private activeModal = inject(NgbActiveModal); 17 | 18 | readableValue(value: any): string { 19 | if (this.health?.key === 'diskSpace') { 20 | // Should display storage space in an human readable unit 21 | const val = value / 1073741824; 22 | if (val > 1) { 23 | return `${val.toFixed(2)} GB`; 24 | } 25 | return `${(value / 1048576).toFixed(2)} MB`; 26 | } 27 | 28 | if (typeof value === 'object') { 29 | return JSON.stringify(value); 30 | } 31 | return String(value); 32 | } 33 | 34 | dismiss(): void { 35 | this.activeModal.dismiss(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/logs/log.model.ts: -------------------------------------------------------------------------------- 1 | export type Level = 'TRACE' | 'DEBUG' | 'INFO' | 'WARN' | 'ERROR' | 'OFF'; 2 | 3 | export interface Logger { 4 | configuredLevel: Level | null; 5 | effectiveLevel: Level; 6 | } 7 | 8 | export interface LoggersResponse { 9 | levels: Level[]; 10 | loggers: { [key: string]: Logger }; 11 | } 12 | 13 | export class Log { 14 | constructor( 15 | public name: string, 16 | public level: Level, 17 | ) {} 18 | } 19 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/logs/logs.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; 3 | 4 | import { LogsService } from './logs.service'; 5 | 6 | describe('Logs Service', () => { 7 | let service: LogsService; 8 | let httpMock: HttpTestingController; 9 | 10 | beforeEach(() => { 11 | TestBed.configureTestingModule({ 12 | imports: [HttpClientTestingModule], 13 | }); 14 | 15 | service = TestBed.inject(LogsService); 16 | httpMock = TestBed.inject(HttpTestingController); 17 | }); 18 | 19 | afterEach(() => { 20 | httpMock.verify(); 21 | }); 22 | 23 | describe('Service methods', () => { 24 | it('should change log level', () => { 25 | service.changeLevel('main', 'ERROR').subscribe(); 26 | 27 | const req = httpMock.expectOne({ method: 'POST' }); 28 | expect(req.request.body).toEqual({ configuredLevel: 'ERROR' }); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/logs/logs.service.ts: -------------------------------------------------------------------------------- 1 | import { inject, Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import { Observable } from 'rxjs'; 4 | 5 | import { ApplicationConfigService } from 'app/core/config/application-config.service'; 6 | import { LoggersResponse, Level } from './log.model'; 7 | 8 | @Injectable({ providedIn: 'root' }) 9 | export class LogsService { 10 | private http = inject(HttpClient); 11 | private applicationConfigService = inject(ApplicationConfigService); 12 | 13 | changeLevel(name: string, configuredLevel: Level): Observable<{}> { 14 | return this.http.post(this.applicationConfigService.getEndpointFor(`management/loggers/${name}`), { configuredLevel }); 15 | } 16 | 17 | findAll(): Observable { 18 | return this.http.get(this.applicationConfigService.getEndpointFor('management/loggers')); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/metrics/blocks/jvm-memory/jvm-memory.component.html: -------------------------------------------------------------------------------- 1 |

Memory

2 | 3 | @if (!updating() && jvmMemoryMetrics()) { 4 |
5 | @for (entry of jvmMemoryMetrics() | keyvalue; track $index) { 6 |
7 | @if (entry.value.max !== -1) { 8 | 9 | {{ entry.key }} 10 | ({{ entry.value.used / 1048576 | number: '1.0-0' }}M / {{ entry.value.max / 1048576 | number: '1.0-0' }}M) 11 | 12 | 13 |
Committed : {{ entry.value.committed / 1048576 | number: '1.0-0' }}M
14 | 15 | {{ (entry.value.used * 100) / entry.value.max | number: '1.0-0' }}% 16 | 17 | } @else { 18 | {{ entry.key }} {{ entry.value.used / 1048576 | number: '1.0-0' }}M 21 | } 22 |
23 | } 24 |
25 | } 26 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/metrics/blocks/jvm-memory/jvm-memory.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, input } from '@angular/core'; 2 | 3 | import SharedModule from 'app/shared/shared.module'; 4 | import { JvmMetrics } from 'app/admin/metrics/metrics.model'; 5 | 6 | @Component({ 7 | standalone: true, 8 | selector: 'jhi-jvm-memory', 9 | templateUrl: './jvm-memory.component.html', 10 | imports: [SharedModule], 11 | }) 12 | export class JvmMemoryComponent { 13 | /** 14 | * object containing all jvm memory metrics 15 | */ 16 | jvmMemoryMetrics = input<{ [key: string]: JvmMetrics }>(); 17 | 18 | /** 19 | * boolean field saying if the metrics are in the process of being updated 20 | */ 21 | updating = input(); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/metrics/blocks/metrics-cache/metrics-cache.component.ts: -------------------------------------------------------------------------------- 1 | import { ChangeDetectionStrategy, Component, input } from '@angular/core'; 2 | 3 | import SharedModule from 'app/shared/shared.module'; 4 | import { CacheMetrics } from 'app/admin/metrics/metrics.model'; 5 | import { filterNaN } from 'app/core/util/operators'; 6 | 7 | @Component({ 8 | standalone: true, 9 | selector: 'jhi-metrics-cache', 10 | templateUrl: './metrics-cache.component.html', 11 | changeDetection: ChangeDetectionStrategy.OnPush, 12 | imports: [SharedModule], 13 | }) 14 | export class MetricsCacheComponent { 15 | /** 16 | * object containing all cache related metrics 17 | */ 18 | cacheMetrics = input<{ [key: string]: CacheMetrics }>(); 19 | 20 | /** 21 | * boolean field saying if the metrics are in the process of being updated 22 | */ 23 | updating = input(); 24 | 25 | filterNaN = (n: number): number => filterNaN(n); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/metrics/blocks/metrics-datasource/metrics-datasource.component.ts: -------------------------------------------------------------------------------- 1 | import { ChangeDetectionStrategy, Component, input } from '@angular/core'; 2 | 3 | import SharedModule from 'app/shared/shared.module'; 4 | import { Databases } from 'app/admin/metrics/metrics.model'; 5 | import { filterNaN } from 'app/core/util/operators'; 6 | 7 | @Component({ 8 | standalone: true, 9 | selector: 'jhi-metrics-datasource', 10 | templateUrl: './metrics-datasource.component.html', 11 | changeDetection: ChangeDetectionStrategy.OnPush, 12 | imports: [SharedModule], 13 | }) 14 | export class MetricsDatasourceComponent { 15 | /** 16 | * object containing all datasource related metrics 17 | */ 18 | datasourceMetrics = input(); 19 | 20 | /** 21 | * boolean field saying if the metrics are in the process of being updated 22 | */ 23 | updating = input(); 24 | 25 | filterNaN = (n: number): number => filterNaN(n); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/metrics/blocks/metrics-endpoints-requests/metrics-endpoints-requests.component.html: -------------------------------------------------------------------------------- 1 |

Endpoints requests (time in millisecond)

2 | 3 | @if (!updating() && endpointsRequestsMetrics()) { 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | @for (entry of endpointsRequestsMetrics() | keyvalue; track entry.key) { 16 | @for (method of entry.value | keyvalue; track method.key) { 17 | 18 | 19 | 20 | 21 | 22 | 23 | } 24 | } 25 | 26 |
MethodEndpoint urlCountMean
{{ method.key }}{{ entry.key }}{{ method.value!.count }}{{ method.value!.mean | number: '1.0-3' }}
27 |
28 | } 29 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/metrics/blocks/metrics-endpoints-requests/metrics-endpoints-requests.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, input } from '@angular/core'; 2 | 3 | import SharedModule from 'app/shared/shared.module'; 4 | import { Services } from 'app/admin/metrics/metrics.model'; 5 | 6 | @Component({ 7 | standalone: true, 8 | selector: 'jhi-metrics-endpoints-requests', 9 | templateUrl: './metrics-endpoints-requests.component.html', 10 | imports: [SharedModule], 11 | }) 12 | export class MetricsEndpointsRequestsComponent { 13 | /** 14 | * object containing service related metrics 15 | */ 16 | endpointsRequestsMetrics = input(); 17 | 18 | /** 19 | * boolean field saying if the metrics are in the process of being updated 20 | */ 21 | updating = input(); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/metrics/blocks/metrics-garbagecollector/metrics-garbagecollector.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, input } from '@angular/core'; 2 | 3 | import SharedModule from 'app/shared/shared.module'; 4 | import { GarbageCollector } from 'app/admin/metrics/metrics.model'; 5 | 6 | @Component({ 7 | standalone: true, 8 | selector: 'jhi-metrics-garbagecollector', 9 | templateUrl: './metrics-garbagecollector.component.html', 10 | imports: [SharedModule], 11 | }) 12 | export class MetricsGarbageCollectorComponent { 13 | /** 14 | * object containing garbage collector related metrics 15 | */ 16 | garbageCollectorMetrics = input(); 17 | 18 | /** 19 | * boolean field saying if the metrics are in the process of being updated 20 | */ 21 | updating = input(); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/metrics/blocks/metrics-request/metrics-request.component.ts: -------------------------------------------------------------------------------- 1 | import { ChangeDetectionStrategy, Component, input } from '@angular/core'; 2 | 3 | import SharedModule from 'app/shared/shared.module'; 4 | import { HttpServerRequests } from 'app/admin/metrics/metrics.model'; 5 | import { filterNaN } from 'app/core/util/operators'; 6 | 7 | @Component({ 8 | standalone: true, 9 | selector: 'jhi-metrics-request', 10 | templateUrl: './metrics-request.component.html', 11 | changeDetection: ChangeDetectionStrategy.OnPush, 12 | imports: [SharedModule], 13 | }) 14 | export class MetricsRequestComponent { 15 | /** 16 | * object containing http request related metrics 17 | */ 18 | requestMetrics = input(); 19 | 20 | /** 21 | * boolean field saying if the metrics are in the process of being updated 22 | */ 23 | updating = input(); 24 | 25 | filterNaN = (n: number): number => filterNaN(n); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/metrics/metrics.service.ts: -------------------------------------------------------------------------------- 1 | import { inject, Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import { Observable } from 'rxjs'; 4 | 5 | import { ApplicationConfigService } from 'app/core/config/application-config.service'; 6 | import { Metrics, ThreadDump } from './metrics.model'; 7 | 8 | @Injectable({ providedIn: 'root' }) 9 | export class MetricsService { 10 | private http = inject(HttpClient); 11 | private applicationConfigService = inject(ApplicationConfigService); 12 | 13 | getMetrics(): Observable { 14 | return this.http.get(this.applicationConfigService.getEndpointFor('management/jhimetrics')); 15 | } 16 | 17 | threadDump(): Observable { 18 | return this.http.get(this.applicationConfigService.getEndpointFor('management/threaddump')); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/tracker/tracker.component.html: -------------------------------------------------------------------------------- 1 |
2 |

Real-time user activities

3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | @for (activity of activities; track $index) { 16 | 17 | 18 | 19 | 20 | 21 | 22 | } 23 | 24 |
UserIP AddressCurrent pageTime
{{ activity.userLogin }}{{ activity.ipAddress }}{{ activity.page }}{{ activity.time | date: 'yyyy-MM-dd HH:mm:ss' }}
25 |
26 |
27 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/user-management/delete/user-management-delete-dialog.component.html: -------------------------------------------------------------------------------- 1 | @if (user) { 2 |
3 | 8 | 9 | 16 | 17 | 26 |
27 | } 28 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/user-management/delete/user-management-delete-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, inject } from '@angular/core'; 2 | import { FormsModule } from '@angular/forms'; 3 | import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; 4 | 5 | import SharedModule from 'app/shared/shared.module'; 6 | import { User } from '../user-management.model'; 7 | import { UserManagementService } from '../service/user-management.service'; 8 | 9 | @Component({ 10 | standalone: true, 11 | selector: 'jhi-user-mgmt-delete-dialog', 12 | templateUrl: './user-management-delete-dialog.component.html', 13 | imports: [SharedModule, FormsModule], 14 | }) 15 | export default class UserManagementDeleteDialogComponent { 16 | user?: User; 17 | 18 | private userService = inject(UserManagementService); 19 | private activeModal = inject(NgbActiveModal); 20 | 21 | cancel(): void { 22 | this.activeModal.dismiss(); 23 | } 24 | 25 | confirmDelete(login: string): void { 26 | this.userService.delete(login).subscribe(() => { 27 | this.activeModal.close('deleted'); 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/user-management/detail/user-management-detail.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, input } from '@angular/core'; 2 | import { RouterModule } from '@angular/router'; 3 | import SharedModule from 'app/shared/shared.module'; 4 | 5 | import { User } from '../user-management.model'; 6 | 7 | @Component({ 8 | standalone: true, 9 | selector: 'jhi-user-mgmt-detail', 10 | templateUrl: './user-management-detail.component.html', 11 | imports: [RouterModule, SharedModule], 12 | }) 13 | export default class UserManagementDetailComponent { 14 | user = input(null); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/webapp/app/admin/user-management/user-management.model.ts: -------------------------------------------------------------------------------- 1 | export interface IUser { 2 | id: string | null; 3 | login?: string; 4 | firstName?: string | null; 5 | lastName?: string | null; 6 | email?: string; 7 | activated?: boolean; 8 | langKey?: string; 9 | authorities?: string[]; 10 | createdBy?: string; 11 | createdDate?: Date; 12 | lastModifiedBy?: string; 13 | lastModifiedDate?: Date; 14 | } 15 | 16 | export class User implements IUser { 17 | constructor( 18 | public id: string | null, 19 | public login?: string, 20 | public firstName?: string | null, 21 | public lastName?: string | null, 22 | public email?: string, 23 | public activated?: boolean, 24 | public langKey?: string, 25 | public authorities?: string[], 26 | public createdBy?: string, 27 | public createdDate?: Date, 28 | public lastModifiedBy?: string, 29 | public lastModifiedDate?: Date, 30 | ) {} 31 | } 32 | -------------------------------------------------------------------------------- /src/main/webapp/app/app-page-title-strategy.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, inject } from '@angular/core'; 2 | import { RouterStateSnapshot, TitleStrategy } from '@angular/router'; 3 | import { TranslateService } from '@ngx-translate/core'; 4 | 5 | @Injectable() 6 | export class AppPageTitleStrategy extends TitleStrategy { 7 | private translateService = inject(TranslateService); 8 | 9 | override updateTitle(routerState: RouterStateSnapshot): void { 10 | let pageTitle = this.buildTitle(routerState); 11 | if (!pageTitle) { 12 | pageTitle = 'global.title'; 13 | } 14 | this.translateService.get(pageTitle).subscribe(title => { 15 | document.title = title; 16 | }); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/webapp/app/app.constants.ts: -------------------------------------------------------------------------------- 1 | // These constants are injected via webpack DefinePlugin variables. 2 | // You can add more variables in webpack.common.js or in profile specific webpack..js files. 3 | // If you change the values in the webpack config files, you need to re run webpack to update the application 4 | 5 | declare const __DEBUG_INFO_ENABLED__: boolean; 6 | declare const __VERSION__: string; 7 | 8 | export const VERSION = __VERSION__; 9 | export const DEBUG_INFO_ENABLED = __DEBUG_INFO_ENABLED__; 10 | -------------------------------------------------------------------------------- /src/main/webapp/app/app.routes.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | 3 | import { Authority } from 'app/config/authority.constants'; 4 | import { UserRouteAccessService } from 'app/core/auth/user-route-access.service'; 5 | import { errorRoute } from './layouts/error/error.route'; 6 | 7 | import HomeComponent from './home/home.component'; 8 | import NavbarComponent from './layouts/navbar/navbar.component'; 9 | import LoginComponent from './login/login.component'; 10 | 11 | const routes: Routes = [ 12 | { 13 | path: '', 14 | component: HomeComponent, 15 | title: 'home.title', 16 | }, 17 | { 18 | path: '', 19 | component: NavbarComponent, 20 | outlet: 'navbar', 21 | }, 22 | { 23 | path: 'admin', 24 | data: { 25 | authorities: [Authority.ADMIN], 26 | }, 27 | canActivate: [UserRouteAccessService], 28 | loadChildren: () => import('./admin/admin.routes'), 29 | }, 30 | { 31 | path: 'account', 32 | loadChildren: () => import('./account/account.route'), 33 | }, 34 | { 35 | path: 'login', 36 | component: LoginComponent, 37 | title: 'login.title', 38 | }, 39 | { 40 | path: '', 41 | loadChildren: () => import(`./entities/entity.routes`), 42 | }, 43 | ...errorRoute, 44 | ]; 45 | 46 | export default routes; 47 | -------------------------------------------------------------------------------- /src/main/webapp/app/config/authority.constants.ts: -------------------------------------------------------------------------------- 1 | export enum Authority { 2 | ADMIN = 'ROLE_ADMIN', 3 | USER = 'ROLE_USER', 4 | } 5 | -------------------------------------------------------------------------------- /src/main/webapp/app/config/datepicker-adapter.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Angular bootstrap Date adapter 3 | */ 4 | import { Injectable } from '@angular/core'; 5 | import { NgbDateAdapter, NgbDateStruct } from '@ng-bootstrap/ng-bootstrap'; 6 | import dayjs from 'dayjs/esm'; 7 | 8 | @Injectable() 9 | export class NgbDateDayjsAdapter extends NgbDateAdapter { 10 | fromModel(date: dayjs.Dayjs | null): NgbDateStruct | null { 11 | if (date && dayjs.isDayjs(date) && date.isValid()) { 12 | return { year: date.year(), month: date.month() + 1, day: date.date() }; 13 | } 14 | return null; 15 | } 16 | 17 | toModel(date: NgbDateStruct | null): dayjs.Dayjs | null { 18 | return date ? dayjs(`${date.year}-${date.month}-${date.day}`) : null; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/webapp/app/config/dayjs.ts: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs/esm'; 2 | import customParseFormat from 'dayjs/esm/plugin/customParseFormat'; 3 | import duration from 'dayjs/esm/plugin/duration'; 4 | import relativeTime from 'dayjs/esm/plugin/relativeTime'; 5 | 6 | // jhipster-needle-i18n-language-dayjs-imports - JHipster will import languages from dayjs here 7 | import 'dayjs/esm/locale/en'; 8 | 9 | // DAYJS CONFIGURATION 10 | dayjs.extend(customParseFormat); 11 | dayjs.extend(duration); 12 | dayjs.extend(relativeTime); 13 | -------------------------------------------------------------------------------- /src/main/webapp/app/config/error.constants.ts: -------------------------------------------------------------------------------- 1 | export const PROBLEM_BASE_URL = 'http://localhost:8080/problem'; 2 | export const EMAIL_ALREADY_USED_TYPE = `${PROBLEM_BASE_URL}/email-already-used`; 3 | export const EMAIL_SERVICE_NOT_ALLOWED_TYPE = `${PROBLEM_BASE_URL}/email-service-not-allowed`; 4 | export const LOGIN_ALREADY_USED_TYPE = `${PROBLEM_BASE_URL}/login-already-used`; 5 | -------------------------------------------------------------------------------- /src/main/webapp/app/config/input.constants.ts: -------------------------------------------------------------------------------- 1 | export const DATE_FORMAT = 'YYYY-MM-DD'; 2 | export const DATE_TIME_FORMAT = 'YYYY-MM-DDTHH:mm'; 3 | -------------------------------------------------------------------------------- /src/main/webapp/app/config/language.constants.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Languages codes are ISO_639-1 codes, see http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes 3 | They are written in English to avoid character encoding issues (not a perfect solution) 4 | */ 5 | export const LANGUAGES: string[] = [ 6 | 'en', 7 | // jhipster-needle-i18n-language-constant - JHipster will add/remove languages in this array 8 | ]; 9 | -------------------------------------------------------------------------------- /src/main/webapp/app/config/navigation.constants.ts: -------------------------------------------------------------------------------- 1 | export const ASC = 'asc'; 2 | export const DESC = 'desc'; 3 | export const SORT = 'sort'; 4 | export const ITEM_DELETED_EVENT = 'deleted'; 5 | export const DEFAULT_SORT_DATA = 'defaultSort'; 6 | -------------------------------------------------------------------------------- /src/main/webapp/app/config/pagination.constants.ts: -------------------------------------------------------------------------------- 1 | export const TOTAL_COUNT_RESPONSE_HEADER = 'X-Total-Count'; 2 | export const PAGE_HEADER = 'page'; 3 | export const ITEMS_PER_PAGE = 20; 4 | -------------------------------------------------------------------------------- /src/main/webapp/app/config/translation.config.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { MissingTranslationHandler, MissingTranslationHandlerParams, TranslateLoader } from '@ngx-translate/core'; 3 | import { TranslateHttpLoader } from '@ngx-translate/http-loader'; 4 | 5 | export const translationNotFoundMessage = 'translation-not-found'; 6 | 7 | export class MissingTranslationHandlerImpl implements MissingTranslationHandler { 8 | handle(params: MissingTranslationHandlerParams): string { 9 | const key = params.key; 10 | return `${translationNotFoundMessage}[${key}]`; 11 | } 12 | } 13 | 14 | export function translatePartialLoader(http: HttpClient): TranslateLoader { 15 | return new TranslateHttpLoader(http, 'i18n/', `.json?_=${I18N_HASH}`); 16 | } 17 | 18 | export function missingTranslationHandler(): MissingTranslationHandler { 19 | return new MissingTranslationHandlerImpl(); 20 | } 21 | -------------------------------------------------------------------------------- /src/main/webapp/app/config/uib-pagination.config.ts: -------------------------------------------------------------------------------- 1 | import { inject, Injectable } from '@angular/core'; 2 | import { NgbPaginationConfig } from '@ng-bootstrap/ng-bootstrap'; 3 | 4 | import { ITEMS_PER_PAGE } from 'app/config/pagination.constants'; 5 | 6 | @Injectable({ providedIn: 'root' }) 7 | export class PaginationConfig { 8 | private config = inject(NgbPaginationConfig); 9 | constructor() { 10 | this.config.boundaryLinks = true; 11 | this.config.maxSize = 5; 12 | this.config.pageSize = ITEMS_PER_PAGE; 13 | this.config.size = 'sm'; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/webapp/app/core/auth/account.model.ts: -------------------------------------------------------------------------------- 1 | export class Account { 2 | constructor( 3 | public activated: boolean, 4 | public authorities: string[], 5 | public email: string, 6 | public firstName: string | null, 7 | public langKey: string, 8 | public lastName: string | null, 9 | public login: string, 10 | public imageUrl: string | null, 11 | ) {} 12 | } 13 | -------------------------------------------------------------------------------- /src/main/webapp/app/core/config/application-config.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable({ 4 | providedIn: 'root', 5 | }) 6 | export class ApplicationConfigService { 7 | private endpointPrefix = ''; 8 | private microfrontend = false; 9 | 10 | setEndpointPrefix(endpointPrefix: string): void { 11 | this.endpointPrefix = endpointPrefix; 12 | } 13 | 14 | setMicrofrontend(microfrontend = true): void { 15 | this.microfrontend = microfrontend; 16 | } 17 | 18 | isMicrofrontend(): boolean { 19 | return this.microfrontend; 20 | } 21 | 22 | getEndpointFor(api: string, microservice?: string): string { 23 | if (microservice) { 24 | return `${this.endpointPrefix}services/${microservice}/${api}`; 25 | } 26 | return `${this.endpointPrefix}${api}`; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/webapp/app/core/interceptor/auth-expired.interceptor.ts: -------------------------------------------------------------------------------- 1 | import { inject, Injectable } from '@angular/core'; 2 | import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http'; 3 | import { Observable } from 'rxjs'; 4 | import { tap } from 'rxjs/operators'; 5 | import { Router } from '@angular/router'; 6 | 7 | import { LoginService } from 'app/login/login.service'; 8 | import { StateStorageService } from 'app/core/auth/state-storage.service'; 9 | 10 | @Injectable() 11 | export class AuthExpiredInterceptor implements HttpInterceptor { 12 | private loginService = inject(LoginService); 13 | private stateStorageService = inject(StateStorageService); 14 | private router = inject(Router); 15 | 16 | intercept(request: HttpRequest, next: HttpHandler): Observable> { 17 | return next.handle(request).pipe( 18 | tap({ 19 | error: (err: HttpErrorResponse) => { 20 | if (err.status === 401 && err.url && !err.url.includes('api/account')) { 21 | this.stateStorageService.storeUrl(this.router.routerState.snapshot.url); 22 | this.loginService.logout(); 23 | this.router.navigate(['/login']); 24 | } 25 | }, 26 | }), 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/webapp/app/core/interceptor/auth.interceptor.ts: -------------------------------------------------------------------------------- 1 | import { inject, Injectable } from '@angular/core'; 2 | import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http'; 3 | import { Observable } from 'rxjs'; 4 | 5 | import { StateStorageService } from 'app/core/auth/state-storage.service'; 6 | import { ApplicationConfigService } from '../config/application-config.service'; 7 | 8 | @Injectable() 9 | export class AuthInterceptor implements HttpInterceptor { 10 | private stateStorageService = inject(StateStorageService); 11 | private applicationConfigService = inject(ApplicationConfigService); 12 | 13 | intercept(request: HttpRequest, next: HttpHandler): Observable> { 14 | const serverApiUrl = this.applicationConfigService.getEndpointFor(''); 15 | if (!request.url || (request.url.startsWith('http') && !(serverApiUrl && request.url.startsWith(serverApiUrl)))) { 16 | return next.handle(request); 17 | } 18 | 19 | const token: string | null = this.stateStorageService.getAuthenticationToken(); 20 | if (token) { 21 | request = request.clone({ 22 | setHeaders: { 23 | Authorization: `Bearer ${token}`, 24 | }, 25 | }); 26 | } 27 | return next.handle(request); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/webapp/app/core/interceptor/error-handler.interceptor.ts: -------------------------------------------------------------------------------- 1 | import { inject, Injectable } from '@angular/core'; 2 | import { HttpInterceptor, HttpRequest, HttpErrorResponse, HttpHandler, HttpEvent } from '@angular/common/http'; 3 | import { Observable } from 'rxjs'; 4 | import { tap } from 'rxjs/operators'; 5 | 6 | import { EventManager, EventWithContent } from 'app/core/util/event-manager.service'; 7 | 8 | @Injectable() 9 | export class ErrorHandlerInterceptor implements HttpInterceptor { 10 | private eventManager = inject(EventManager); 11 | 12 | intercept(request: HttpRequest, next: HttpHandler): Observable> { 13 | return next.handle(request).pipe( 14 | tap({ 15 | error: (err: HttpErrorResponse) => { 16 | if (!(err.status === 401 && (err.message === '' || err.url?.includes('api/account')))) { 17 | this.eventManager.broadcast(new EventWithContent('webApp.httpError', err)); 18 | } 19 | }, 20 | }), 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/webapp/app/core/interceptor/index.ts: -------------------------------------------------------------------------------- 1 | import { HTTP_INTERCEPTORS } from '@angular/common/http'; 2 | 3 | import { AuthInterceptor } from 'app/core/interceptor/auth.interceptor'; 4 | import { AuthExpiredInterceptor } from 'app/core/interceptor/auth-expired.interceptor'; 5 | import { ErrorHandlerInterceptor } from 'app/core/interceptor/error-handler.interceptor'; 6 | import { NotificationInterceptor } from 'app/core/interceptor/notification.interceptor'; 7 | 8 | export const httpInterceptorProviders = [ 9 | { 10 | provide: HTTP_INTERCEPTORS, 11 | useClass: AuthInterceptor, 12 | multi: true, 13 | }, 14 | { 15 | provide: HTTP_INTERCEPTORS, 16 | useClass: AuthExpiredInterceptor, 17 | multi: true, 18 | }, 19 | { 20 | provide: HTTP_INTERCEPTORS, 21 | useClass: ErrorHandlerInterceptor, 22 | multi: true, 23 | }, 24 | { 25 | provide: HTTP_INTERCEPTORS, 26 | useClass: NotificationInterceptor, 27 | multi: true, 28 | }, 29 | ]; 30 | -------------------------------------------------------------------------------- /src/main/webapp/app/core/request/request-util.ts: -------------------------------------------------------------------------------- 1 | import { HttpParams } from '@angular/common/http'; 2 | 3 | export const createRequestOption = (req?: any): HttpParams => { 4 | let options: HttpParams = new HttpParams(); 5 | 6 | if (req) { 7 | Object.entries(req).forEach(([key, val]) => { 8 | if (val !== undefined && val !== null) { 9 | for (const value of [].concat(req[key]).filter(v => v !== '')) { 10 | options = options.append(key, value); 11 | } 12 | } 13 | }); 14 | } 15 | 16 | return options; 17 | }; 18 | -------------------------------------------------------------------------------- /src/main/webapp/app/core/request/request.model.ts: -------------------------------------------------------------------------------- 1 | export interface Pagination { 2 | page: number; 3 | size: number; 4 | sort: string[]; 5 | } 6 | 7 | export interface Search { 8 | query: string; 9 | } 10 | 11 | export interface SearchWithPagination extends Search, Pagination {} 12 | -------------------------------------------------------------------------------- /src/main/webapp/app/core/tracker/tracker-activity.model.ts: -------------------------------------------------------------------------------- 1 | export class TrackerActivity { 2 | constructor( 3 | public sessionId: string, 4 | public userLogin: string, 5 | public ipAddress: string, 6 | public page: string, 7 | public time: string, 8 | ) {} 9 | } 10 | -------------------------------------------------------------------------------- /src/main/webapp/app/core/util/data-util.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { DataUtils } from './data-util.service'; 4 | 5 | describe('Data Utils Service Test', () => { 6 | let service: DataUtils; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({ 10 | providers: [DataUtils], 11 | }); 12 | service = TestBed.inject(DataUtils); 13 | }); 14 | 15 | describe('byteSize', () => { 16 | it('should return the bytesize of the text', () => { 17 | expect(service.byteSize('Hello JHipster')).toBe(`10.5 bytes`); 18 | }); 19 | }); 20 | 21 | describe('openFile', () => { 22 | it('should open the file in the new window', () => { 23 | const newWindow = { ...window }; 24 | newWindow.document.write = jest.fn(); 25 | window.open = jest.fn(() => newWindow); 26 | window.URL.createObjectURL = jest.fn(); 27 | // 'JHipster' in base64 is 'SkhpcHN0ZXI=' 28 | const data = 'SkhpcHN0ZXI='; 29 | const contentType = 'text/plain'; 30 | service.openFile(data, contentType); 31 | expect(window.open).toHaveBeenCalledTimes(1); 32 | }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /src/main/webapp/app/core/util/operators.spec.ts: -------------------------------------------------------------------------------- 1 | import { filterNaN, isPresent } from './operators'; 2 | 3 | describe('Operators Test', () => { 4 | describe('isPresent', () => { 5 | it('should remove null and undefined values', () => { 6 | expect([1, null, undefined].filter(isPresent)).toEqual([1]); 7 | }); 8 | }); 9 | 10 | describe('filterNaN', () => { 11 | it('should return 0 for NaN', () => { 12 | expect(filterNaN(NaN)).toBe(0); 13 | }); 14 | it('should return number for a number', () => { 15 | expect(filterNaN(12345)).toBe(12345); 16 | }); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/main/webapp/app/core/util/operators.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Function used to workaround https://github.com/microsoft/TypeScript/issues/16069 3 | * es2019 alternative `const filteredArr = myArr.flatMap((x) => x ? x : []);` 4 | */ 5 | export function isPresent(t: T | undefined | null | void): t is T { 6 | return t !== undefined && t !== null; 7 | } 8 | 9 | export const filterNaN = (input: number): number => (isNaN(input) ? 0 : input); 10 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/admin/authority/authority.model.ts: -------------------------------------------------------------------------------- 1 | export interface IAuthority { 2 | name: string; 3 | } 4 | 5 | export type NewAuthority = Omit & { name: null }; 6 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/admin/authority/authority.test-samples.ts: -------------------------------------------------------------------------------- 1 | import { IAuthority, NewAuthority } from './authority.model'; 2 | 3 | export const sampleWithRequiredData: IAuthority = { 4 | name: '0f92069c-b8f6-4580-bb72-2ecd8b2e1f36', 5 | }; 6 | 7 | export const sampleWithPartialData: IAuthority = { 8 | name: 'b8c9dd58-1a04-4320-bd74-ee41a1ebdc8c', 9 | }; 10 | 11 | export const sampleWithFullData: IAuthority = { 12 | name: 'e1e2bb52-2ef5-411a-be32-fcb0255e649b', 13 | }; 14 | 15 | export const sampleWithNewData: NewAuthority = { 16 | name: null, 17 | }; 18 | 19 | Object.freeze(sampleWithNewData); 20 | Object.freeze(sampleWithRequiredData); 21 | Object.freeze(sampleWithPartialData); 22 | Object.freeze(sampleWithFullData); 23 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/admin/authority/delete/authority-delete-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, inject } from '@angular/core'; 2 | import { FormsModule } from '@angular/forms'; 3 | import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; 4 | 5 | import SharedModule from 'app/shared/shared.module'; 6 | import { ITEM_DELETED_EVENT } from 'app/config/navigation.constants'; 7 | import { IAuthority } from '../authority.model'; 8 | import { AuthorityService } from '../service/authority.service'; 9 | 10 | @Component({ 11 | standalone: true, 12 | templateUrl: './authority-delete-dialog.component.html', 13 | imports: [SharedModule, FormsModule], 14 | }) 15 | export class AuthorityDeleteDialogComponent { 16 | authority?: IAuthority; 17 | 18 | protected authorityService = inject(AuthorityService); 19 | protected activeModal = inject(NgbActiveModal); 20 | 21 | cancel(): void { 22 | this.activeModal.dismiss(); 23 | } 24 | 25 | confirmDelete(id: string): void { 26 | this.authorityService.delete(id).subscribe(() => { 27 | this.activeModal.close(ITEM_DELETED_EVENT); 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/admin/authority/detail/authority-detail.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | @if (authority()) { 4 |
5 |

Authority

6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 |
14 |
Name
15 |
16 | {{ authority()!.name }} 17 |
18 |
19 | 20 | 23 |
24 | } 25 |
26 |
27 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/admin/authority/detail/authority-detail.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, input } from '@angular/core'; 2 | import { RouterModule } from '@angular/router'; 3 | 4 | import SharedModule from 'app/shared/shared.module'; 5 | import { DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe } from 'app/shared/date'; 6 | import { IAuthority } from '../authority.model'; 7 | 8 | @Component({ 9 | standalone: true, 10 | selector: 'jhi-authority-detail', 11 | templateUrl: './authority-detail.component.html', 12 | imports: [SharedModule, RouterModule, DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe], 13 | }) 14 | export class AuthorityDetailComponent { 15 | authority = input(null); 16 | 17 | previousState(): void { 18 | window.history.back(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/admin/authority/route/authority-routing-resolve.service.ts: -------------------------------------------------------------------------------- 1 | import { inject } from '@angular/core'; 2 | import { HttpResponse } from '@angular/common/http'; 3 | import { ActivatedRouteSnapshot, Router } from '@angular/router'; 4 | import { of, EMPTY, Observable } from 'rxjs'; 5 | import { mergeMap } from 'rxjs/operators'; 6 | 7 | import { IAuthority } from '../authority.model'; 8 | import { AuthorityService } from '../service/authority.service'; 9 | 10 | const authorityResolve = (route: ActivatedRouteSnapshot): Observable => { 11 | const id = route.params['name']; 12 | if (id) { 13 | return inject(AuthorityService) 14 | .find(id) 15 | .pipe( 16 | mergeMap((authority: HttpResponse) => { 17 | if (authority.body) { 18 | return of(authority.body); 19 | } else { 20 | inject(Router).navigate(['404']); 21 | return EMPTY; 22 | } 23 | }), 24 | ); 25 | } 26 | return of(null); 27 | }; 28 | 29 | export default authorityResolve; 30 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/detail/delete/detail-delete-dialog.component.html: -------------------------------------------------------------------------------- 1 | @if (detail) { 2 |
3 | 8 | 9 | 15 | 16 | 25 |
26 | } 27 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/detail/delete/detail-delete-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, inject } from '@angular/core'; 2 | import { FormsModule } from '@angular/forms'; 3 | import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; 4 | 5 | import SharedModule from 'app/shared/shared.module'; 6 | import { ITEM_DELETED_EVENT } from 'app/config/navigation.constants'; 7 | import { IDetail } from '../detail.model'; 8 | import { DetailService } from '../service/detail.service'; 9 | 10 | @Component({ 11 | standalone: true, 12 | templateUrl: './detail-delete-dialog.component.html', 13 | imports: [SharedModule, FormsModule], 14 | }) 15 | export class DetailDeleteDialogComponent { 16 | detail?: IDetail; 17 | 18 | protected detailService = inject(DetailService); 19 | protected activeModal = inject(NgbActiveModal); 20 | 21 | cancel(): void { 22 | this.activeModal.dismiss(); 23 | } 24 | 25 | confirmDelete(id: string): void { 26 | this.detailService.delete(id).subscribe(() => { 27 | this.activeModal.close(ITEM_DELETED_EVENT); 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/detail/detail.model.ts: -------------------------------------------------------------------------------- 1 | import { IUser } from 'app/entities/user/user.model'; 2 | import { Membership } from 'app/entities/enumerations/membership.model'; 3 | 4 | export interface IDetail { 5 | id: string; 6 | discord?: string | null; 7 | sourceId?: string | null; 8 | sourceChannel?: string | null; 9 | total?: string | null; 10 | login?: string | null; 11 | membership?: keyof typeof Membership | null; 12 | user?: Pick | null; 13 | } 14 | 15 | export type NewDetail = Omit & { id: null }; 16 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/detail/detail.routes.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | 3 | import { UserRouteAccessService } from 'app/core/auth/user-route-access.service'; 4 | import { DetailComponent } from './list/detail.component'; 5 | import { DetailDetailComponent } from './detail/detail-detail.component'; 6 | import { DetailUpdateComponent } from './update/detail-update.component'; 7 | import DetailResolve from './route/detail-routing-resolve.service'; 8 | 9 | const detailRoute: Routes = [ 10 | { 11 | path: '', 12 | component: DetailComponent, 13 | data: {}, 14 | canActivate: [UserRouteAccessService], 15 | }, 16 | { 17 | path: ':id/view', 18 | component: DetailDetailComponent, 19 | resolve: { 20 | detail: DetailResolve, 21 | }, 22 | canActivate: [UserRouteAccessService], 23 | }, 24 | { 25 | path: 'new', 26 | component: DetailUpdateComponent, 27 | resolve: { 28 | detail: DetailResolve, 29 | }, 30 | canActivate: [UserRouteAccessService], 31 | }, 32 | { 33 | path: ':id/edit', 34 | component: DetailUpdateComponent, 35 | resolve: { 36 | detail: DetailResolve, 37 | }, 38 | canActivate: [UserRouteAccessService], 39 | }, 40 | ]; 41 | 42 | export default detailRoute; 43 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/detail/detail/detail-detail.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, input } from '@angular/core'; 2 | import { RouterModule } from '@angular/router'; 3 | 4 | import SharedModule from 'app/shared/shared.module'; 5 | import HasAnyAuthorityDirective from 'app/shared/auth/has-any-authority.directive'; 6 | import { DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe } from 'app/shared/date'; 7 | import { IDetail } from '../detail.model'; 8 | 9 | @Component({ 10 | standalone: true, 11 | selector: 'jhi-detail-detail', 12 | templateUrl: './detail-detail.component.html', 13 | imports: [SharedModule, RouterModule, DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe, HasAnyAuthorityDirective], 14 | }) 15 | export class DetailDetailComponent { 16 | detail = input(null); 17 | 18 | previousState(): void { 19 | window.history.back(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/detail/route/detail-routing-resolve.service.ts: -------------------------------------------------------------------------------- 1 | import { inject } from '@angular/core'; 2 | import { HttpResponse } from '@angular/common/http'; 3 | import { ActivatedRouteSnapshot, Router } from '@angular/router'; 4 | import { of, EMPTY, Observable } from 'rxjs'; 5 | import { mergeMap } from 'rxjs/operators'; 6 | 7 | import { IDetail } from '../detail.model'; 8 | import { DetailService } from '../service/detail.service'; 9 | 10 | const detailResolve = (route: ActivatedRouteSnapshot): Observable => { 11 | const id = route.params['id']; 12 | if (id) { 13 | return inject(DetailService) 14 | .find(id) 15 | .pipe( 16 | mergeMap((detail: HttpResponse) => { 17 | if (detail.body) { 18 | return of(detail.body); 19 | } else { 20 | inject(Router).navigate(['404']); 21 | return EMPTY; 22 | } 23 | }), 24 | ); 25 | } 26 | return of(null); 27 | }; 28 | 29 | export default detailResolve; 30 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/entity-navbar-items.ts: -------------------------------------------------------------------------------- 1 | import NavbarItem from 'app/layouts/navbar/navbar-item.model'; 2 | 3 | export const EntityNavbarItems: NavbarItem[] = [ 4 | { 5 | name: 'Job', 6 | route: '/job', 7 | translationKey: 'global.menu.entities.job', 8 | }, 9 | { 10 | name: 'Detail', 11 | route: '/detail', 12 | translationKey: 'global.menu.entities.detail', 13 | }, 14 | { 15 | name: 'Type', 16 | route: '/type', 17 | translationKey: 'global.menu.entities.type', 18 | }, 19 | ]; 20 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/entity.routes.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | 3 | const routes: Routes = [ 4 | { 5 | path: 'authority', 6 | data: { pageTitle: 'webApp.adminAuthority.home.title' }, 7 | loadChildren: () => import('./admin/authority/authority.routes'), 8 | }, 9 | { 10 | path: 'job', 11 | data: { pageTitle: 'webApp.job.home.title' }, 12 | loadChildren: () => import('./job/job.routes'), 13 | }, 14 | { 15 | path: 'detail', 16 | data: { pageTitle: 'webApp.detail.home.title' }, 17 | loadChildren: () => import('./detail/detail.routes'), 18 | }, 19 | { 20 | path: 'type', 21 | data: { pageTitle: 'webApp.type.home.title' }, 22 | loadChildren: () => import('./type/type.routes'), 23 | }, 24 | { 25 | path: 'redeem', 26 | data: { pageTitle: 'webApp.redeem.home.title' }, 27 | loadChildren: () => import('./redeem/redeem.routes'), 28 | }, 29 | /* jhipster-needle-add-entity-route - JHipster will add entity modules routes here */ 30 | ]; 31 | 32 | export default routes; 33 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/enumerations/job-source.model.ts: -------------------------------------------------------------------------------- 1 | export enum JobSource { 2 | WEB = 'WEB', 3 | 4 | IOS = 'IOS', 5 | 6 | ANDROID = 'ANDROID', 7 | 8 | DISCORD = 'DISCORD', 9 | 10 | PAYPAL = 'PAYPAL', 11 | 12 | PATREON = 'PATREON', 13 | 14 | OTHER = 'OTHER', 15 | } 16 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/enumerations/job-status.model.ts: -------------------------------------------------------------------------------- 1 | export enum JobStatus { 2 | POSITIVE = 'POSITIVE', 3 | 4 | NEGATIVE = 'NEGATIVE', 5 | 6 | WAITING = 'WAITING', 7 | 8 | WORKING = 'WORKING', 9 | 10 | DONE = 'DONE', 11 | 12 | FAILED = 'FAILED', 13 | 14 | CANCELED = 'CANCELED', 15 | 16 | EXPIRED = 'EXPIRED', 17 | } 18 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/enumerations/membership.model.ts: -------------------------------------------------------------------------------- 1 | export enum Membership { 2 | FREE = 'FREE', 3 | 4 | PAID = 'PAID', 5 | } 6 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/enumerations/redeem-status.model.ts: -------------------------------------------------------------------------------- 1 | export enum RedeemStatus { 2 | WAITING = 'WAITING', 3 | 4 | USED = 'USED', 5 | 6 | FAILED = 'FAILED', 7 | 8 | CANCELED = 'CANCELED', 9 | 10 | EXPIRED = 'EXPIRED', 11 | } 12 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/job/delete/job-delete-dialog.component.html: -------------------------------------------------------------------------------- 1 | @if (job) { 2 |
3 | 8 | 9 | 15 | 16 | 25 |
26 | } 27 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/job/delete/job-delete-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, inject } from '@angular/core'; 2 | import { FormsModule } from '@angular/forms'; 3 | import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; 4 | 5 | import SharedModule from 'app/shared/shared.module'; 6 | import { ITEM_DELETED_EVENT } from 'app/config/navigation.constants'; 7 | import { IJob } from '../job.model'; 8 | import { JobService } from '../service/job.service'; 9 | 10 | @Component({ 11 | standalone: true, 12 | templateUrl: './job-delete-dialog.component.html', 13 | imports: [SharedModule, FormsModule], 14 | }) 15 | export class JobDeleteDialogComponent { 16 | job?: IJob; 17 | 18 | protected jobService = inject(JobService); 19 | protected activeModal = inject(NgbActiveModal); 20 | 21 | cancel(): void { 22 | this.activeModal.dismiss(); 23 | } 24 | 25 | confirmDelete(id: string): void { 26 | this.jobService.delete(id).subscribe(() => { 27 | this.activeModal.close(ITEM_DELETED_EVENT); 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/job/detail/job-detail.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, input } from '@angular/core'; 2 | import { RouterModule } from '@angular/router'; 3 | 4 | import SharedModule from 'app/shared/shared.module'; 5 | import { DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe } from 'app/shared/date'; 6 | import { IJob } from '../job.model'; 7 | 8 | @Component({ 9 | standalone: true, 10 | selector: 'jhi-job-detail', 11 | templateUrl: './job-detail.component.html', 12 | imports: [SharedModule, RouterModule, DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe], 13 | }) 14 | export class JobDetailComponent { 15 | job = input(null); 16 | 17 | previousState(): void { 18 | window.history.back(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/job/job.model.ts: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs/esm'; 2 | import { IDetail } from 'app/entities/detail/detail.model'; 3 | import { IUser } from 'app/entities/user/user.model'; 4 | import { JobStatus } from 'app/entities/enumerations/job-status.model'; 5 | import { JobSource } from 'app/entities/enumerations/job-source.model'; 6 | 7 | export interface IJob { 8 | id: string; 9 | date?: dayjs.Dayjs | null; 10 | status?: keyof typeof JobStatus | null; 11 | source?: keyof typeof JobSource | null; 12 | sourceId?: string | null; 13 | sourceChannel?: string | null; 14 | command?: string | null; 15 | type?: string | null; 16 | amount?: string | null; 17 | result?: string | null; 18 | login?: string | null; 19 | discord?: IDetail | null; 20 | total?: IDetail | null; 21 | user?: Pick | null; 22 | } 23 | 24 | export type NewJob = Omit & { id: null }; 25 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/job/job.routes.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | 3 | import { UserRouteAccessService } from 'app/core/auth/user-route-access.service'; 4 | import { JobComponent } from './list/job.component'; 5 | import { JobDetailComponent } from './detail/job-detail.component'; 6 | import { JobUpdateComponent } from './update/job-update.component'; 7 | import JobResolve from './route/job-routing-resolve.service'; 8 | 9 | const jobRoute: Routes = [ 10 | { 11 | path: '', 12 | component: JobComponent, 13 | data: {}, 14 | canActivate: [UserRouteAccessService], 15 | }, 16 | { 17 | path: ':id/view', 18 | component: JobDetailComponent, 19 | resolve: { 20 | job: JobResolve, 21 | }, 22 | canActivate: [UserRouteAccessService], 23 | }, 24 | { 25 | path: 'new', 26 | component: JobUpdateComponent, 27 | resolve: { 28 | job: JobResolve, 29 | }, 30 | canActivate: [UserRouteAccessService], 31 | }, 32 | { 33 | path: ':id/edit', 34 | component: JobUpdateComponent, 35 | resolve: { 36 | job: JobResolve, 37 | }, 38 | canActivate: [UserRouteAccessService], 39 | }, 40 | ]; 41 | 42 | export default jobRoute; 43 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/job/route/job-routing-resolve.service.ts: -------------------------------------------------------------------------------- 1 | import { inject } from '@angular/core'; 2 | import { HttpResponse } from '@angular/common/http'; 3 | import { ActivatedRouteSnapshot, Router } from '@angular/router'; 4 | import { of, EMPTY, Observable } from 'rxjs'; 5 | import { mergeMap } from 'rxjs/operators'; 6 | 7 | import { IJob } from '../job.model'; 8 | import { JobService } from '../service/job.service'; 9 | 10 | const jobResolve = (route: ActivatedRouteSnapshot): Observable => { 11 | const id = route.params['id']; 12 | if (id) { 13 | return inject(JobService) 14 | .find(id) 15 | .pipe( 16 | mergeMap((job: HttpResponse) => { 17 | if (job.body) { 18 | return of(job.body); 19 | } else { 20 | inject(Router).navigate(['404']); 21 | return EMPTY; 22 | } 23 | }), 24 | ); 25 | } 26 | return of(null); 27 | }; 28 | 29 | export default jobResolve; 30 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/redeem/delete/redeem-delete-dialog.component.html: -------------------------------------------------------------------------------- 1 | @if (redeem) { 2 |
3 | 8 | 9 | 15 | 16 | 25 |
26 | } 27 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/redeem/delete/redeem-delete-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, inject } from '@angular/core'; 2 | import { FormsModule } from '@angular/forms'; 3 | import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; 4 | 5 | import SharedModule from 'app/shared/shared.module'; 6 | import { ITEM_DELETED_EVENT } from 'app/config/navigation.constants'; 7 | import { IRedeem } from '../redeem.model'; 8 | import { RedeemService } from '../service/redeem.service'; 9 | 10 | @Component({ 11 | standalone: true, 12 | templateUrl: './redeem-delete-dialog.component.html', 13 | imports: [SharedModule, FormsModule], 14 | }) 15 | export class RedeemDeleteDialogComponent { 16 | redeem?: IRedeem; 17 | 18 | protected redeemService = inject(RedeemService); 19 | protected activeModal = inject(NgbActiveModal); 20 | 21 | cancel(): void { 22 | this.activeModal.dismiss(); 23 | } 24 | 25 | confirmDelete(id: string): void { 26 | this.redeemService.delete(id).subscribe(() => { 27 | this.activeModal.close(ITEM_DELETED_EVENT); 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/redeem/detail/redeem-detail.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, input } from '@angular/core'; 2 | import { RouterModule } from '@angular/router'; 3 | 4 | import SharedModule from 'app/shared/shared.module'; 5 | import { DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe } from 'app/shared/date'; 6 | import { IRedeem } from '../redeem.model'; 7 | 8 | @Component({ 9 | standalone: true, 10 | selector: 'jhi-redeem-detail', 11 | templateUrl: './redeem-detail.component.html', 12 | imports: [SharedModule, RouterModule, DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe], 13 | }) 14 | export class RedeemDetailComponent { 15 | redeem = input(null); 16 | 17 | previousState(): void { 18 | window.history.back(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/redeem/redeem.model.ts: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs/esm'; 2 | import { IUser } from 'app/entities/user/user.model'; 3 | import { RedeemStatus } from 'app/entities/enumerations/redeem-status.model'; 4 | 5 | export interface IRedeem { 6 | id: string; 7 | date?: dayjs.Dayjs | null; 8 | status?: keyof typeof RedeemStatus | null; 9 | type?: string | null; 10 | author?: string | null; 11 | login?: string | null; 12 | amount?: string | null; 13 | code?: string | null; 14 | user?: Pick | null; 15 | } 16 | 17 | export type NewRedeem = Omit & { id: null }; 18 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/redeem/redeem.routes.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | 3 | import { UserRouteAccessService } from 'app/core/auth/user-route-access.service'; 4 | import { RedeemComponent } from './list/redeem.component'; 5 | import { RedeemDetailComponent } from './detail/redeem-detail.component'; 6 | import { RedeemUpdateComponent } from './update/redeem-update.component'; 7 | import RedeemResolve from './route/redeem-routing-resolve.service'; 8 | 9 | const redeemRoute: Routes = [ 10 | { 11 | path: '', 12 | component: RedeemComponent, 13 | data: {}, 14 | canActivate: [UserRouteAccessService], 15 | }, 16 | { 17 | path: ':id/view', 18 | component: RedeemDetailComponent, 19 | resolve: { 20 | redeem: RedeemResolve, 21 | }, 22 | canActivate: [UserRouteAccessService], 23 | }, 24 | { 25 | path: 'new', 26 | component: RedeemUpdateComponent, 27 | resolve: { 28 | redeem: RedeemResolve, 29 | }, 30 | canActivate: [UserRouteAccessService], 31 | }, 32 | { 33 | path: ':id/edit', 34 | component: RedeemUpdateComponent, 35 | resolve: { 36 | redeem: RedeemResolve, 37 | }, 38 | canActivate: [UserRouteAccessService], 39 | }, 40 | ]; 41 | 42 | export default redeemRoute; 43 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/redeem/route/redeem-routing-resolve.service.ts: -------------------------------------------------------------------------------- 1 | import { inject } from '@angular/core'; 2 | import { HttpResponse } from '@angular/common/http'; 3 | import { ActivatedRouteSnapshot, Router } from '@angular/router'; 4 | import { of, EMPTY, Observable } from 'rxjs'; 5 | import { mergeMap } from 'rxjs/operators'; 6 | 7 | import { IRedeem } from '../redeem.model'; 8 | import { RedeemService } from '../service/redeem.service'; 9 | 10 | const redeemResolve = (route: ActivatedRouteSnapshot): Observable => { 11 | const id = route.params['id']; 12 | if (id) { 13 | return inject(RedeemService) 14 | .find(id) 15 | .pipe( 16 | mergeMap((redeem: HttpResponse) => { 17 | if (redeem.body) { 18 | return of(redeem.body); 19 | } else { 20 | inject(Router).navigate(['404']); 21 | return EMPTY; 22 | } 23 | }), 24 | ); 25 | } 26 | return of(null); 27 | }; 28 | 29 | export default redeemResolve; 30 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/type/delete/type-delete-dialog.component.html: -------------------------------------------------------------------------------- 1 | @if (type) { 2 |
3 | 8 | 9 | 15 | 16 | 25 |
26 | } 27 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/type/delete/type-delete-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, inject } from '@angular/core'; 2 | import { FormsModule } from '@angular/forms'; 3 | import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; 4 | 5 | import SharedModule from 'app/shared/shared.module'; 6 | import { ITEM_DELETED_EVENT } from 'app/config/navigation.constants'; 7 | import { IType } from '../type.model'; 8 | import { TypeService } from '../service/type.service'; 9 | 10 | @Component({ 11 | standalone: true, 12 | templateUrl: './type-delete-dialog.component.html', 13 | imports: [SharedModule, FormsModule], 14 | }) 15 | export class TypeDeleteDialogComponent { 16 | type?: IType; 17 | 18 | protected typeService = inject(TypeService); 19 | protected activeModal = inject(NgbActiveModal); 20 | 21 | cancel(): void { 22 | this.activeModal.dismiss(); 23 | } 24 | 25 | confirmDelete(id: string): void { 26 | this.typeService.delete(id).subscribe(() => { 27 | this.activeModal.close(ITEM_DELETED_EVENT); 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/type/route/type-routing-resolve.service.ts: -------------------------------------------------------------------------------- 1 | import { inject } from '@angular/core'; 2 | import { HttpResponse } from '@angular/common/http'; 3 | import { ActivatedRouteSnapshot, Router } from '@angular/router'; 4 | import { of, EMPTY, Observable } from 'rxjs'; 5 | import { mergeMap } from 'rxjs/operators'; 6 | 7 | import { IType } from '../type.model'; 8 | import { TypeService } from '../service/type.service'; 9 | 10 | const typeResolve = (route: ActivatedRouteSnapshot): Observable => { 11 | const id = route.params['id']; 12 | if (id) { 13 | return inject(TypeService) 14 | .find(id) 15 | .pipe( 16 | mergeMap((type: HttpResponse) => { 17 | if (type.body) { 18 | return of(type.body); 19 | } else { 20 | inject(Router).navigate(['404']); 21 | return EMPTY; 22 | } 23 | }), 24 | ); 25 | } 26 | return of(null); 27 | }; 28 | 29 | export default typeResolve; 30 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/type/type.model.ts: -------------------------------------------------------------------------------- 1 | export interface IType { 2 | id: string; 3 | type?: string | null; 4 | amount?: string | null; 5 | schema?: string | null; 6 | model?: string | null; 7 | title?: string | null; 8 | isDefault?: boolean | null; 9 | isActive?: boolean | null; 10 | isFree?: boolean | null; 11 | cooldown?: string | null; 12 | } 13 | 14 | export type NewType = Omit & { id: null }; 15 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/type/type.routes.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | 3 | import { UserRouteAccessService } from 'app/core/auth/user-route-access.service'; 4 | import { TypeComponent } from './list/type.component'; 5 | import { TypeDetailComponent } from './detail/type-detail.component'; 6 | import { TypeUpdateComponent } from './update/type-update.component'; 7 | import TypeResolve from './route/type-routing-resolve.service'; 8 | 9 | const typeRoute: Routes = [ 10 | { 11 | path: '', 12 | component: TypeComponent, 13 | data: {}, 14 | canActivate: [UserRouteAccessService], 15 | }, 16 | { 17 | path: ':id/view', 18 | component: TypeDetailComponent, 19 | resolve: { 20 | type: TypeResolve, 21 | }, 22 | canActivate: [UserRouteAccessService], 23 | }, 24 | { 25 | path: 'new', 26 | component: TypeUpdateComponent, 27 | resolve: { 28 | type: TypeResolve, 29 | }, 30 | canActivate: [UserRouteAccessService], 31 | }, 32 | { 33 | path: ':id/edit', 34 | component: TypeUpdateComponent, 35 | resolve: { 36 | type: TypeResolve, 37 | }, 38 | canActivate: [UserRouteAccessService], 39 | }, 40 | ]; 41 | 42 | export default typeRoute; 43 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/user/user.model.ts: -------------------------------------------------------------------------------- 1 | export interface IUser { 2 | id: string; 3 | login?: string | null; 4 | } 5 | -------------------------------------------------------------------------------- /src/main/webapp/app/entities/user/user.test-samples.ts: -------------------------------------------------------------------------------- 1 | import { IUser } from './user.model'; 2 | 3 | export const sampleWithRequiredData: IUser = { 4 | id: 'c8d822a6-ea8a-44a3-92a0-68feb8b40b1b', 5 | login: 'EAN@WJV\\0dK\\vC\\NG', 6 | }; 7 | 8 | export const sampleWithPartialData: IUser = { 9 | id: '677d5319-42eb-4b73-a4d4-844ca5ca5dde', 10 | login: '0be', 11 | }; 12 | 13 | export const sampleWithFullData: IUser = { 14 | id: '2e4654dd-e303-4ccd-95ce-00d86ed1d275', 15 | login: '3?fyv@oxU\\,DfVQG\\30j\\Tlt\\.GItGyV', 16 | }; 17 | Object.freeze(sampleWithRequiredData); 18 | Object.freeze(sampleWithPartialData); 19 | Object.freeze(sampleWithFullData); 20 | -------------------------------------------------------------------------------- /src/main/webapp/app/home/home.component.scss: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | Main page styles 3 | ========================================================================== */ 4 | -------------------------------------------------------------------------------- /src/main/webapp/app/layouts/error/error.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Error page!

5 | @if (errorMessage()) { 6 |
{{ errorMessage() }}
7 | } 8 |
9 |
10 |
11 | -------------------------------------------------------------------------------- /src/main/webapp/app/layouts/error/error.route.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | 3 | import ErrorComponent from './error.component'; 4 | 5 | export const errorRoute: Routes = [ 6 | { 7 | path: 'error', 8 | component: ErrorComponent, 9 | title: 'error.title', 10 | }, 11 | { 12 | path: 'accessdenied', 13 | component: ErrorComponent, 14 | data: { 15 | errorMessage: 'error.http.403', 16 | }, 17 | title: 'error.title', 18 | }, 19 | { 20 | path: '404', 21 | component: ErrorComponent, 22 | data: { 23 | errorMessage: 'error.http.404', 24 | }, 25 | title: 'error.title', 26 | }, 27 | { 28 | path: '**', 29 | redirectTo: '/404', 30 | }, 31 | ]; 32 | -------------------------------------------------------------------------------- /src/main/webapp/app/layouts/main/main.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 | 7 |
8 |
9 | 10 |
11 | 12 | 13 |
14 | -------------------------------------------------------------------------------- /src/main/webapp/app/layouts/navbar/active-menu.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, OnInit, ElementRef, Renderer2, inject, Input } from '@angular/core'; 2 | import { TranslateService, LangChangeEvent } from '@ngx-translate/core'; 3 | 4 | @Directive({ 5 | standalone: true, 6 | selector: '[jhiActiveMenu]', 7 | }) 8 | export default class ActiveMenuDirective implements OnInit { 9 | @Input() jhiActiveMenu?: string; 10 | 11 | private el = inject(ElementRef); 12 | private renderer = inject(Renderer2); 13 | private translateService = inject(TranslateService); 14 | 15 | ngOnInit(): void { 16 | this.translateService.onLangChange.subscribe((event: LangChangeEvent) => { 17 | this.updateActiveFlag(event.lang); 18 | }); 19 | 20 | this.updateActiveFlag(this.translateService.currentLang); 21 | } 22 | 23 | updateActiveFlag(selectedLanguage: string): void { 24 | if (this.jhiActiveMenu === selectedLanguage) { 25 | this.renderer.addClass(this.el.nativeElement, 'active'); 26 | } else { 27 | this.renderer.removeClass(this.el.nativeElement, 'active'); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/webapp/app/layouts/navbar/navbar-item.model.d.ts: -------------------------------------------------------------------------------- 1 | type NavbarItem = { 2 | name: string; 3 | route: string; 4 | translationKey: string; 5 | }; 6 | 7 | export default NavbarItem; 8 | -------------------------------------------------------------------------------- /src/main/webapp/app/layouts/profiles/page-ribbon.component.scss: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | Development Ribbon 3 | ========================================================================== */ 4 | .ribbon { 5 | background-color: rgba(170, 0, 0, 0.5); 6 | overflow: hidden; 7 | position: absolute; 8 | top: 40px; 9 | white-space: nowrap; 10 | width: 15em; 11 | z-index: 9999; 12 | pointer-events: none; 13 | opacity: 0.75; 14 | a { 15 | color: #fff; 16 | display: block; 17 | font-weight: 400; 18 | margin: 1px 0; 19 | padding: 10px 50px; 20 | text-align: center; 21 | text-decoration: none; 22 | text-shadow: 0 0 5px #444; 23 | pointer-events: none; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/webapp/app/layouts/profiles/page-ribbon.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, inject, OnInit } from '@angular/core'; 2 | import { Observable } from 'rxjs'; 3 | import { map } from 'rxjs/operators'; 4 | 5 | import SharedModule from 'app/shared/shared.module'; 6 | import { ProfileService } from './profile.service'; 7 | 8 | @Component({ 9 | standalone: true, 10 | selector: 'jhi-page-ribbon', 11 | template: ` 12 | @if (ribbonEnv$ | async; as ribbonEnv) { 13 | 16 | } 17 | `, 18 | styleUrl: './page-ribbon.component.scss', 19 | imports: [SharedModule], 20 | }) 21 | export default class PageRibbonComponent implements OnInit { 22 | ribbonEnv$?: Observable; 23 | 24 | private profileService = inject(ProfileService); 25 | 26 | ngOnInit(): void { 27 | this.ribbonEnv$ = this.profileService.getProfileInfo().pipe(map(profileInfo => profileInfo.ribbonEnv)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/webapp/app/layouts/profiles/profile-info.model.ts: -------------------------------------------------------------------------------- 1 | export interface InfoResponse { 2 | 'display-ribbon-on-profiles'?: string; 3 | git?: any; 4 | build?: any; 5 | activeProfiles?: string[]; 6 | } 7 | 8 | export class ProfileInfo { 9 | constructor( 10 | public activeProfiles?: string[], 11 | public ribbonEnv?: string, 12 | public inProduction?: boolean, 13 | public openAPIEnabled?: boolean, 14 | ) {} 15 | } 16 | -------------------------------------------------------------------------------- /src/main/webapp/app/login/login.model.ts: -------------------------------------------------------------------------------- 1 | export class Login { 2 | constructor( 3 | public username: string, 4 | public password: string, 5 | public rememberMe: boolean, 6 | ) {} 7 | } 8 | -------------------------------------------------------------------------------- /src/main/webapp/app/login/login.service.ts: -------------------------------------------------------------------------------- 1 | import { inject, Injectable } from '@angular/core'; 2 | import { Observable } from 'rxjs'; 3 | import { mergeMap } from 'rxjs/operators'; 4 | 5 | import { Account } from 'app/core/auth/account.model'; 6 | import { AccountService } from 'app/core/auth/account.service'; 7 | import { AuthServerProvider } from 'app/core/auth/auth-jwt.service'; 8 | import { Login } from './login.model'; 9 | 10 | @Injectable({ providedIn: 'root' }) 11 | export class LoginService { 12 | private accountService = inject(AccountService); 13 | private authServerProvider = inject(AuthServerProvider); 14 | 15 | login(credentials: Login): Observable { 16 | return this.authServerProvider.login(credentials).pipe(mergeMap(() => this.accountService.identity(true))); 17 | } 18 | 19 | logout(): void { 20 | this.authServerProvider.logout().subscribe({ complete: () => this.accountService.authenticate(null) }); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/alert/alert-error.component.html: -------------------------------------------------------------------------------- 1 | 12 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/alert/alert-error.model.ts: -------------------------------------------------------------------------------- 1 | export class AlertError { 2 | constructor( 3 | public message: string, 4 | public key?: string, 5 | public params?: { [key: string]: unknown }, 6 | ) {} 7 | } 8 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/alert/alert.component.html: -------------------------------------------------------------------------------- 1 | 12 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/alert/alert.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, inject, OnDestroy, OnInit, signal } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; 4 | 5 | import { AlertService, Alert } from 'app/core/util/alert.service'; 6 | 7 | @Component({ 8 | standalone: true, 9 | selector: 'jhi-alert', 10 | templateUrl: './alert.component.html', 11 | imports: [CommonModule, NgbModule], 12 | }) 13 | export class AlertComponent implements OnInit, OnDestroy { 14 | alerts = signal([]); 15 | 16 | private alertService = inject(AlertService); 17 | 18 | ngOnInit(): void { 19 | this.alerts.set(this.alertService.get()); 20 | } 21 | 22 | setClasses(alert: Alert): { [key: string]: boolean } { 23 | const classes = { 'jhi-toast': Boolean(alert.toast) }; 24 | if (alert.position) { 25 | return { ...classes, [alert.position]: true }; 26 | } 27 | return classes; 28 | } 29 | 30 | ngOnDestroy(): void { 31 | this.alertService.clear(); 32 | } 33 | 34 | close(alert: Alert): void { 35 | alert.close?.(this.alerts()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/date/duration.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | import dayjs from 'dayjs/esm'; 4 | 5 | @Pipe({ 6 | standalone: true, 7 | name: 'duration', 8 | }) 9 | export default class DurationPipe implements PipeTransform { 10 | transform(value: any): string { 11 | if (value) { 12 | return dayjs.duration(value).humanize(); 13 | } 14 | return ''; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/date/format-medium-date.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs/esm'; 2 | 3 | import FormatMediumDatePipe from './format-medium-date.pipe'; 4 | 5 | describe('FormatMediumDatePipe', () => { 6 | const formatMediumDatePipe = new FormatMediumDatePipe(); 7 | 8 | it('should return an empty string when receive undefined', () => { 9 | expect(formatMediumDatePipe.transform(undefined)).toBe(''); 10 | }); 11 | 12 | it('should return an empty string when receive null', () => { 13 | expect(formatMediumDatePipe.transform(null)).toBe(''); 14 | }); 15 | 16 | it('should format date like this D MMM YYYY', () => { 17 | expect(formatMediumDatePipe.transform(dayjs('2020-11-16').locale('fr'))).toBe('16 Nov 2020'); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/date/format-medium-date.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | import dayjs from 'dayjs/esm'; 4 | 5 | @Pipe({ 6 | standalone: true, 7 | name: 'formatMediumDate', 8 | }) 9 | export default class FormatMediumDatePipe implements PipeTransform { 10 | transform(day: dayjs.Dayjs | null | undefined): string { 11 | return day ? day.format('D MMM YYYY') : ''; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/date/format-medium-datetime.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs/esm'; 2 | 3 | import FormatMediumDatetimePipe from './format-medium-datetime.pipe'; 4 | 5 | describe('FormatMediumDatePipe', () => { 6 | const formatMediumDatetimePipe = new FormatMediumDatetimePipe(); 7 | 8 | it('should return an empty string when receive undefined', () => { 9 | expect(formatMediumDatetimePipe.transform(undefined)).toBe(''); 10 | }); 11 | 12 | it('should return an empty string when receive null', () => { 13 | expect(formatMediumDatetimePipe.transform(null)).toBe(''); 14 | }); 15 | 16 | it('should format date like this D MMM YYYY', () => { 17 | expect(formatMediumDatetimePipe.transform(dayjs('2020-11-16').locale('fr'))).toBe('16 Nov 2020 00:00:00'); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/date/format-medium-datetime.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | import dayjs from 'dayjs/esm'; 4 | 5 | @Pipe({ 6 | standalone: true, 7 | name: 'formatMediumDatetime', 8 | }) 9 | export default class FormatMediumDatetimePipe implements PipeTransform { 10 | transform(day: dayjs.Dayjs | null | undefined): string { 11 | return day ? day.format('D MMM YYYY HH:mm:ss') : ''; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/date/index.ts: -------------------------------------------------------------------------------- 1 | export { default as DurationPipe } from './duration.pipe'; 2 | export { default as FormatMediumDatePipe } from './format-medium-date.pipe'; 3 | export { default as FormatMediumDatetimePipe } from './format-medium-datetime.pipe'; 4 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/filter/filter.component.html: -------------------------------------------------------------------------------- 1 | @if (filters.hasAnyFilterSet()) { 2 |
3 | Following filters are set 4 | 5 |
    6 | @for (filterOption of filters.filterOptions; track filterOption.name) { 7 | @for (value of filterOption.values; track value) { 8 |
  • 9 | {{ filterOption.name }}: {{ value }} 10 | 15 |
  • 16 | } 17 | } 18 |
19 |
20 | } 21 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/filter/filter.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | import SharedModule from '../shared.module'; 3 | import { IFilterOptions } from './filter.model'; 4 | 5 | @Component({ 6 | standalone: true, 7 | selector: 'jhi-filter', 8 | imports: [SharedModule], 9 | templateUrl: './filter.component.html', 10 | }) 11 | export default class FilterComponent { 12 | @Input() filters!: IFilterOptions; 13 | 14 | clearAllFilters(): void { 15 | this.filters.clear(); 16 | } 17 | 18 | clearFilter(filterName: string, value: string): void { 19 | this.filters.removeFilter(filterName, value); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/filter/index.ts: -------------------------------------------------------------------------------- 1 | export { default as FilterComponent } from './filter.component'; 2 | export * from './filter.model'; 3 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/language/find-language-from-key.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | standalone: true, 5 | name: 'findLanguageFromKey', 6 | }) 7 | export default class FindLanguageFromKeyPipe implements PipeTransform { 8 | private languages: { [key: string]: { name: string; rtl?: boolean } } = { 9 | en: { name: 'English' }, 10 | // jhipster-needle-i18n-language-key-pipe - JHipster will add/remove languages in this object 11 | }; 12 | 13 | transform(lang: string): string { 14 | return this.languages[lang].name; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/language/index.ts: -------------------------------------------------------------------------------- 1 | export { default as TranslateDirective } from './translate.directive'; 2 | export { default as FindLanguageFromKeyPipe } from './find-language-from-key.pipe'; 3 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/language/translate.directive.spec.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 3 | import { TranslateModule, TranslateService } from '@ngx-translate/core'; 4 | 5 | import TranslateDirective from './translate.directive'; 6 | 7 | @Component({ 8 | template: `
`, 9 | }) 10 | class TestTranslateDirectiveComponent {} 11 | 12 | describe('TranslateDirective Tests', () => { 13 | let fixture: ComponentFixture; 14 | let translateService: TranslateService; 15 | 16 | beforeEach(waitForAsync(() => { 17 | TestBed.configureTestingModule({ 18 | imports: [TranslateModule.forRoot(), TranslateDirective], 19 | declarations: [TestTranslateDirectiveComponent], 20 | }); 21 | })); 22 | 23 | beforeEach(() => { 24 | translateService = TestBed.inject(TranslateService); 25 | fixture = TestBed.createComponent(TestTranslateDirectiveComponent); 26 | }); 27 | 28 | it('should change HTML', () => { 29 | const spy = jest.spyOn(translateService, 'get'); 30 | 31 | fixture.detectChanges(); 32 | 33 | expect(spy).toHaveBeenCalled(); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/pagination/index.ts: -------------------------------------------------------------------------------- 1 | export { default as ItemCountComponent } from './item-count.component'; 2 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/sort/index.ts: -------------------------------------------------------------------------------- 1 | export * from './sort-by.directive'; 2 | export * from './sort-state'; 3 | export * from './sort.directive'; 4 | export * from './sort.service'; 5 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/sort/sort-state.ts: -------------------------------------------------------------------------------- 1 | import { signal, Signal, WritableSignal } from '@angular/core'; 2 | 3 | export type SortOrder = 'asc' | 'desc'; 4 | 5 | export type SortState = { predicate?: string; order?: SortOrder }; 6 | 7 | export type SortStateSignal = Signal; 8 | 9 | export const sortStateSignal = (state: SortState): WritableSignal => 10 | signal(state, { 11 | equal: (a, b) => a.predicate === b.predicate && a.order === b.order, 12 | }); 13 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/sort/sort.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, EventEmitter, Input, Output } from '@angular/core'; 2 | import { SortOrder, SortState, SortStateSignal } from './sort-state'; 3 | 4 | export interface SortChangeDirective { 5 | sortChange: EventEmitter; 6 | 7 | sort(field: T): void; 8 | } 9 | 10 | @Directive({ 11 | standalone: true, 12 | selector: '[jhiSort]', 13 | }) 14 | export class SortDirective implements SortChangeDirective { 15 | @Input() sortState!: SortStateSignal; 16 | 17 | @Output() sortChange = new EventEmitter(); 18 | 19 | sort(field: string): void { 20 | const { predicate, order } = this.sortState(); 21 | const toggle = (): SortOrder => (order === 'asc' ? 'desc' : 'asc'); 22 | this.sortChange.emit({ predicate: field, order: field !== predicate ? 'asc' : toggle() }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/widgets/MyWidgetRegistry.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { DefaultWidgetRegistry } from 'ngx-schema-form'; 3 | import { ButtonWidget } from './button.widget'; 4 | import { ReadmeWidget } from './readme.widget'; 5 | import { ChatWidget } from './chat.widget'; 6 | 7 | @Injectable() 8 | export class MyWidgetRegistry extends DefaultWidgetRegistry { 9 | constructor() { 10 | super(); 11 | this.register('button', ButtonWidget); 12 | this.register('readme', ReadmeWidget); 13 | this.register('chat', ChatWidget); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/widgets/button.widget.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/widgets/button.widget.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import { Component, AfterViewInit } from '@angular/core'; 3 | 4 | @Component({ 5 | selector: 'sf-button-widget', 6 | templateUrl: 'button.widget.html', 7 | }) 8 | export class ButtonWidget implements AfterViewInit { 9 | button: any; 10 | formProperty: any; 11 | 12 | ngAfterViewInit(): void { 13 | const llmButtons = document.querySelectorAll('.llm') as NodeListOf; 14 | if (this.formProperty.findRoot().getProperty('chat')) { 15 | llmButtons.forEach((button: HTMLButtonElement) => { 16 | button.style.display = 'none'; 17 | }); 18 | } else { 19 | llmButtons.forEach((button: HTMLButtonElement) => { 20 | button.style.display = 'block'; 21 | }); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/widgets/readme.widget.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | [{{ tag }}] {{ schema.title }} 4 |
5 |
6 |

{{ schema.author }}

7 | Code 8 | Paper 9 | Page 10 | Jupyter 11 | Replicate 12 | Post 13 |
14 |
15 |
16 | -------------------------------------------------------------------------------- /src/main/webapp/app/shared/widgets/readme.widget.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import { Component } from '@angular/core'; 3 | import { ControlWidget } from 'ngx-schema-form'; 4 | import { CommonModule } from '@angular/common'; 5 | 6 | @Component({ 7 | standalone: true, 8 | selector: 'sf-readme-widget', 9 | templateUrl: 'readme.widget.html', 10 | imports: [CommonModule], 11 | }) 12 | export class ReadmeWidget extends ControlWidget {} 13 | -------------------------------------------------------------------------------- /src/main/webapp/bootstrap.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { bootstrapApplication } from '@angular/platform-browser'; 3 | import { appConfig } from './app/app.config'; 4 | import AppComponent from './app/app.component'; 5 | 6 | import { DEBUG_INFO_ENABLED } from './app/app.constants'; 7 | 8 | // disable debug data on prod profile to improve performance 9 | if (!DEBUG_INFO_ENABLED) { 10 | enableProdMode(); 11 | } 12 | 13 | bootstrapApplication(AppComponent, appConfig) 14 | // eslint-disable-next-line no-console 15 | .then(() => console.log('Application started')) 16 | .catch(err => console.error(err)); 17 | -------------------------------------------------------------------------------- /src/main/webapp/content/images/generating.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camenduru/web/bab4f7ee8bdc6592ed11e1d966351e7fabdd62f7/src/main/webapp/content/images/generating.jpg -------------------------------------------------------------------------------- /src/main/webapp/content/images/logo-jhipster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camenduru/web/bab4f7ee8bdc6592ed11e1d966351e7fabdd62f7/src/main/webapp/content/images/logo-jhipster.png -------------------------------------------------------------------------------- /src/main/webapp/content/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camenduru/web/bab4f7ee8bdc6592ed11e1d966351e7fabdd62f7/src/main/webapp/content/images/logo.png -------------------------------------------------------------------------------- /src/main/webapp/content/scss/_bootstrap-variables.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * Bootstrap overrides https://getbootstrap.com/docs/5.1/customize/sass/ 3 | * All values defined in bootstrap source 4 | * https://github.com/twbs/bootstrap/blob/v5.1.3/scss/_variables.scss can be overwritten here 5 | * Make sure not to add !default to values here 6 | */ 7 | -------------------------------------------------------------------------------- /src/main/webapp/content/scss/vendor.scss: -------------------------------------------------------------------------------- 1 | /* after changing this file run 'npm run webapp:build' */ 2 | 3 | /*************************** 4 | put Sass variables here: 5 | eg $input-color: red; 6 | ****************************/ 7 | @import 'bootswatch/dist/darkly/variables'; 8 | // Override Bootstrap variables 9 | @import 'bootstrap-variables'; 10 | // Import Bootstrap source files from node_modules 11 | @import 'bootstrap/scss/bootstrap'; 12 | @import 'bootswatch/dist/darkly/bootswatch'; 13 | 14 | /* jhipster-needle-scss-add-vendor JHipster will add new css style */ 15 | -------------------------------------------------------------------------------- /src/main/webapp/declarations.d.ts: -------------------------------------------------------------------------------- 1 | declare const SERVER_API_URL: string; 2 | declare const I18N_HASH: string; 3 | -------------------------------------------------------------------------------- /src/main/webapp/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camenduru/web/bab4f7ee8bdc6592ed11e1d966351e7fabdd62f7/src/main/webapp/favicon.ico -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/activate.json: -------------------------------------------------------------------------------- 1 | { 2 | "activate": { 3 | "title": "Activation", 4 | "messages": { 5 | "success": "Your user account has been activated. Please ", 6 | "error": "Your user could not be activated. Please use the registration form to sign up." 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/adminAuthority.json: -------------------------------------------------------------------------------- 1 | { 2 | "webApp": { 3 | "adminAuthority": { 4 | "home": { 5 | "title": "Authorities", 6 | "refreshListLabel": "Refresh list", 7 | "createLabel": "Create a new Authority", 8 | "createOrEditLabel": "Create or edit a Authority", 9 | "notFound": "No Authorities found" 10 | }, 11 | "created": "A new Authority is created with identifier {{ param }}", 12 | "updated": "A Authority is updated with identifier {{ param }}", 13 | "deleted": "A Authority is deleted with identifier {{ param }}", 14 | "delete": { 15 | "question": "Are you sure you want to delete Authority {{ id }}?" 16 | }, 17 | "detail": { 18 | "title": "Authority" 19 | }, 20 | "name": "Name" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "configuration": { 3 | "title": "Configuration", 4 | "filter": "Filter (by prefix)", 5 | "table": { 6 | "prefix": "Prefix", 7 | "properties": "Properties" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/detail.json: -------------------------------------------------------------------------------- 1 | { 2 | "webApp": { 3 | "detail": { 4 | "home": { 5 | "title": "Details", 6 | "refreshListLabel": "Refresh list", 7 | "createLabel": "Create a new Detail", 8 | "createOrEditLabel": "Create or edit a Detail", 9 | "notFound": "No Details found" 10 | }, 11 | "created": "A new Detail is created with identifier {{ param }}", 12 | "updated": "A Detail is updated with identifier {{ param }}", 13 | "deleted": "A Detail is deleted with identifier {{ param }}", 14 | "delete": { 15 | "question": "Are you sure you want to delete Detail {{ id }}?" 16 | }, 17 | "detail": { 18 | "title": "Detail" 19 | }, 20 | "id": "ID", 21 | "discord": "Discord", 22 | "sourceId": "Source Id", 23 | "sourceChannel": "Source Channel", 24 | "total": "Total", 25 | "login": "Login", 26 | "membership": "Membership", 27 | "user": "User" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/error.json: -------------------------------------------------------------------------------- 1 | { 2 | "error": { 3 | "title": "Error page!", 4 | "http": { 5 | "400": "Bad request.", 6 | "403": "You are not authorized to access this page.", 7 | "404": "The page does not exist.", 8 | "405": "The HTTP verb you used is not supported for this URL.", 9 | "500": "Internal server error." 10 | }, 11 | "concurrencyFailure": "Another user modified this data at the same time as you. Your changes were rejected.", 12 | "validation": "Validation error on the server." 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/health.json: -------------------------------------------------------------------------------- 1 | { 2 | "health": { 3 | "title": "Health Checks", 4 | "refresh.button": "Refresh", 5 | "stacktrace": "Stacktrace", 6 | "details": { 7 | "details": "Details", 8 | "properties": "Properties", 9 | "name": "Name", 10 | "value": "Value", 11 | "error": "Error" 12 | }, 13 | "indicator": { 14 | "diskSpace": "Disk space", 15 | "mail": "Email", 16 | "livenessState": "Liveness state", 17 | "readinessState": "Readiness state", 18 | "ping": "Application", 19 | "mongo": "MongoDB" 20 | }, 21 | "table": { 22 | "service": "Service name", 23 | "status": "Status" 24 | }, 25 | "status": { 26 | "UNKNOWN": "UNKNOWN", 27 | "UP": "UP", 28 | "OUT_OF_SERVICE": "OUT_OF_SERVICE", 29 | "DOWN": "DOWN" 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/home.json: -------------------------------------------------------------------------------- 1 | { 2 | "home": { 3 | "title": "Tost AI", 4 | "subtitle": "This is your homepage", 5 | "logged": { 6 | "message": "You are logged in as user \"{{username}}\"." 7 | }, 8 | "question": "If you have any question on Tost AI:", 9 | "link": { 10 | "homepage": "Tost AI homepage", 11 | "stackoverflow": "Tost AI on Stack Overflow", 12 | "bugtracker": "Tost AI bug tracker", 13 | "chat": "Tost AI public chat room", 14 | "follow": "follow @tost_ai on Twitter" 15 | }, 16 | "like": "If you like Tost AI, don't forget to give us a star on", 17 | "github": "GitHub" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/job.json: -------------------------------------------------------------------------------- 1 | { 2 | "webApp": { 3 | "job": { 4 | "home": { 5 | "title": "Jobs", 6 | "refreshListLabel": "Refresh list", 7 | "createLabel": "Create a new Job", 8 | "createOrEditLabel": "Create or edit a Job", 9 | "notFound": "No Jobs found" 10 | }, 11 | "created": "A new Job is created with identifier {{ param }}", 12 | "updated": "A Job is updated with identifier {{ param }}", 13 | "deleted": "A Job is deleted with identifier {{ param }}", 14 | "delete": { 15 | "question": "Are you sure you want to delete Job {{ id }}?" 16 | }, 17 | "detail": { 18 | "title": "Job" 19 | }, 20 | "id": "ID", 21 | "date": "Date", 22 | "status": "Status", 23 | "source": "Source", 24 | "sourceId": "Source Id", 25 | "sourceChannel": "Source Channel", 26 | "command": "Command", 27 | "type": "Type", 28 | "amount": "Amount", 29 | "result": "Result", 30 | "login": "Login", 31 | "discord": "Discord", 32 | "total": "Total", 33 | "user": "User" 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/jobSource.json: -------------------------------------------------------------------------------- 1 | { 2 | "webApp": { 3 | "JobSource": { 4 | "null": "", 5 | "WEB": "WEB", 6 | "IOS": "IOS", 7 | "ANDROID": "ANDROID", 8 | "DISCORD": "DISCORD", 9 | "PAYPAL": "PAYPAL", 10 | "PATREON": "PATREON", 11 | "OTHER": "OTHER" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/jobStatus.json: -------------------------------------------------------------------------------- 1 | { 2 | "webApp": { 3 | "JobStatus": { 4 | "null": "", 5 | "POSITIVE": "POSITIVE", 6 | "NEGATIVE": "NEGATIVE", 7 | "WAITING": "WAITING", 8 | "WORKING": "WORKING", 9 | "DONE": "DONE", 10 | "FAILED": "FAILED", 11 | "CANCELED": "CANCELED", 12 | "EXPIRED": "EXPIRED" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/login.json: -------------------------------------------------------------------------------- 1 | { 2 | "login": { 3 | "title": "Sign in", 4 | "form": { 5 | "password": "Password", 6 | "password.placeholder": "Your password", 7 | "rememberme": "Remember me", 8 | "button": "Sign in" 9 | }, 10 | "messages": { 11 | "error": { 12 | "authentication": "Failed to sign in! Please check your credentials and try again." 13 | } 14 | }, 15 | "password": { 16 | "forgot": "Did you forget your password?" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/logs.json: -------------------------------------------------------------------------------- 1 | { 2 | "logs": { 3 | "title": "Logs", 4 | "nbloggers": "There are {{ total }} loggers.", 5 | "filter": "Filter", 6 | "table": { 7 | "name": "Name", 8 | "level": "Level" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/membership.json: -------------------------------------------------------------------------------- 1 | { 2 | "webApp": { 3 | "Membership": { 4 | "null": "", 5 | "FREE": "FREE", 6 | "PAID": "PAID" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/password.json: -------------------------------------------------------------------------------- 1 | { 2 | "password": { 3 | "title": "Password for [{{username}}]", 4 | "form": { 5 | "button": "Save" 6 | }, 7 | "messages": { 8 | "error": "An error has occurred! The password could not be changed.", 9 | "success": "Password changed!" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/redeem.json: -------------------------------------------------------------------------------- 1 | { 2 | "webApp": { 3 | "redeem": { 4 | "home": { 5 | "title": "Redeems", 6 | "refreshListLabel": "Refresh list", 7 | "createLabel": "Create a new Redeem", 8 | "createOrEditLabel": "Create or edit a Redeem", 9 | "notFound": "No Redeems found" 10 | }, 11 | "created": "A new Redeem is created with identifier {{ param }}", 12 | "updated": "A Redeem is updated with identifier {{ param }}", 13 | "deleted": "A Redeem is deleted with identifier {{ param }}", 14 | "delete": { 15 | "question": "Are you sure you want to delete Redeem {{ id }}?" 16 | }, 17 | "detail": { 18 | "title": "Redeem" 19 | }, 20 | "id": "ID", 21 | "date": "Date", 22 | "status": "Status", 23 | "type": "Type", 24 | "author": "Author", 25 | "login": "Login", 26 | "amount": "Amount", 27 | "code": "Code", 28 | "user": "User" 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/redeemStatus.json: -------------------------------------------------------------------------------- 1 | { 2 | "webApp": { 3 | "RedeemStatus": { 4 | "null": "", 5 | "WAITING": "WAITING", 6 | "USED": "USED", 7 | "FAILED": "FAILED", 8 | "CANCELED": "CANCELED", 9 | "EXPIRED": "EXPIRED" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/register.json: -------------------------------------------------------------------------------- 1 | { 2 | "register": { 3 | "title": "Registration", 4 | "form": { 5 | "button": "Register" 6 | }, 7 | "messages": { 8 | "validate": { 9 | "login": { 10 | "required": "Your username is required.", 11 | "minlength": "Your username is required to be at least 1 character.", 12 | "maxlength": "Your username cannot be longer than 50 characters.", 13 | "pattern": "Your username is invalid." 14 | } 15 | }, 16 | "success": "Registration saved! Please check your email for confirmation.", 17 | "error": { 18 | "fail": "Registration failed! Please try again later.", 19 | "userexists": "Login name already registered! Please choose another one.", 20 | "emailexists": "Email is already in use! Please choose another one.", 21 | "emailservicenotallowed": "Email service is not allowed! Please choose another one." 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/reset.json: -------------------------------------------------------------------------------- 1 | { 2 | "reset": { 3 | "request": { 4 | "title": "Reset your password", 5 | "form": { 6 | "button": "Reset password" 7 | }, 8 | "messages": { 9 | "info": "Enter the email address you used to register", 10 | "success": "Check your email for details on how to reset your password." 11 | } 12 | }, 13 | "finish": { 14 | "title": "Reset password", 15 | "form": { 16 | "button": "Validate new password" 17 | }, 18 | "messages": { 19 | "info": "Choose a new password", 20 | "success": "Your password has been reset. Please ", 21 | "keymissing": "The reset key is missing.", 22 | "error": "Your password couldn't be reset. Remember a password request is only valid for 24 hours." 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/sessions.json: -------------------------------------------------------------------------------- 1 | { 2 | "sessions": { 3 | "title": "Active sessions for [{{username}}]", 4 | "table": { 5 | "ipaddress": "IP address", 6 | "useragent": "User Agent", 7 | "date": "Date", 8 | "button": "Invalidate" 9 | }, 10 | "messages": { 11 | "success": "Session invalidated!", 12 | "error": "An error has occurred! The session could not be invalidated." 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "settings": { 3 | "title": "User settings for [{{username}}]", 4 | "form": { 5 | "firstname": "First Name", 6 | "firstname.placeholder": "Your first name", 7 | "lastname": "Last Name", 8 | "lastname.placeholder": "Your last name", 9 | "language": "Language", 10 | "button": "Save" 11 | }, 12 | "messages": { 13 | "error": { 14 | "fail": "An error has occurred! Settings could not be saved.", 15 | "emailexists": "Email is already in use! Please choose another one." 16 | }, 17 | "success": "Settings saved!", 18 | "validate": { 19 | "firstname": { 20 | "required": "Your first name is required.", 21 | "minlength": "Your first name is required to be at least 1 character", 22 | "maxlength": "Your first name cannot be longer than 50 characters" 23 | }, 24 | "lastname": { 25 | "required": "Your last name is required.", 26 | "minlength": "Your last name is required to be at least 1 character", 27 | "maxlength": "Your last name cannot be longer than 50 characters" 28 | } 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/tracker.json: -------------------------------------------------------------------------------- 1 | { 2 | "tracker": { 3 | "title": "Real-time user activities", 4 | "table": { 5 | "userlogin": "User", 6 | "ipaddress": "IP Address", 7 | "userAgent": "User agent", 8 | "page": "Current page", 9 | "time": "Time" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/type.json: -------------------------------------------------------------------------------- 1 | { 2 | "webApp": { 3 | "type": { 4 | "home": { 5 | "title": "Types", 6 | "refreshListLabel": "Refresh list", 7 | "createLabel": "Create a new Type", 8 | "createOrEditLabel": "Create or edit a Type", 9 | "notFound": "No Types found" 10 | }, 11 | "created": "A new Type is created with identifier {{ param }}", 12 | "updated": "A Type is updated with identifier {{ param }}", 13 | "deleted": "A Type is deleted with identifier {{ param }}", 14 | "delete": { 15 | "question": "Are you sure you want to delete Type {{ id }}?" 16 | }, 17 | "detail": { 18 | "title": "Type" 19 | }, 20 | "id": "ID", 21 | "type": "Type", 22 | "amount": "Amount", 23 | "schema": "Schema", 24 | "model": "Model", 25 | "title": "Title", 26 | "isDefault": "Is Default", 27 | "isActive": "Is Active", 28 | "isFree": "Is Free", 29 | "cooldown": "Cooldown" 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/webapp/i18n/en/user-management.json: -------------------------------------------------------------------------------- 1 | { 2 | "userManagement": { 3 | "home": { 4 | "title": "Users", 5 | "refreshListLabel": "Refresh list", 6 | "createLabel": "Create a new user", 7 | "createOrEditLabel": "Create or edit a user" 8 | }, 9 | "created": "A new user is created with identifier {{ param }}", 10 | "updated": "A user is updated with identifier {{ param }}", 11 | "deleted": "A user is deleted with identifier {{ param }}", 12 | "delete": { 13 | "question": "Are you sure you want to delete user {{ login }}?" 14 | }, 15 | "detail": { 16 | "title": "User" 17 | }, 18 | "login": "Login", 19 | "firstName": "First name", 20 | "lastName": "Last name", 21 | "email": "Email", 22 | "activated": "Activated", 23 | "deactivated": "Deactivated", 24 | "profiles": "Profiles", 25 | "langKey": "Language", 26 | "createdBy": "Created by", 27 | "createdDate": "Created date", 28 | "lastModifiedBy": "Modified by", 29 | "lastModifiedDate": "Modified date" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/webapp/main.ts: -------------------------------------------------------------------------------- 1 | import('./bootstrap').catch(err => console.error(err)); 2 | -------------------------------------------------------------------------------- /src/main/webapp/manifest.webapp: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Tost AI", 3 | "short_name": "Tost AI", 4 | "icons": [ 5 | { 6 | "src": "./content/images/logo-jhipster.png", 7 | "sizes": "128x128", 8 | "type": "image/png" 9 | } 10 | ], 11 | "theme_color": "#000000", 12 | "background_color": "#e0e0e0", 13 | "start_url": ".", 14 | "display": "standalone", 15 | "orientation": "portrait" 16 | } 17 | -------------------------------------------------------------------------------- /src/main/webapp/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org/ 2 | 3 | User-agent: * 4 | Disallow: /api/account 5 | Disallow: /api/account/change-password 6 | Disallow: /api/account/sessions 7 | Disallow: /api/logs/ 8 | Disallow: /api/users/ 9 | Disallow: /management/ 10 | Disallow: /v3/api-docs/ 11 | -------------------------------------------------------------------------------- /src/main/webapp/sockjs-client.polyfill.ts: -------------------------------------------------------------------------------- 1 | (window as any).global = window; 2 | -------------------------------------------------------------------------------- /src/main/webapp/swagger-ui/dist/images/throbber.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camenduru/web/bab4f7ee8bdc6592ed11e1d966351e7fabdd62f7/src/main/webapp/swagger-ui/dist/images/throbber.gif -------------------------------------------------------------------------------- /src/test/java/com/camenduru/web/IntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web; 2 | 3 | import com.camenduru.web.config.AsyncSyncConfiguration; 4 | import com.camenduru.web.config.EmbeddedMongo; 5 | import com.camenduru.web.config.JacksonConfiguration; 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.RetentionPolicy; 9 | import java.lang.annotation.Target; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | 12 | /** 13 | * Base composite annotation for integration tests. 14 | */ 15 | @Target(ElementType.TYPE) 16 | @Retention(RetentionPolicy.RUNTIME) 17 | @SpringBootTest(classes = { WebApp.class, JacksonConfiguration.class, AsyncSyncConfiguration.class }) 18 | @EmbeddedMongo 19 | public @interface IntegrationTest { 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/com/camenduru/web/config/AsyncSyncConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.config; 2 | 3 | import java.util.concurrent.Executor; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.core.task.SyncTaskExecutor; 7 | 8 | @Configuration 9 | public class AsyncSyncConfiguration { 10 | 11 | @Bean(name = "taskExecutor") 12 | public Executor taskExecutor() { 13 | return new SyncTaskExecutor(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/com/camenduru/web/config/EmbeddedMongo.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.config; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Target(ElementType.TYPE) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface EmbeddedMongo { 11 | } 12 | -------------------------------------------------------------------------------- /src/test/java/com/camenduru/web/config/SpringBootTestClassOrderer.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.config; 2 | 3 | import com.camenduru.web.IntegrationTest; 4 | import java.util.Comparator; 5 | import org.junit.jupiter.api.ClassDescriptor; 6 | import org.junit.jupiter.api.ClassOrderer; 7 | import org.junit.jupiter.api.ClassOrdererContext; 8 | 9 | public class SpringBootTestClassOrderer implements ClassOrderer { 10 | 11 | @Override 12 | public void orderClasses(ClassOrdererContext context) { 13 | context.getClassDescriptors().sort(Comparator.comparingInt(SpringBootTestClassOrderer::getOrder)); 14 | } 15 | 16 | private static int getOrder(ClassDescriptor classDescriptor) { 17 | if (classDescriptor.findAnnotation(IntegrationTest.class).isPresent()) { 18 | return 2; 19 | } 20 | return 1; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/com/camenduru/web/config/WebConfigurerTestController.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.config; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | @RestController 7 | public class WebConfigurerTestController { 8 | 9 | @GetMapping("/api/test-cors") 10 | public void testCorsOnApiPath() {} 11 | 12 | @GetMapping("/test/test-cors") 13 | public void testCorsOnOtherPath() {} 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/com/camenduru/web/domain/AssertUtils.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.domain; 2 | 3 | import java.math.BigDecimal; 4 | import java.time.ZoneOffset; 5 | import java.time.ZonedDateTime; 6 | import java.util.Comparator; 7 | 8 | public class AssertUtils { 9 | 10 | public static Comparator zonedDataTimeSameInstant = Comparator.nullsFirst( 11 | (e1, a2) -> e1.withZoneSameInstant(ZoneOffset.UTC).compareTo(a2.withZoneSameInstant(ZoneOffset.UTC)) 12 | ); 13 | 14 | public static Comparator bigDecimalCompareTo = Comparator.nullsFirst((e1, a2) -> e1.compareTo(a2)); 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/com/camenduru/web/domain/AuthorityTest.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.domain; 2 | 3 | import static com.camenduru.web.domain.AuthorityTestSamples.*; 4 | import static org.assertj.core.api.Assertions.assertThat; 5 | 6 | import com.camenduru.web.web.rest.TestUtil; 7 | import org.junit.jupiter.api.Test; 8 | 9 | class AuthorityTest { 10 | 11 | @Test 12 | void equalsVerifier() throws Exception { 13 | TestUtil.equalsVerifier(Authority.class); 14 | Authority authority1 = getAuthoritySample1(); 15 | Authority authority2 = new Authority(); 16 | assertThat(authority1).isNotEqualTo(authority2); 17 | 18 | authority2.setName(authority1.getName()); 19 | assertThat(authority1).isEqualTo(authority2); 20 | 21 | authority2 = getAuthoritySample2(); 22 | assertThat(authority1).isNotEqualTo(authority2); 23 | } 24 | 25 | @Test 26 | void hashCodeVerifier() throws Exception { 27 | Authority authority = new Authority(); 28 | assertThat(authority.hashCode()).isZero(); 29 | 30 | Authority authority1 = getAuthoritySample1(); 31 | authority.setName(authority1.getName()); 32 | assertThat(authority).hasSameHashCodeAs(authority1); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/com/camenduru/web/domain/AuthorityTestSamples.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.domain; 2 | 3 | import java.util.UUID; 4 | 5 | public class AuthorityTestSamples { 6 | 7 | public static Authority getAuthoritySample1() { 8 | return new Authority().name("name1"); 9 | } 10 | 11 | public static Authority getAuthoritySample2() { 12 | return new Authority().name("name2"); 13 | } 14 | 15 | public static Authority getAuthorityRandomSampleGenerator() { 16 | return new Authority().name(UUID.randomUUID().toString()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/camenduru/web/domain/DetailTest.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.domain; 2 | 3 | import static com.camenduru.web.domain.DetailTestSamples.*; 4 | import static org.assertj.core.api.Assertions.assertThat; 5 | 6 | import com.camenduru.web.web.rest.TestUtil; 7 | import org.junit.jupiter.api.Test; 8 | 9 | class DetailTest { 10 | 11 | @Test 12 | void equalsVerifier() throws Exception { 13 | TestUtil.equalsVerifier(Detail.class); 14 | Detail detail1 = getDetailSample1(); 15 | Detail detail2 = new Detail(); 16 | assertThat(detail1).isNotEqualTo(detail2); 17 | 18 | detail2.setId(detail1.getId()); 19 | assertThat(detail1).isEqualTo(detail2); 20 | 21 | detail2 = getDetailSample2(); 22 | assertThat(detail1).isNotEqualTo(detail2); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/com/camenduru/web/domain/DetailTestSamples.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.domain; 2 | 3 | import java.util.UUID; 4 | 5 | public class DetailTestSamples { 6 | 7 | public static Detail getDetailSample1() { 8 | return new Detail() 9 | .id("id1") 10 | .discord("discord1") 11 | .sourceId("sourceId1") 12 | .sourceChannel("sourceChannel1") 13 | .total("total1") 14 | .login("login1"); 15 | } 16 | 17 | public static Detail getDetailSample2() { 18 | return new Detail() 19 | .id("id2") 20 | .discord("discord2") 21 | .sourceId("sourceId2") 22 | .sourceChannel("sourceChannel2") 23 | .total("total2") 24 | .login("login2"); 25 | } 26 | 27 | public static Detail getDetailRandomSampleGenerator() { 28 | return new Detail() 29 | .id(UUID.randomUUID().toString()) 30 | .discord(UUID.randomUUID().toString()) 31 | .sourceId(UUID.randomUUID().toString()) 32 | .sourceChannel(UUID.randomUUID().toString()) 33 | .total(UUID.randomUUID().toString()) 34 | .login(UUID.randomUUID().toString()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/com/camenduru/web/domain/RedeemTest.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.domain; 2 | 3 | import static com.camenduru.web.domain.RedeemTestSamples.*; 4 | import static org.assertj.core.api.Assertions.assertThat; 5 | 6 | import com.camenduru.web.web.rest.TestUtil; 7 | import org.junit.jupiter.api.Test; 8 | 9 | class RedeemTest { 10 | 11 | @Test 12 | void equalsVerifier() throws Exception { 13 | TestUtil.equalsVerifier(Redeem.class); 14 | Redeem redeem1 = getRedeemSample1(); 15 | Redeem redeem2 = new Redeem(); 16 | assertThat(redeem1).isNotEqualTo(redeem2); 17 | 18 | redeem2.setId(redeem1.getId()); 19 | assertThat(redeem1).isEqualTo(redeem2); 20 | 21 | redeem2 = getRedeemSample2(); 22 | assertThat(redeem1).isNotEqualTo(redeem2); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/com/camenduru/web/domain/RedeemTestSamples.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.domain; 2 | 3 | import java.util.UUID; 4 | 5 | public class RedeemTestSamples { 6 | 7 | public static Redeem getRedeemSample1() { 8 | return new Redeem().id("id1").type("type1").author("author1").login("login1").amount("amount1").code("code1"); 9 | } 10 | 11 | public static Redeem getRedeemSample2() { 12 | return new Redeem().id("id2").type("type2").author("author2").login("login2").amount("amount2").code("code2"); 13 | } 14 | 15 | public static Redeem getRedeemRandomSampleGenerator() { 16 | return new Redeem() 17 | .id(UUID.randomUUID().toString()) 18 | .type(UUID.randomUUID().toString()) 19 | .author(UUID.randomUUID().toString()) 20 | .login(UUID.randomUUID().toString()) 21 | .amount(UUID.randomUUID().toString()) 22 | .code(UUID.randomUUID().toString()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/com/camenduru/web/domain/TypeTest.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.domain; 2 | 3 | import static com.camenduru.web.domain.TypeTestSamples.*; 4 | import static org.assertj.core.api.Assertions.assertThat; 5 | 6 | import com.camenduru.web.web.rest.TestUtil; 7 | import org.junit.jupiter.api.Test; 8 | 9 | class TypeTest { 10 | 11 | @Test 12 | void equalsVerifier() throws Exception { 13 | TestUtil.equalsVerifier(Type.class); 14 | Type type1 = getTypeSample1(); 15 | Type type2 = new Type(); 16 | assertThat(type1).isNotEqualTo(type2); 17 | 18 | type2.setId(type1.getId()); 19 | assertThat(type1).isEqualTo(type2); 20 | 21 | type2 = getTypeSample2(); 22 | assertThat(type1).isNotEqualTo(type2); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/com/camenduru/web/domain/TypeTestSamples.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.domain; 2 | 3 | import java.util.UUID; 4 | 5 | public class TypeTestSamples { 6 | 7 | public static Type getTypeSample1() { 8 | return new Type().id("id1").type("type1").amount("amount1").schema("schema1").model("model1").title("title1").cooldown("cooldown1"); 9 | } 10 | 11 | public static Type getTypeSample2() { 12 | return new Type().id("id2").type("type2").amount("amount2").schema("schema2").model("model2").title("title2").cooldown("cooldown2"); 13 | } 14 | 15 | public static Type getTypeRandomSampleGenerator() { 16 | return new Type() 17 | .id(UUID.randomUUID().toString()) 18 | .type(UUID.randomUUID().toString()) 19 | .amount(UUID.randomUUID().toString()) 20 | .schema(UUID.randomUUID().toString()) 21 | .model(UUID.randomUUID().toString()) 22 | .title(UUID.randomUUID().toString()) 23 | .cooldown(UUID.randomUUID().toString()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/camenduru/web/web/rest/WithUnauthenticatedMockUser.java: -------------------------------------------------------------------------------- 1 | package com.camenduru.web.web.rest; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | import org.springframework.security.core.context.SecurityContext; 8 | import org.springframework.security.core.context.SecurityContextHolder; 9 | import org.springframework.security.test.context.support.WithSecurityContext; 10 | import org.springframework.security.test.context.support.WithSecurityContextFactory; 11 | 12 | @Target({ ElementType.METHOD, ElementType.TYPE }) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @WithSecurityContext(factory = WithUnauthenticatedMockUser.Factory.class) 15 | public @interface WithUnauthenticatedMockUser { 16 | class Factory implements WithSecurityContextFactory { 17 | 18 | @Override 19 | public SecurityContext createSecurityContext(WithUnauthenticatedMockUser annotation) { 20 | return SecurityContextHolder.createEmptyContext(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/javascript/cypress/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "plugins": ["cypress", "@typescript-eslint"], 5 | "env": { 6 | "cypress/globals": true 7 | }, 8 | "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:cypress/recommended"], 9 | "rules": { 10 | "@typescript-eslint/no-namespace": ["error", { "allowDeclarations": true }], 11 | "@typescript-eslint/no-unused-vars": "off" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/test/javascript/cypress/e2e/lighthouse.audits.ts: -------------------------------------------------------------------------------- 1 | describe('Lighthouse Audits', () => { 2 | beforeEach(() => { 3 | cy.visit('/'); 4 | }); 5 | 6 | it('homepage', () => { 7 | const customThresholds = { 8 | performance: 80, 9 | accessibility: 90, 10 | seo: 90, 11 | 'best-practices': 90, 12 | // If you have enabled PWA you should set this threshold to 100 13 | pwa: 0, 14 | }; 15 | 16 | const desktopConfig = { 17 | extends: 'lighthouse:default', 18 | formFactor: 'desktop', 19 | // Change the CPU slowdown multiplier to emulate different kind of devices 20 | // See https://github.com/GoogleChrome/lighthouse/blob/master/docs/throttling.md#cpu-throttling for details 21 | throttling: { 22 | cpuSlowdownMultiplier: 1, 23 | }, 24 | screenEmulation: { disabled: true }, 25 | }; 26 | cy.lighthouse(customThresholds, desktopConfig); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/test/javascript/cypress/fixtures/integration-test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camenduru/web/bab4f7ee8bdc6592ed11e1d966351e7fabdd62f7/src/test/javascript/cypress/fixtures/integration-test.png -------------------------------------------------------------------------------- /src/test/javascript/cypress/plugins/global.d.ts: -------------------------------------------------------------------------------- 1 | // workaround missing typings https://github.com/cypress-io/code-coverage/issues/257 2 | declare module '@cypress/code-coverage/task' { 3 | export default function codecov(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions): void; 4 | } 5 | -------------------------------------------------------------------------------- /src/test/javascript/cypress/support/account.ts: -------------------------------------------------------------------------------- 1 | export type Account = Record; 2 | 3 | Cypress.Commands.add('getAccount', () => { 4 | return cy 5 | .authenticatedRequest({ 6 | method: 'GET', 7 | url: '/api/account', 8 | }) 9 | .then(response => response.body as Account); 10 | }); 11 | 12 | Cypress.Commands.add('saveAccount', (account: Account) => { 13 | return cy.authenticatedRequest({ 14 | method: 'POST', 15 | url: '/api/account', 16 | body: account, 17 | }); 18 | }); 19 | 20 | declare global { 21 | namespace Cypress { 22 | interface Chainable { 23 | getAccount(): Cypress.Chainable; 24 | saveAccount(account: Account): Cypress.Chainable>; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/javascript/cypress/support/index.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | import '@cypress/code-coverage/support'; 16 | 17 | import './account'; 18 | import './commands'; 19 | import './navbar'; 20 | import './entity'; 21 | import './management'; 22 | -------------------------------------------------------------------------------- /src/test/javascript/cypress/support/management.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-namespace */ 2 | /* eslint-disable @typescript-eslint/no-use-before-define */ 3 | 4 | Cypress.Commands.add('getManagementInfo', () => { 5 | return cy 6 | .request({ 7 | method: 'GET', 8 | url: '/management/info', 9 | }) 10 | .then(response => response.body); 11 | }); 12 | 13 | declare global { 14 | namespace Cypress { 15 | interface Chainable { 16 | getManagementInfo(): Cypress.Chainable; 17 | } 18 | } 19 | } 20 | 21 | // Convert this to a module instead of script (allows import/export) 22 | export {}; 23 | -------------------------------------------------------------------------------- /src/test/javascript/cypress/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "sourceMap": false, 6 | "outDir": "../../../../target/cypress/tsc", 7 | "target": "es2018", 8 | "types": ["cypress", "node"] 9 | }, 10 | "include": ["./../../../../cypress*.config.ts", "./**/*.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /src/test/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.test.context.ContextCustomizerFactory = com.camenduru.web.\ 2 | config.TestContainersSpringContextCustomizerFactory -------------------------------------------------------------------------------- /src/test/resources/i18n/messages_en.properties: -------------------------------------------------------------------------------- 1 | email.test.title=test title 2 | # Value used for English locale unit test in MailServiceIT 3 | # as this file is loaded instead of real file 4 | email.activation.title=web account activation 5 | -------------------------------------------------------------------------------- /src/test/resources/junit-platform.properties: -------------------------------------------------------------------------------- 1 | junit.jupiter.execution.timeout.default = 15 s 2 | junit.jupiter.execution.timeout.testable.method.default = 15 s 3 | junit.jupiter.execution.timeout.beforeall.method.default = 60 s 4 | junit.jupiter.testclass.order.default=com.camenduru.web.config.SpringBootTestClassOrderer 5 | -------------------------------------------------------------------------------- /src/test/resources/templates/mail/activationEmail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | JHipster activation 5 | 6 | 7 | 8 |

Dear

9 |

Your JHipster account has been created, please click on the URL below to activate it:

10 |

11 | Activation link 12 |

13 |

14 | Regards, 15 |
16 | JHipster. 17 |

18 | 19 | 20 | -------------------------------------------------------------------------------- /src/test/resources/templates/mail/creationEmail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | JHipster creation 5 | 6 | 7 | 8 |

Dear

9 |

Your JHipster account has been created, please click on the URL below to access it:

10 |

11 | Login link 12 |

13 |

14 | Regards, 15 |
16 | JHipster. 17 |

18 | 19 | 20 | -------------------------------------------------------------------------------- /src/test/resources/templates/mail/passwordResetEmail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | JHipster password reset 5 | 6 | 7 | 8 |

Dear

9 |

10 | For your JHipster account a password reset was requested, please click on the URL below to reset it: 11 |

12 |

13 | Login link 14 |

15 |

16 | Regards, 17 |
18 | JHipster. 19 |

20 | 21 | 22 | -------------------------------------------------------------------------------- /src/test/resources/templates/mail/testEmail.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./target/out-tsc/app", 5 | "types": ["@angular/localize"] 6 | }, 7 | "files": ["src/main/webapp/sockjs-client.polyfill.ts", "src/main/webapp/main.ts"], 8 | "include": ["src/main/webapp/**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "src/main/webapp/", 4 | "outDir": "./target/out-tsc/root", 5 | "forceConsistentCasingInFileNames": true, 6 | "strict": true, 7 | "strictNullChecks": true, 8 | "noImplicitReturns": true, 9 | "noFallthroughCasesInSwitch": true, 10 | "sourceMap": true, 11 | "declaration": false, 12 | "downlevelIteration": true, 13 | "experimentalDecorators": true, 14 | "moduleResolution": "node", 15 | "importHelpers": true, 16 | "esModuleInterop": true, 17 | "allowSyntheticDefaultImports": true, 18 | "useDefineForClassFields": false, 19 | "target": "es2022", 20 | "module": "es2020", 21 | "types": [], 22 | "lib": ["es2018", "es2020", "dom"] 23 | }, 24 | "references": [ 25 | { 26 | "path": "tsconfig.spec.json" 27 | } 28 | ], 29 | "angularCompilerOptions": { 30 | "strictInjectionParameters": true, 31 | "strictInputAccessModifiers": true, 32 | "strictTemplates": true, 33 | "preserveWhitespaces": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["src/main/webapp/**/*.ts"], 4 | "compilerOptions": { 5 | "composite": true, 6 | "outDir": "target/out-tsc/spec", 7 | "types": ["jest", "node"] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /webpack/environment.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | I18N_HASH: 'generated_hash', 3 | SERVER_API_URL: '', 4 | __VERSION__: process.env.hasOwnProperty('APP_VERSION') ? process.env.APP_VERSION : 'DEV', 5 | __DEBUG_INFO_ENABLED__: false, 6 | }; 7 | -------------------------------------------------------------------------------- /webpack/logo-jhipster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camenduru/web/bab4f7ee8bdc6592ed11e1d966351e7fabdd62f7/webpack/logo-jhipster.png -------------------------------------------------------------------------------- /webpack/proxy.conf.js: -------------------------------------------------------------------------------- 1 | function setupProxy({ tls }) { 2 | const serverResources = ['/api', '/services', '/management', '/v3/api-docs', '/h2-console', '/health']; 3 | const conf = [ 4 | { 5 | context: serverResources, 6 | target: `http${tls ? 's' : ''}://localhost:8080`, 7 | secure: false, 8 | changeOrigin: tls, 9 | }, 10 | { 11 | context: ['/websocket'], 12 | target: 'ws://127.0.0.1:8080', 13 | ws: true, 14 | }, 15 | ]; 16 | return conf; 17 | } 18 | 19 | module.exports = setupProxy; 20 | --------------------------------------------------------------------------------