├── .dockerignore ├── .gitattributes ├── .gitchangelog-keepachangelog.tpl ├── .gitchangelog.rc ├── .github ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── no-response.yml └── workflows │ ├── ci.yml │ ├── docker_build.sh │ └── docker_push.sh ├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── Dockerfile.heroku ├── LICENSE.txt ├── README.md ├── ROADMAP.md ├── bootstrap ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── hesperides │ │ └── HesperidesSpringApplication.java │ └── resources │ ├── application.yml │ ├── banner.txt │ ├── ehcache.xml │ └── logback-spring.xml ├── commons ├── pom.xml └── src │ └── main │ └── java │ └── org │ └── hesperides │ └── commons │ ├── DomainPrimer.java │ ├── SpringProfiles.java │ ├── VersionIdLogger.java │ └── axon │ └── AxonQueries.java ├── core ├── application │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── org │ │ │ └── hesperides │ │ │ └── core │ │ │ └── application │ │ │ ├── events │ │ │ └── EventUseCases.java │ │ │ ├── files │ │ │ ├── FileUseCases.java │ │ │ └── InfiniteMustacheRecursion.java │ │ │ ├── modules │ │ │ └── ModuleUseCases.java │ │ │ ├── platforms │ │ │ ├── PlatformUseCases.java │ │ │ ├── PropertiesUseCases.java │ │ │ └── properties │ │ │ │ ├── PropertyType.java │ │ │ │ ├── PropertyValuationBuilder.java │ │ │ │ └── PropertyValuationContext.java │ │ │ ├── security │ │ │ ├── ApplicationDirectoryGroupsUseCases.java │ │ │ └── UserUseCases.java │ │ │ └── technos │ │ │ └── TechnoUseCases.java │ │ └── test │ │ └── java │ │ └── org │ │ └── hesperides │ │ └── core │ │ └── application │ │ ├── files │ │ ├── FileUseCasesTest.java │ │ ├── RandomPlatformViewGenerator.java │ │ └── UnescapeValuesMustacheFactoryTest.java │ │ ├── modules │ │ └── ModuleUseCasesTest.java │ │ └── platforms │ │ └── PlatformUseCasesTest.java ├── domain │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── org │ │ │ │ └── hesperides │ │ │ │ └── core │ │ │ │ └── domain │ │ │ │ ├── events │ │ │ │ ├── EventRepository.java │ │ │ │ ├── commands │ │ │ │ │ └── EventCommands.java │ │ │ │ └── queries │ │ │ │ │ ├── EventQueries.java │ │ │ │ │ └── EventView.java │ │ │ │ ├── exceptions │ │ │ │ ├── DuplicateException.java │ │ │ │ ├── ForbiddenOperationException.java │ │ │ │ ├── NotFoundException.java │ │ │ │ ├── OutOfDateException.java │ │ │ │ ├── OutOfDateGlobalPropertiesException.java │ │ │ │ ├── OutOfDatePlatformVersionException.java │ │ │ │ ├── OutOfDatePropertiesException.java │ │ │ │ └── OutOfDateVersionException.java │ │ │ │ ├── files │ │ │ │ └── InstanceFileView.java │ │ │ │ ├── modules │ │ │ │ ├── ModuleProjectionRepository.java │ │ │ │ ├── TemplateProjectionRepository.java │ │ │ │ ├── commands │ │ │ │ │ ├── ModuleAggregate.java │ │ │ │ │ └── ModuleCommands.java │ │ │ │ ├── entities │ │ │ │ │ └── Module.java │ │ │ │ ├── exceptions │ │ │ │ │ ├── DuplicateModuleException.java │ │ │ │ │ ├── DuplicateTemplateCreationException.java │ │ │ │ │ ├── ModuleHasWorkingcopyTechnoException.java │ │ │ │ │ ├── ModuleNotFoundException.java │ │ │ │ │ ├── ModuleUsedByPlatformsException.java │ │ │ │ │ ├── TemplateNotFoundException.java │ │ │ │ │ └── UpdateReleaseException.java │ │ │ │ └── queries │ │ │ │ │ ├── ModulePasswordProperties.java │ │ │ │ │ ├── ModulePropertiesView.java │ │ │ │ │ ├── ModuleQueries.java │ │ │ │ │ └── ModuleView.java │ │ │ │ ├── platforms │ │ │ │ ├── PlatformProjectionRepository.java │ │ │ │ ├── commands │ │ │ │ │ ├── PlatformAggregate.java │ │ │ │ │ └── PlatformCommands.java │ │ │ │ ├── entities │ │ │ │ │ ├── DeployedModule.java │ │ │ │ │ ├── Instance.java │ │ │ │ │ ├── Platform.java │ │ │ │ │ └── properties │ │ │ │ │ │ ├── AbstractValuedProperty.java │ │ │ │ │ │ ├── IterablePropertyItem.java │ │ │ │ │ │ ├── IterableValuedProperty.java │ │ │ │ │ │ ├── ValuedProperty.java │ │ │ │ │ │ ├── ValuedPropertyTransformation.java │ │ │ │ │ │ ├── diff │ │ │ │ │ │ ├── AbstractDifferingProperty.java │ │ │ │ │ │ ├── IterableDifferingProperty.java │ │ │ │ │ │ ├── PropertiesDiff.java │ │ │ │ │ │ └── SimpleDifferingProperty.java │ │ │ │ │ │ └── visitors │ │ │ │ │ │ ├── IterablePropertyVisitor.java │ │ │ │ │ │ ├── PropertyVisitor.java │ │ │ │ │ │ ├── PropertyVisitorsSequence.java │ │ │ │ │ │ └── SimplePropertyVisitor.java │ │ │ │ ├── exceptions │ │ │ │ │ ├── ApplicationNotFoundException.java │ │ │ │ │ ├── DeployedModuleNotFoundException.java │ │ │ │ │ ├── DuplicateDeployedModuleIdException.java │ │ │ │ │ ├── DuplicatePlatformException.java │ │ │ │ │ ├── InexistantPlatformAtTimeException.java │ │ │ │ │ ├── InstanceNotFoundException.java │ │ │ │ │ ├── InvalidDiffSourceException.java │ │ │ │ │ ├── InvalidPropertyValorisationException.java │ │ │ │ │ ├── PlatformNotFoundException.java │ │ │ │ │ ├── PropertyPatternNotMatchedException.java │ │ │ │ │ ├── RequiredPropertyNotValorisedException.java │ │ │ │ │ └── UnreplayablePlatformEventsException.java │ │ │ │ └── queries │ │ │ │ │ ├── PlatformQueries.java │ │ │ │ │ └── views │ │ │ │ │ ├── ApplicationView.java │ │ │ │ │ ├── DeployedModuleView.java │ │ │ │ │ ├── InstanceView.java │ │ │ │ │ ├── ModulePlatformView.java │ │ │ │ │ ├── PlatformEventView.java │ │ │ │ │ ├── PlatformView.java │ │ │ │ │ ├── PropertiesEventView.java │ │ │ │ │ ├── SearchApplicationResultView.java │ │ │ │ │ ├── SearchPlatformResultView.java │ │ │ │ │ └── properties │ │ │ │ │ ├── AbstractValuedPropertyView.java │ │ │ │ │ ├── GlobalPropertyUsageView.java │ │ │ │ │ ├── IterablePropertyItemView.java │ │ │ │ │ ├── IterableValuedPropertyView.java │ │ │ │ │ ├── PlatformDetailedPropertiesView.java │ │ │ │ │ ├── PlatformPropertiesView.java │ │ │ │ │ ├── PropertyReferenceScanner.java │ │ │ │ │ ├── PropertySearchResultView.java │ │ │ │ │ └── ValuedPropertyView.java │ │ │ │ ├── security │ │ │ │ ├── AuthorizationProjectionRepository.java │ │ │ │ ├── UserRepository.java │ │ │ │ ├── commands │ │ │ │ │ ├── ApplicationDirectoryGroupsAggregate.java │ │ │ │ │ └── ApplicationDirectoryGroupsCommands.java │ │ │ │ ├── entities │ │ │ │ │ ├── ApplicationDirectoryGroups.java │ │ │ │ │ ├── User.java │ │ │ │ │ └── springauthorities │ │ │ │ │ │ ├── ApplicationProdRole.java │ │ │ │ │ │ ├── DirectoryGroupDN.java │ │ │ │ │ │ └── GlobalRole.java │ │ │ │ ├── exceptions │ │ │ │ │ ├── CreateDirectoryGroupsForbiddenException.java │ │ │ │ │ ├── InvalidDirectoryGroupsException.java │ │ │ │ │ ├── UpdateDirectoryGroupsForbiddenException.java │ │ │ │ │ └── UserNotFoundException.java │ │ │ │ └── queries │ │ │ │ │ ├── ApplicationDirectoryGroupsQueries.java │ │ │ │ │ ├── UserQueries.java │ │ │ │ │ └── views │ │ │ │ │ ├── ApplicationDirectoryGroupsView.java │ │ │ │ │ └── DirectoryGroupsView.java │ │ │ │ ├── technos │ │ │ │ ├── TechnoProjectionRepository.java │ │ │ │ ├── commands │ │ │ │ │ ├── TechnoAggregate.java │ │ │ │ │ └── TechnoCommands.java │ │ │ │ ├── entities │ │ │ │ │ └── Techno.java │ │ │ │ ├── exception │ │ │ │ │ ├── DuplicateTechnoException.java │ │ │ │ │ ├── TechnoNotFoundException.java │ │ │ │ │ └── UndeletableTechnoInUseException.java │ │ │ │ └── queries │ │ │ │ │ ├── TechnoQueries.java │ │ │ │ │ └── TechnoView.java │ │ │ │ └── templatecontainers │ │ │ │ ├── entities │ │ │ │ ├── AbstractProperty.java │ │ │ │ ├── IterableProperty.java │ │ │ │ ├── Property.java │ │ │ │ ├── Template.java │ │ │ │ └── TemplateContainer.java │ │ │ │ ├── exceptions │ │ │ │ ├── InvalidTemplateException.java │ │ │ │ └── PropertyWithSameNameAsIterablePropertyException.java │ │ │ │ └── queries │ │ │ │ ├── AbstractPropertyView.java │ │ │ │ ├── IterablePropertyView.java │ │ │ │ ├── PropertyView.java │ │ │ │ ├── TemplateContainerKeyView.java │ │ │ │ └── TemplateView.java │ │ └── kotlin │ │ │ └── org │ │ │ └── hesperides │ │ │ └── core │ │ │ └── domain │ │ │ ├── events │ │ │ └── Events.kt │ │ │ ├── modules │ │ │ ├── Module.kt │ │ │ └── Template.kt │ │ │ ├── platforms │ │ │ └── Platform.kt │ │ │ ├── security │ │ │ ├── Authorization.kt │ │ │ └── User.kt │ │ │ └── technos │ │ │ └── Techno.kt │ │ └── test │ │ ├── java │ │ └── org │ │ │ └── hesperides │ │ │ └── core │ │ │ └── domain │ │ │ ├── diff │ │ │ └── PropertiesDiffTest.java │ │ │ ├── files │ │ │ └── InstanceFileViewTest.java │ │ │ ├── platforms │ │ │ └── entities │ │ │ │ └── PlatformTest.java │ │ │ └── templatecontainers │ │ │ └── entities │ │ │ └── PropertyTest.java │ │ └── resources │ │ └── logback-test.xml ├── infrastructure │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── org │ │ │ │ └── hesperides │ │ │ │ └── core │ │ │ │ └── infrastructure │ │ │ │ ├── MinimalPlatformRepository.java │ │ │ │ ├── axon │ │ │ │ ├── AxonConfiguration.java │ │ │ │ └── SecureXStreamSerializer.java │ │ │ │ ├── inmemory │ │ │ │ └── platforms │ │ │ │ │ └── InmemoryPlatformRepository.java │ │ │ │ ├── mongo │ │ │ │ ├── Collections.java │ │ │ │ ├── FakeMongoConfiguration.java │ │ │ │ ├── MongoConfiguration.java │ │ │ │ ├── authorizations │ │ │ │ │ ├── ApplicationDirectoryGroupsDocument.java │ │ │ │ │ ├── MongoApplicationDirectoryGroupsRepository.java │ │ │ │ │ └── MongoAuthorizationProjectionRepository.java │ │ │ │ ├── events │ │ │ │ │ ├── EventDocument.java │ │ │ │ │ ├── MongoAxonEventRepository.java │ │ │ │ │ └── MongoEventRepository.java │ │ │ │ ├── modules │ │ │ │ │ ├── ModuleDocument.java │ │ │ │ │ ├── MongoModuleProjectionRepository.java │ │ │ │ │ ├── MongoModuleRepository.java │ │ │ │ │ └── MongoTemplateProjectionRepository.java │ │ │ │ ├── platforms │ │ │ │ │ ├── MongoPlatformProjectionRepository.java │ │ │ │ │ ├── MongoPlatformRepository.java │ │ │ │ │ └── documents │ │ │ │ │ │ ├── AbstractValuedPropertyDocument.java │ │ │ │ │ │ ├── DeployedModuleDocument.java │ │ │ │ │ │ ├── InstanceDocument.java │ │ │ │ │ │ ├── IterablePropertyItemDocument.java │ │ │ │ │ │ ├── IterableValuedPropertyDocument.java │ │ │ │ │ │ ├── PlatformDocument.java │ │ │ │ │ │ ├── PlatformKeyDocument.java │ │ │ │ │ │ └── ValuedPropertyDocument.java │ │ │ │ ├── technos │ │ │ │ │ ├── MongoTechnoProjectionRepository.java │ │ │ │ │ ├── MongoTechnoRepository.java │ │ │ │ │ └── TechnoDocument.java │ │ │ │ └── templatecontainers │ │ │ │ │ ├── AbstractPropertyDocument.java │ │ │ │ │ ├── IterablePropertyDocument.java │ │ │ │ │ ├── KeyDocument.java │ │ │ │ │ ├── PropertyDocument.java │ │ │ │ │ └── TemplateDocument.java │ │ │ │ ├── monitoring │ │ │ │ ├── PrometheusConfiguration.java │ │ │ │ └── SentryConfiguration.java │ │ │ │ └── security │ │ │ │ ├── LdapAuthenticationProvider.java │ │ │ │ ├── LdapCNSearcher.java │ │ │ │ ├── LdapConfiguration.java │ │ │ │ ├── LdapUserRepository.java │ │ │ │ └── groups │ │ │ │ ├── CachedParentLdapGroupAuthorityRetriever.java │ │ │ │ ├── LdapSearchContext.java │ │ │ │ ├── LdapSearchMetrics.java │ │ │ │ └── ParentGroupsDNRetriever.java │ │ └── resources │ │ │ └── db │ │ │ └── changelog │ │ │ ├── db.changelog-axon-3.2.yaml │ │ │ ├── db.changelog-hesperides-1.0.yaml │ │ │ └── db.changelog-master.yaml │ │ └── test │ │ └── java │ │ └── org │ │ └── hesperides │ │ └── core │ │ └── infrastructure │ │ └── security │ │ └── groups │ │ └── CachedParentLdapGroupAuthorityRetrieverTest.java ├── pom.xml └── presentation │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── hesperides │ │ │ └── core │ │ │ └── presentation │ │ │ ├── PresentationConfiguration.java │ │ │ ├── controllers │ │ │ ├── AbstractController.java │ │ │ ├── ApplicationsController.java │ │ │ ├── EventsController.java │ │ │ ├── FilesController.java │ │ │ ├── ModuleTemplatesController.java │ │ │ ├── ModulesController.java │ │ │ ├── PlatformsController.java │ │ │ ├── PropertiesController.java │ │ │ ├── TechnoTemplatesController.java │ │ │ ├── TechnosController.java │ │ │ ├── UsersController.java │ │ │ └── VersionsController.java │ │ │ ├── exceptions │ │ │ └── GlobalExceptionHandler.java │ │ │ ├── io │ │ │ ├── ModuleIO.java │ │ │ ├── ModuleKeyOutput.java │ │ │ ├── OnlyPrintableCharacters.java │ │ │ ├── OnlyPrintableCharactersValidator.java │ │ │ ├── TechnoIO.java │ │ │ ├── UserInfoOutput.java │ │ │ ├── events │ │ │ │ ├── EventOutput.java │ │ │ │ ├── ModuleCreatedEventIO.java │ │ │ │ ├── TemplateCreatedEventIO.java │ │ │ │ └── TemplateUpdatedEventIO.java │ │ │ ├── files │ │ │ │ └── InstanceFileOutput.java │ │ │ ├── platforms │ │ │ │ ├── AllApplicationsDetailOutput.java │ │ │ │ ├── ApplicationDirectoryGroupsInput.java │ │ │ │ ├── ApplicationOutput.java │ │ │ │ ├── DeployedModuleIO.java │ │ │ │ ├── InstanceIO.java │ │ │ │ ├── InstancesModelOutput.java │ │ │ │ ├── ModulePlatformsOutput.java │ │ │ │ ├── PlatformEventOutput.java │ │ │ │ ├── PlatformIO.java │ │ │ │ ├── PropertiesEventOutput.java │ │ │ │ ├── SearchResultOutput.java │ │ │ │ └── properties │ │ │ │ │ ├── AbstractValuedPropertyIO.java │ │ │ │ │ ├── FlatPasswordsOutput.java │ │ │ │ │ ├── GlobalPropertyUsageOutput.java │ │ │ │ │ ├── IterablePropertyItemIO.java │ │ │ │ │ ├── IterableValuedPropertyIO.java │ │ │ │ │ ├── PlatformDetailedPropertiesOutput.java │ │ │ │ │ ├── PlatformPasswordsOutput.java │ │ │ │ │ ├── PropertiesIO.java │ │ │ │ │ ├── PropertySearchResultOutput.java │ │ │ │ │ ├── ValuedPropertyIO.java │ │ │ │ │ └── diff │ │ │ │ │ ├── AbstractDifferingPropertyOutput.java │ │ │ │ │ ├── DualDifferingPropertyOutput.java │ │ │ │ │ ├── IterableDifferingPropertyOutput.java │ │ │ │ │ ├── NonDifferingPropertyOutput.java │ │ │ │ │ ├── PropertiesDiffOutput.java │ │ │ │ │ └── PropertyDiffValueOutput.java │ │ │ └── templatecontainers │ │ │ │ ├── ModelOutput.java │ │ │ │ ├── PartialTemplateIO.java │ │ │ │ ├── PropertyOutput.java │ │ │ │ └── TemplateIO.java │ │ │ ├── security │ │ │ ├── HttpFirewallConfiguration.java │ │ │ ├── LocalWebSecurityConfig.java │ │ │ ├── VerboseBasicAuthenticationEntryPoint.java │ │ │ └── WebSecurityConfig.java │ │ │ └── swagger │ │ │ ├── SpringfoxJsonToGsonAdapter.java │ │ │ └── SwaggerConfiguration.java │ └── resources │ │ └── swagger-ui.html │ └── test │ └── java │ └── org │ └── hesperides │ └── core │ └── presentation │ ├── config │ └── TestAppConfig.java │ └── controllers │ ├── AbstractControllerTest.java │ ├── ModulesControllerTest.java │ └── SwaggerControllerTest.java ├── docker ├── docker-compose-mongo.yml └── docker-compose.yml ├── docker_entrypoint.sh ├── documentation ├── architecture │ ├── cqrs_event_sourcing.md │ ├── docker.md │ ├── draw.io │ │ ├── cqrs_event_sourcing.xml │ │ └── hexagonal.xml │ ├── hexagonal.md │ ├── images │ │ ├── axon-iq-logo.png │ │ ├── cqrs_event_sourcing.png │ │ ├── hexagonal.png │ │ ├── mongodb-logo.png │ │ └── spring-boot-logo.png │ ├── mongodb.md │ ├── monitoring.md │ ├── sentry-error-message-filter.png │ └── spring-boot-auto-configuration.md ├── domain_model.drawio ├── domain_model.png ├── lightweight-architecture-decision-records │ ├── ACLs_pseudo_UML.png │ ├── access_control.md │ ├── aggregate_identifiers.md │ ├── application_properties.md │ ├── clean_unused_properties.md │ ├── database.md │ ├── ddd_cqrs_event_sourcing.md │ ├── deprecated_endpoints.md │ ├── detailed_properties.md │ ├── diff.md │ ├── events_history │ │ ├── index.md │ │ ├── platform_events.md │ │ ├── properties_events.md │ │ └── template_container_events.md │ ├── java_11.md │ ├── letter_case_sensitivity_in_rest_api.md │ ├── mongo_optim.md │ ├── move_to_spring_boot.md │ ├── regression_testing.md │ ├── search_properties.md │ ├── spring-actuator-endpoints.md │ ├── swagger_customization.md │ ├── tests_strategy.md │ ├── update_module_properties.md │ ├── use_axon_framework.md │ ├── use_gson.md │ ├── use_kotlin.md │ └── use_lombok.md └── postman │ ├── hesperides.postman_collection.json │ ├── hesperides_local.postman_environment.json │ └── postman.md ├── heroku.yml ├── mongo_create_collections.js ├── mongo_test_create_collections.js ├── pom.xml └── tests ├── activedirectory-integration ├── README.md ├── pom.xml └── src │ └── test │ ├── java │ └── org │ │ └── hesperides │ │ └── test │ │ └── activedirectory_integration │ │ └── CucumberActiveDirectoryIntegTests.java │ └── resources │ └── logback-test.xml ├── bdd ├── README.md ├── pom.xml └── src │ ├── main │ └── java │ │ └── org │ │ └── hesperides │ │ └── test │ │ └── bdd │ │ ├── applications │ │ ├── ApplicationClient.java │ │ ├── ApplicationDirectoryGroupsBuilder.java │ │ └── scenarios │ │ │ ├── CreateApplications.java │ │ │ ├── GetApplications.java │ │ │ └── SearchApplications.java │ │ ├── commons │ │ ├── CommonSteps.java │ │ ├── DataTableHelper.java │ │ ├── HesperidesScenario.java │ │ └── TestContext.java │ │ ├── configuration │ │ ├── AuthorizationCredentialsConfig.java │ │ ├── CustomRestTemplate.java │ │ ├── TestContextCleaner.java │ │ ├── TestDatabaseCleaner.java │ │ ├── TestExceptionHandler.java │ │ └── TestRestTemplateConfig.java │ │ ├── events │ │ ├── EventClient.java │ │ └── GetEvents.java │ │ ├── files │ │ ├── FileBuilder.java │ │ ├── FileClient.java │ │ └── scenarios │ │ │ ├── GetFile.java │ │ │ └── GetFiles.java │ │ ├── modules │ │ ├── ModuleBuilder.java │ │ ├── ModuleClient.java │ │ ├── ModuleHistory.java │ │ └── scenarios │ │ │ ├── CopyModules.java │ │ │ ├── CreateModules.java │ │ │ ├── DeleteModules.java │ │ │ ├── GetModules.java │ │ │ ├── GetModulesModel.java │ │ │ ├── ReleaseModules.java │ │ │ ├── SearchModules.java │ │ │ ├── UpdateModules.java │ │ │ └── templates │ │ │ ├── CreateModuleTemplates.java │ │ │ ├── DeleteModuleTemplates.java │ │ │ ├── GetModuleTemplates.java │ │ │ └── UpdateModuleTemplates.java │ │ ├── platforms │ │ ├── PlatformClient.java │ │ ├── PlatformHistory.java │ │ ├── builders │ │ │ ├── DeployedModuleBuilder.java │ │ │ ├── InstanceBuilder.java │ │ │ └── PlatformBuilder.java │ │ └── scenarios │ │ │ ├── CopyPlatforms.java │ │ │ ├── CreatePlatforms.java │ │ │ ├── DeletePlatforms.java │ │ │ ├── GetDetailedProperties.java │ │ │ ├── GetInstancesModel.java │ │ │ ├── GetPlatformEvents.java │ │ │ ├── GetPlatforms.java │ │ │ ├── GetProperties.java │ │ │ ├── GetPropertiesDiff.java │ │ │ ├── GetPropertiesEvents.java │ │ │ ├── PurgeProperties.java │ │ │ ├── SaveProperties.java │ │ │ ├── SearchPlatforms.java │ │ │ ├── SearchProperties.java │ │ │ ├── UpdatePlatforms.java │ │ │ └── UpdateProperties.java │ │ ├── technos │ │ ├── TechnoBuilder.java │ │ ├── TechnoClient.java │ │ ├── TechnoHistory.java │ │ └── scenarios │ │ │ ├── CopyTechnos.java │ │ │ ├── CreateTechnos.java │ │ │ ├── DeleteTechnos.java │ │ │ ├── GetTechnos.java │ │ │ ├── GetTechnosModel.java │ │ │ ├── ReleaseTechnos.java │ │ │ ├── SearchTechnos.java │ │ │ └── templates │ │ │ ├── CreateTechnoTemplates.java │ │ │ ├── DeleteTechnoTemplates.java │ │ │ ├── GetTechnoTemplates.java │ │ │ └── UpdateTechnoTemplates.java │ │ ├── templatecontainers │ │ ├── TestVersionType.java │ │ ├── builders │ │ │ ├── PropertyBuilder.java │ │ │ ├── TemplateBuilder.java │ │ │ └── TemplateContainerBuilder.java │ │ └── scenarios │ │ │ ├── CreateTemplates.java │ │ │ └── UpdateTemplates.java │ │ ├── users │ │ ├── GetUserInformation.java │ │ ├── UserAuthorities.java │ │ └── UserClient.java │ │ └── versions │ │ └── GetApplicationVersion.java │ └── test │ ├── java │ └── org │ │ └── hesperides │ │ └── test │ │ └── bdd │ │ └── CucumberTests.java │ └── resources │ ├── application-test.yml │ ├── authorizations │ ├── do-not-restrict-prod-actions-for-users-with-acls.feature │ ├── get-application-directory-groups.feature │ ├── get-user-authorities.feature │ ├── obfuscated-passwords.feature │ ├── restrict-prod-actions.feature │ └── set-application-prod-groups.feature │ ├── events │ ├── get-module-events.feature │ └── get-platform-events.feature │ ├── files │ ├── get-file.feature │ └── get-files.feature │ ├── logback-test.xml │ ├── modules │ ├── copy-modules.feature │ ├── create-modules.feature │ ├── delete-modules.feature │ ├── get-modules-model.feature │ ├── get-modules-name.feature │ ├── get-modules-types.feature │ ├── get-modules-using-techno.feature │ ├── get-modules-versions.feature │ ├── get-modules.feature │ ├── release-modules.feature │ ├── search-modules.feature │ ├── templates │ │ ├── create-module-templates.feature │ │ ├── delete-module-templates.feature │ │ ├── get-module-templates.feature │ │ └── update-module-templates.feature │ └── update-modules.feature │ ├── platforms │ ├── applications │ │ ├── get-applications.feature │ │ └── search-applications.feature │ ├── copy-platforms.feature │ ├── create-platforms.feature │ ├── delete-platforms.feature │ ├── get-instance-model.feature │ ├── get-platform-at-point-in-time.feature │ ├── get-platform-events.feature │ ├── get-platforms-using-module.feature │ ├── get-platforms.feature │ ├── properties │ │ ├── get-detailed-properties.feature │ │ ├── get-global-properties-usage.feature │ │ ├── get-properties-diffs.feature │ │ ├── get-properties-events.feature │ │ ├── get-properties.feature │ │ ├── purge-properties.feature │ │ ├── save-properties.feature │ │ ├── search-properties.feature │ │ └── update-properties.feature │ ├── restore-platforms.feature │ ├── search-platforms.feature │ └── update-platforms.feature │ ├── technos │ ├── copy-technos.feature │ ├── create-technos.feature │ ├── delete-technos.feature │ ├── get-technos-model.feature │ ├── get-technos-name.feature │ ├── get-technos-types.feature │ ├── get-technos-versions.feature │ ├── get-technos.feature │ ├── release-technos.feature │ ├── search-technos.feature │ └── templates │ │ ├── create-techno-templates.feature │ │ ├── delete-techno-templates.feature │ │ ├── get-techno-templates.feature │ │ └── update-techno-templates.feature │ ├── users │ ├── get-any-user-information.feature │ ├── get-logged-user-information.feature │ └── user-logout.feature │ └── versions │ └── get-application-version.feature ├── mongo-integration ├── README.md ├── pom.xml └── src │ └── test │ ├── java │ └── org │ │ └── hesperides │ │ └── test │ │ └── mongo_integration │ │ ├── CucumberMongoIntegTests.java │ │ └── config │ │ ├── IntegTestConfig.java │ │ └── IntegTestHttpConfig.java │ └── resources │ ├── application-test.yml │ └── logback-test.xml ├── perfs ├── README.md ├── dependency-reduced-pom.xml ├── pom.xml └── src │ └── test │ ├── resources │ ├── gatling.conf │ └── logback.xml │ └── scala │ ├── HesperidesApi.scala │ ├── conf │ └── Config.scala │ ├── feeder │ └── Feeders.scala │ ├── process │ ├── Events.scala │ ├── Modules.scala │ └── Platforms.scala │ └── scenario │ └── Generic.scala ├── pom.xml └── regression ├── pom.xml └── src └── test ├── java └── org │ └── hesperides │ └── test │ └── regression │ ├── RegressionLogs.java │ ├── RegressionTests.java │ ├── RestConfiguration.java │ ├── errors │ ├── AbstractError.java │ ├── Diff.java │ └── UnexpectedException.java │ └── validation │ ├── AbstractValidation.java │ ├── ModulesValidation.java │ ├── PlatformsValidation.java │ └── TechnosValidation.java └── resources ├── application.yml └── logback-test.xml /.dockerignore: -------------------------------------------------------------------------------- 1 | /.git/ 2 | /bootstrap/target 3 | /Dockerfile 4 | /*.log -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.groovy text eol=lf -crlf 2 | *.java text eol=lf -crlf 3 | *.json text eol=lf -crlf 4 | *.mustache text eol=lf -crlf 5 | *.txt text eol=lf -crlf 6 | *.yml text eol=lf -crlf 7 | -------------------------------------------------------------------------------- /.gitchangelog-keepachangelog.tpl: -------------------------------------------------------------------------------- 1 | {{#versions}} 2 | ## {{#tag}}{{{tag}}}{{/tag}}{{^tag}}_(unreleased)_{{/tag}} 3 | {{#sections}} 4 | ### {{{label}}} 5 | 6 | {{#commits}} 7 | - {{{subject}}} [{{{author}}}] 8 | 9 | {{/commits}} 10 | 11 | {{/sections}} 12 | 13 | {{/versions}} -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | **TL;DR** 3 | 4 | 5 | ### Extra Detail 6 | 7 | #### Screenshots 8 | 9 | 10 | #### Reasoning 11 | 12 | 13 | ### How to Contribute 14 | - [ ] Comment on this issue if you'd like to work/collaborate on it! 15 | - [ ] Fork the [repository](https://github.com/voyages-sncf-technologies/hesperides). 16 | - [ ] Use the [GitHub Flow](https://guides.github.com/introduction/flow/) to make changes to your fork. [This](https://services.github.com/on-demand/intro-to-github/) is a refresher course if you're unsure about how to make a change on GitHub. 17 | - [ ] Push your changes to your repository. 18 | - [ ] Submit a Pull Request 19 | - Base Dropdown: voyages-sncf-technologies/hesperides 20 | - Compare Dropdown: Your fork 21 | 22 | ### Questions? 23 | - Leave a comment on this issue! Make sure to use @ mentions if you want a specific person's attention! -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Desktop (please complete the following information):** 24 | - OS: [e.g. iOS] 25 | - Browser [e.g. chrome, safari] 26 | - Version [e.g. 22] 27 | 28 | **Smartphone (please complete the following information):** 29 | - Device: [e.g. iPhone6] 30 | - OS: [e.g. iOS8.1] 31 | - Browser [e.g. stock browser, safari] 32 | - Version [e.g. 22] 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | **TL;DR** 3 | 4 | 5 | 6 | 7 | ### Questions 8 | 9 | 10 | ### Next Steps 11 | 12 | 13 | ### Review 14 | -------------------------------------------------------------------------------- /.github/no-response.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-no-response - https://github.com/probot/no-response 2 | 3 | # Number of days of inactivity before an Issue is closed for lack of response 4 | daysUntilClose: 90 5 | # Label requiring a response 6 | responseRequiredLabel: pending-answer 7 | # Comment to post when closing an Issue for lack of response. Set to `false` to disable 8 | closeComment: > 9 | This issue has been automatically closed because there has been no response 10 | to our request for more information from the original author. With only the 11 | information that is currently in the issue, we don't have enough information 12 | to take action. Please reach out if you have or find the answers we need so 13 | that we can investigate further. 14 | -------------------------------------------------------------------------------- /.github/workflows/docker_build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o pipefail -o errexit -o nounset -o xtrace 4 | 5 | GIT_COMMIT_MSG="${1?'Required parameter'}" 6 | 7 | docker build -t $DOCKER_IMAGE:$GITHUB_SHA \ 8 | --label date=$(date +%F) \ 9 | --label git_commit=$GITHUB_SHA \ 10 | --build-arg BUILD_TIME=$(date +%FT%T) \ 11 | --build-arg GIT_TAG=$(date +%F) \ 12 | --build-arg GIT_BRANCH=$GITHUB_REF \ 13 | --build-arg GIT_COMMIT=$GITHUB_SHA \ 14 | --build-arg GIT_COMMIT_MSG="$GIT_COMMIT_MSG" . 15 | 16 | # We validate that the image built can start without any error: 17 | docker run --rm -e SPRING_PROFILES_ACTIVE=noldap,fake_mongo -e EXIT_AFTER_INIT=true $DOCKER_IMAGE:$GITHUB_SHA 18 | -------------------------------------------------------------------------------- /.github/workflows/docker_push.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o pipefail -o errexit -o nounset -o xtrace 4 | 5 | if [ "$DOCKER_USER" != "" ] && [ "$DOCKER_PASS" != "" ]; then 6 | docker login -u "$DOCKER_USER" -p "$DOCKER_PASS" 7 | if [ "$GITHUB_REF" == "refs/heads/master" ]; then 8 | TAG=latest 9 | else 10 | TAG=$(echo "$GITHUB_REF" | sed -e 's~/~_~g' -e 's/#//g' -e 's/-/_/g') 11 | fi 12 | docker tag "$DOCKER_IMAGE":"$GITHUB_SHA" "$DOCKER_IMAGE":"$TAG" 13 | echo "✓ Docker image $DOCKER_IMAGE:$GITHUB_REF tagged: $TAG" 14 | docker push "$DOCKER_IMAGE":"$TAG" 15 | echo "✓ Docker image pushed to public hub with version $TAG" 16 | docker tag "$DOCKER_IMAGE":"$TAG" "$DOCKER_IMAGE":$(date +%F) 17 | docker push "$DOCKER_IMAGE":$(date +%F) 18 | echo "✓ Docker image pushed to public hub with version $(date +%F)" 19 | else 20 | echo "✗ Missing $DOCKER_USER or $DOCKER_PASS environment variable" 21 | fi 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | target/ 3 | *.iml 4 | *.orig 5 | *.bak 6 | hesperides.yml 7 | hesperides.iml 8 | rebel.xml 9 | data/ 10 | .m2settings.xml 11 | /hesperides/bootstrap/src/main/resources/application-corp.yml 12 | /hesperides/tests/perfs/dependency-reduced-pom.xml 13 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sncf-connect-tech/hesperides/90995d20e0a213cf4e98457ab7958aa35393164d/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip 2 | -------------------------------------------------------------------------------- /Dockerfile.heroku: -------------------------------------------------------------------------------- 1 | # Recipe from: https://stackoverflow.com/a/58204409/636849 2 | FROM hesperides/hesperides 3 | 4 | CMD /usr/local/bin/java $JAVA_OPTS \ 5 | -XX:+ExitOnOutOfMemoryError -XX:+HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow \ 6 | -Xms2g -Xmx4g \ 7 | -jar /hesperides.jar 8 | -------------------------------------------------------------------------------- /bootstrap/src/main/java/org/hesperides/HesperidesSpringApplication.java: -------------------------------------------------------------------------------- 1 | package org.hesperides; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.cache.annotation.EnableCaching; 7 | import org.springframework.context.ConfigurableApplicationContext; 8 | 9 | import java.util.Arrays; 10 | 11 | @SpringBootApplication 12 | @EnableCaching 13 | @Slf4j 14 | public class HesperidesSpringApplication { 15 | 16 | public static void main(String[] args) { 17 | log.info("Program arguments: " + Arrays.toString(args)); 18 | System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true"); 19 | ConfigurableApplicationContext ctx = SpringApplication.run(HesperidesSpringApplication.class, args); 20 | if (System.getenv("EXIT_AFTER_INIT") != null) { 21 | log.info("Immediately stopping the app:"); 22 | System.exit(SpringApplication.exit(ctx, () -> 0)); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /bootstrap/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ._-'-_ . 2 | ) . ' /_-_-_\ ` . 3 | /( .' |-_-_-_-| `. 4 | _ (_)) _ _ ( `.-_-_-.' ) 5 | | | / __) (_) | | !`. .'! 6 | | |__ _____ _| |__ ____ _____ ____ _ __| |_____ ___ !` . . ' ! 7 | | _ \| ___ (_ __) _ \| ___ |/ ___) |/ _ | ___ |/___) ! ! ! ! ! ! ! ! ! 8 | | | | | ____| | | | |_| | ____| | | ( (_| | ____|___ | / / \ \ 9 | |_| |_|_____) |_| | __/|_____)_| |_|\____|_____|___/ _-| \___ ___/ /-_ 10 | |_| -------------------------------------------------------------------------------- /bootstrap/src/main/resources/ehcache.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 14 | 15 | 16 | 23 | 24 | 25 | 32 | -------------------------------------------------------------------------------- /bootstrap/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /commons/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | hesperides 7 | org.hesperides 8 | 4.3-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | commons 13 | 14 | 15 | 16 | org.axonframework 17 | axon-spring-boot-starter 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-web 22 | 23 | 24 | org.apache.commons 25 | commons-lang3 26 | 27 | 28 | -------------------------------------------------------------------------------- /commons/src/main/java/org/hesperides/commons/DomainPrimer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.commons; 22 | 23 | import java.util.Optional; 24 | 25 | /** 26 | * Interface à utiliser lorsqu'un objet doit implémenter la méthode toDomainInstance sur un object potentiellement null. 27 | * "Primer" signifie "amorceur" (du verbe to prime, amorcer). 28 | * 29 | * @param 30 | */ 31 | public interface DomainPrimer { 32 | T toDomainInstance(); 33 | 34 | static O toDomainInstanceOrNull(DomainPrimer candidate) { 35 | return Optional.ofNullable(candidate).map(DomainPrimer::toDomainInstance).orElse(null); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /commons/src/main/java/org/hesperides/commons/SpringProfiles.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.commons; 22 | 23 | import org.springframework.beans.factory.annotation.Autowired; 24 | import org.springframework.core.env.Environment; 25 | import org.springframework.stereotype.Component; 26 | 27 | import java.util.Arrays; 28 | 29 | @Component 30 | public class SpringProfiles { 31 | 32 | public static final String MONGO = "mongo"; 33 | public static final String FAKE_MONGO = "fake_mongo"; 34 | public static final String LDAP = "ldap"; 35 | public static final String NOLDAP = "noldap"; 36 | public static final String TEST = "test"; 37 | 38 | @Autowired 39 | private Environment environment; 40 | 41 | public boolean isActive(String profile) { 42 | return Arrays.asList(environment.getActiveProfiles()).contains(profile); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /commons/src/main/java/org/hesperides/commons/VersionIdLogger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.commons; 22 | 23 | import lombok.extern.slf4j.Slf4j; 24 | 25 | @Slf4j 26 | public class VersionIdLogger { 27 | 28 | public static void log(boolean isBeforeEvent, String aggregateType, String aggregateId, Long aggregateVersionId, Long entityVersionId) { 29 | String message = isBeforeEvent ? "Before" : "After"; 30 | message += " event, " + aggregateType + " aggregate, id: " + aggregateId + ", versionId: " + aggregateVersionId; 31 | if (entityVersionId != null) { 32 | message += ", entity versionId: " + entityVersionId; 33 | } 34 | log.debug(message); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core/application/src/main/java/org/hesperides/core/application/files/InfiniteMustacheRecursion.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.application.files; 2 | 3 | public class InfiniteMustacheRecursion extends RuntimeException { 4 | public InfiniteMustacheRecursion(String errorMsg) { 5 | super(errorMsg); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /core/application/src/main/java/org/hesperides/core/application/platforms/properties/PropertyType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.application.platforms.properties; 22 | 23 | public enum PropertyType { 24 | GLOBAL, 25 | WITHOUT_MODEL 26 | } 27 | -------------------------------------------------------------------------------- /core/application/src/main/java/org/hesperides/core/application/security/UserUseCases.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.application.security; 2 | 3 | import org.hesperides.core.domain.security.entities.User; 4 | import org.hesperides.core.domain.security.exceptions.UserNotFoundException; 5 | import org.hesperides.core.domain.security.queries.UserQueries; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public class UserUseCases { 11 | 12 | private final UserQueries userQueries; 13 | 14 | @Autowired 15 | public UserUseCases(UserQueries userQueries) { 16 | this.userQueries = userQueries; 17 | } 18 | 19 | public User getUser(String username) { 20 | return userQueries.getOptionalUser(username) 21 | .orElseThrow(() -> new UserNotFoundException(username)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/events/EventRepository.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.events; 2 | 3 | import org.axonframework.queryhandling.QueryHandler; 4 | import org.hesperides.core.domain.events.queries.EventView; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.List; 8 | 9 | @Repository 10 | public interface EventRepository { 11 | 12 | @QueryHandler 13 | List onGetLastToFirstEventsQuery(GetLastToFirstEventsQuery query); 14 | 15 | @QueryHandler 16 | List onGetLastToFirstPlatformModulePropertiesUpdatedEvents(GetLastToFirstPlatformModulePropertiesUpdatedEvents query); 17 | 18 | void cleanAggregateEvents(String aggregateIdentifier); 19 | } 20 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/events/commands/EventCommands.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.domain.events.commands; 22 | 23 | import org.hesperides.core.domain.events.EventRepository; 24 | import org.springframework.beans.factory.annotation.Autowired; 25 | import org.springframework.stereotype.Component; 26 | 27 | @Component 28 | public class EventCommands { 29 | 30 | private final EventRepository eventRepository; 31 | 32 | @Autowired 33 | public EventCommands(EventRepository eventRepository) { 34 | this.eventRepository = eventRepository; 35 | } 36 | 37 | public void cleanAggregateEvents(String aggregateIdentifier) { 38 | eventRepository.cleanAggregateEvents(aggregateIdentifier); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/events/queries/EventQueries.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.events.queries; 2 | 3 | import org.axonframework.queryhandling.QueryGateway; 4 | import org.hesperides.commons.axon.AxonQueries; 5 | import org.hesperides.core.domain.events.GetLastToFirstEventsQuery; 6 | import org.hesperides.core.domain.events.GetLastToFirstPlatformModulePropertiesUpdatedEvents; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.List; 10 | 11 | 12 | @Component 13 | public class EventQueries extends AxonQueries { 14 | 15 | protected EventQueries(QueryGateway queryGateway) { 16 | super(queryGateway); 17 | } 18 | 19 | public List getLastToFirstEvents(String aggregateId, Integer page, Integer size) { 20 | return getLastToFirstEventsByTypes(aggregateId, new Class[0], page, size); 21 | } 22 | 23 | public List getLastToFirstEventsByType(String aggregateId, Class eventType, Integer page, Integer size) { 24 | return getLastToFirstEventsByTypes(aggregateId, new Class[]{eventType}, page, size); 25 | } 26 | 27 | public List getLastToFirstEventsByTypes(String aggregateId, Class[] eventTypes, Integer page, Integer size) { 28 | return querySyncList(new GetLastToFirstEventsQuery(aggregateId, eventTypes, page, size), EventView.class); 29 | } 30 | 31 | public List getLastToFirstPlatformModulePropertiesUpdatedEvents(String aggregateId, String propertiesPath, Integer page, Integer size) { 32 | return querySyncList(new GetLastToFirstPlatformModulePropertiesUpdatedEvents(aggregateId, propertiesPath, page, size), EventView.class); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/events/queries/EventView.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.events.queries; 2 | 3 | import lombok.Value; 4 | import org.hesperides.core.domain.security.UserEvent; 5 | 6 | import java.time.Instant; 7 | 8 | @Value 9 | public class EventView { 10 | String type; 11 | UserEvent data; 12 | Instant timestamp; 13 | } 14 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/exceptions/DuplicateException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.exceptions; 2 | 3 | public class DuplicateException extends RuntimeException { 4 | public DuplicateException(String message) { 5 | super(message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/exceptions/ForbiddenOperationException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.exceptions; 2 | 3 | public class ForbiddenOperationException extends RuntimeException { 4 | public ForbiddenOperationException(String message) { 5 | super(message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/exceptions/NotFoundException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.exceptions; 2 | 3 | public class NotFoundException extends RuntimeException { 4 | public NotFoundException(String message) { 5 | super(message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/exceptions/OutOfDateException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.exceptions; 2 | 3 | public abstract class OutOfDateException extends RuntimeException { 4 | 5 | public OutOfDateException(String message) { 6 | super(message); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/exceptions/OutOfDateGlobalPropertiesException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.exceptions; 2 | 3 | public class OutOfDateGlobalPropertiesException extends OutOfDateException { 4 | public OutOfDateGlobalPropertiesException(final Long expected, final Long actual) { 5 | super("Invalid global propertiesVersionId for : expected " + expected + " but found " + actual); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/exceptions/OutOfDatePlatformVersionException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.exceptions; 2 | 3 | public class OutOfDatePlatformVersionException extends OutOfDateException { 4 | public OutOfDatePlatformVersionException(final Long expected, final Long actual) { 5 | super("Invalid platform VersionId for : expected " + expected + " but found " + actual); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/exceptions/OutOfDatePropertiesException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.exceptions; 2 | 3 | import org.hesperides.core.domain.modules.entities.Module; 4 | 5 | public class OutOfDatePropertiesException extends OutOfDateException { 6 | public OutOfDatePropertiesException(final String path, final Long expected, final Long actual) { 7 | super("Invalid propertiesVersionId for " + Module.Key.fromPropertiesPath(path).toString() + ": expected " + expected + " but found " + actual); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/exceptions/OutOfDateVersionException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.exceptions; 2 | 3 | public class OutOfDateVersionException extends OutOfDateException { 4 | public OutOfDateVersionException(final Long expected, final Long actual) { 5 | super("Invalid versionId: expected " + expected + " but found " + actual); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/modules/TemplateProjectionRepository.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.modules; 2 | 3 | import org.axonframework.eventhandling.EventHandler; 4 | import org.axonframework.queryhandling.QueryHandler; 5 | import org.hesperides.core.domain.templatecontainers.queries.TemplateView; 6 | 7 | import java.util.List; 8 | import java.util.Optional; 9 | 10 | public interface TemplateProjectionRepository { 11 | 12 | /*** EVENT HANDLERS ***/ 13 | 14 | @EventHandler 15 | void onTemplateCreatedEvent(TemplateCreatedEvent event); 16 | 17 | @EventHandler 18 | void onTemplateUpdatedEvent(TemplateUpdatedEvent event); 19 | 20 | @EventHandler 21 | void onTemplateDeletedEvent(TemplateDeletedEvent event); 22 | 23 | /*** QUERY HANDLERS ***/ 24 | 25 | @QueryHandler 26 | Optional onGetTemplateByNameQuery(GetTemplateByNameQuery query); 27 | 28 | @QueryHandler 29 | List onGetModuleTemplatesQuery(GetModuleTemplatesQuery query); 30 | } 31 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/modules/exceptions/DuplicateModuleException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.modules.exceptions; 2 | 3 | import org.hesperides.core.domain.exceptions.DuplicateException; 4 | import org.hesperides.core.domain.templatecontainers.entities.TemplateContainer; 5 | 6 | public class DuplicateModuleException extends DuplicateException { 7 | public DuplicateModuleException(TemplateContainer.Key newModuleKey) { 8 | super("could not create a new module with key: " + newModuleKey.getNamespaceWithoutPrefix() + " as it already exists"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/modules/exceptions/DuplicateTemplateCreationException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.modules.exceptions; 2 | 3 | import org.hesperides.core.domain.exceptions.DuplicateException; 4 | import org.hesperides.core.domain.templatecontainers.entities.TemplateContainer; 5 | 6 | public class DuplicateTemplateCreationException extends DuplicateException { 7 | public DuplicateTemplateCreationException(TemplateContainer.Key templateContainerKey, String templateName) { 8 | super("Template " + templateContainerKey.getNamespaceWithoutPrefix() + "/" + templateName + " already exists"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/modules/exceptions/ModuleNotFoundException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.modules.exceptions; 2 | 3 | import org.hesperides.core.domain.exceptions.NotFoundException; 4 | import org.hesperides.core.domain.modules.entities.Module; 5 | import org.hesperides.core.domain.templatecontainers.entities.TemplateContainer; 6 | 7 | public class ModuleNotFoundException extends NotFoundException { 8 | public ModuleNotFoundException(TemplateContainer.Key key) { 9 | super("Could not find module info for " + key.getNamespaceWithoutPrefix()); 10 | } 11 | 12 | public ModuleNotFoundException(Module.Key key, String modulePath) { 13 | super("Could not find module " + key.getNamespaceWithoutPrefix() + " at path " + modulePath); 14 | } 15 | 16 | public ModuleNotFoundException(Module.Key key, String modulePath, Long timestamp) { 17 | super("Could not find module " + key.getNamespaceWithoutPrefix() + " at path " + modulePath + " and at timestamp " + timestamp); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/modules/exceptions/ModuleUsedByPlatformsException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.modules.exceptions; 2 | 3 | import org.hesperides.core.domain.platforms.queries.views.ModulePlatformView; 4 | import org.hesperides.core.domain.templatecontainers.entities.TemplateContainer; 5 | 6 | import java.util.List; 7 | import java.util.stream.Collectors; 8 | 9 | public class ModuleUsedByPlatformsException extends RuntimeException { 10 | 11 | public ModuleUsedByPlatformsException(TemplateContainer.Key moduleKey, List platforms) { 12 | super("Could not delete module " + moduleKey.getNamespaceWithoutPrefix() + 13 | " because it is used by platform(s): " + platforms.stream() 14 | .map(ModulePlatformView::toString) 15 | .collect(Collectors.joining(", "))); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/modules/exceptions/TemplateNotFoundException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.modules.exceptions; 2 | 3 | import org.hesperides.core.domain.exceptions.NotFoundException; 4 | import org.hesperides.core.domain.templatecontainers.entities.TemplateContainer; 5 | 6 | public class TemplateNotFoundException extends NotFoundException { 7 | public TemplateNotFoundException(TemplateContainer.Key templateContainerKey, String templateName) { 8 | super("Could not find template " + templateName + " in " + templateContainerKey.getNamespaceWithoutPrefix()); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/modules/exceptions/UpdateReleaseException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.domain.modules.exceptions; 22 | 23 | import org.hesperides.core.domain.templatecontainers.entities.TemplateContainer; 24 | 25 | public class UpdateReleaseException extends IllegalArgumentException { 26 | public UpdateReleaseException(TemplateContainer.Key key) { 27 | super("Could not update a released version of a module (key: " + key.getNamespaceWithoutPrefix() + ")"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/modules/queries/ModulePasswordProperties.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.modules.queries; 2 | 3 | import lombok.Value; 4 | import org.hesperides.core.domain.modules.entities.Module; 5 | 6 | import java.util.Set; 7 | 8 | @Value 9 | public class ModulePasswordProperties { 10 | Module.Key moduleKey; 11 | Set passwords; 12 | } 13 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/modules/queries/ModulePropertiesView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.domain.modules.queries; 22 | 23 | import lombok.Value; 24 | import org.hesperides.core.domain.modules.entities.Module; 25 | import org.hesperides.core.domain.templatecontainers.queries.AbstractPropertyView; 26 | 27 | import java.util.List; 28 | 29 | @Value 30 | public class ModulePropertiesView { 31 | Module.Key moduleKey; 32 | List properties; 33 | } 34 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/modules/queries/ModuleView.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.modules.queries; 2 | 3 | import lombok.Value; 4 | import org.hesperides.core.domain.modules.entities.Module; 5 | import org.hesperides.core.domain.technos.queries.TechnoView; 6 | import org.hesperides.core.domain.templatecontainers.entities.TemplateContainer; 7 | import org.hesperides.core.domain.templatecontainers.queries.TemplateView; 8 | 9 | import java.util.List; 10 | 11 | @Value 12 | public class ModuleView { 13 | String name; 14 | String version; 15 | boolean isWorkingCopy; 16 | List templates; 17 | List technos; 18 | Long versionId; 19 | 20 | public Module.Key getKey() { 21 | return new Module.Key(name, version, TemplateContainer.getVersionType(isWorkingCopy)); 22 | } 23 | 24 | public Module toDomainInstance() { 25 | TemplateContainer.Key moduleKey = getKey(); 26 | return new Module(moduleKey, TemplateView.toDomainInstances(templates, moduleKey), TechnoView.toDomainInstances(technos), versionId); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/entities/Instance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.domain.platforms.entities; 22 | 23 | import lombok.Value; 24 | import org.hesperides.core.domain.platforms.entities.properties.ValuedProperty; 25 | 26 | import java.util.List; 27 | 28 | @Value 29 | public class Instance { 30 | String name; 31 | List valuedProperties; 32 | } 33 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/entities/properties/IterablePropertyItem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.domain.platforms.entities.properties; 22 | 23 | import lombok.Value; 24 | 25 | import java.util.List; 26 | 27 | @Value 28 | public class IterablePropertyItem { 29 | 30 | String title; 31 | List abstractValuedProperties; 32 | } 33 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/entities/properties/ValuedPropertyTransformation.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.platforms.entities.properties; 2 | 3 | public enum ValuedPropertyTransformation { 4 | OVERRIDDEN_BY_GLOBAL, 5 | OVERRIDDEN_BY_INSTANCE, 6 | OVERRIDDEN_BY_PREDEFINED, 7 | PROPERTY_SUBSTITUTION_LEVEL_1, 8 | PROPERTY_SUBSTITUTION_LEVEL_2, 9 | PROPERTY_SUBSTITUTION_LEVEL_3, 10 | FROM_PARENT_ITERABLE, 11 | ERASED_DUE_TO_REMAINING_MUSTACHE 12 | } 13 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/entities/properties/diff/AbstractDifferingProperty.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.platforms.entities.properties.diff; 2 | 3 | import lombok.Value; 4 | import lombok.experimental.NonFinal; 5 | 6 | @Value 7 | @NonFinal 8 | public abstract class AbstractDifferingProperty { 9 | String name; 10 | } 11 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/entities/properties/diff/IterableDifferingProperty.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.platforms.entities.properties.diff; 2 | 3 | import lombok.EqualsAndHashCode; 4 | import lombok.Value; 5 | 6 | import java.util.List; 7 | 8 | @Value 9 | @EqualsAndHashCode(callSuper = true) 10 | public class IterableDifferingProperty extends AbstractDifferingProperty { 11 | 12 | List differingItems; 13 | 14 | IterableDifferingProperty(String name, List differingItems) { 15 | super(name); 16 | this.differingItems = differingItems; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/entities/properties/diff/SimpleDifferingProperty.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.platforms.entities.properties.diff; 2 | 3 | import lombok.EqualsAndHashCode; 4 | import lombok.Value; 5 | import org.hesperides.core.domain.platforms.entities.properties.visitors.SimplePropertyVisitor; 6 | import org.springframework.lang.Nullable; 7 | 8 | @Value 9 | @EqualsAndHashCode(callSuper = true) 10 | public class SimpleDifferingProperty extends AbstractDifferingProperty { 11 | 12 | @Nullable 13 | SimplePropertyVisitor left; 14 | @Nullable 15 | SimplePropertyVisitor right; 16 | 17 | SimpleDifferingProperty(String name, SimplePropertyVisitor left, SimplePropertyVisitor right) { 18 | super(name); 19 | this.left = left; 20 | this.right = right; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/entities/properties/visitors/PropertyVisitor.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.platforms.entities.properties.visitors; 2 | 3 | import org.hesperides.core.domain.platforms.entities.properties.diff.PropertiesDiff; 4 | 5 | import java.util.function.Consumer; 6 | import java.util.function.Function; 7 | 8 | /* Cette interface a 2 rôles : 9 | - coupler les modèles de propriétés avec leurs valorisations 10 | - permettre le parcours récursif de l'arbre de ces propriétés 11 | */ 12 | public interface PropertyVisitor { 13 | 14 | String getName(); 15 | 16 | void acceptSimplesRecursive(Consumer consumer); 17 | 18 | PropertyVisitor mapSimplesRecursive(Function mapper); 19 | 20 | PropertyVisitor mapSequencesRecursive(Function mapper); 21 | 22 | boolean equals(PropertyVisitor propertyVisitor, PropertiesDiff.ComparisonMode comparisonMode); 23 | 24 | boolean isValued(); 25 | } 26 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/exceptions/ApplicationNotFoundException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.platforms.exceptions; 2 | 3 | import org.hesperides.core.domain.exceptions.NotFoundException; 4 | 5 | public class ApplicationNotFoundException extends NotFoundException { 6 | public ApplicationNotFoundException(String applicationName) { 7 | super("Could not find application info for " + applicationName); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/exceptions/DeployedModuleNotFoundException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.platforms.exceptions; 2 | 3 | import org.hesperides.core.domain.exceptions.NotFoundException; 4 | import org.hesperides.core.domain.modules.entities.Module; 5 | import org.hesperides.core.domain.platforms.entities.Platform; 6 | 7 | public class DeployedModuleNotFoundException extends NotFoundException { 8 | public DeployedModuleNotFoundException(Platform.Key platformKey, Module.Key moduleKey, String modulePath) { 9 | super("Could not find module " + moduleKey.getNamespaceWithoutPrefix() + " with path " + modulePath + " on platform " + platformKey.getApplicationName() + "-" + platformKey.getPlatformName()); 10 | } 11 | public DeployedModuleNotFoundException(Platform.Key platformKey, String propertiesPath) { 12 | super("Could not find deployed module with properties path " + propertiesPath + " on platform " + platformKey.getApplicationName() + "-" + platformKey.getPlatformName()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/exceptions/DuplicateDeployedModuleIdException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.platforms.exceptions; 2 | 3 | import org.hesperides.core.domain.exceptions.DuplicateException; 4 | 5 | public class DuplicateDeployedModuleIdException extends DuplicateException { 6 | 7 | public DuplicateDeployedModuleIdException() { 8 | super("Trying to create or update a platform using the same id for multiple modules"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/exceptions/DuplicatePlatformException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.platforms.exceptions; 2 | 3 | import org.hesperides.core.domain.exceptions.DuplicateException; 4 | import org.hesperides.core.domain.platforms.entities.Platform; 5 | 6 | public class DuplicatePlatformException extends DuplicateException { 7 | public DuplicatePlatformException(Platform.Key platformKey) { 8 | super("Could not create a new platform with key: " + platformKey.getApplicationName() + "-" + platformKey.getPlatformName() + " as it already exists"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/exceptions/InexistantPlatformAtTimeException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.platforms.exceptions; 2 | 3 | import org.hesperides.core.domain.exceptions.NotFoundException; 4 | 5 | public class InexistantPlatformAtTimeException extends NotFoundException { 6 | public InexistantPlatformAtTimeException(Long timestamp) { 7 | super("Inexistant platform at this time" + (timestamp == null ? "" : " for timestamp " + timestamp)); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/exceptions/InstanceNotFoundException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.platforms.exceptions; 2 | 3 | import org.hesperides.core.domain.exceptions.NotFoundException; 4 | import org.hesperides.core.domain.modules.entities.Module; 5 | import org.hesperides.core.domain.platforms.entities.Platform; 6 | 7 | public class InstanceNotFoundException extends NotFoundException { 8 | public InstanceNotFoundException(Platform.Key platformKey, Module.Key moduleKey, String modulePath, String instanceName) { 9 | super("Could not find instance " + instanceName + " for module " + moduleKey.getNamespaceWithoutPrefix() + " with path " + modulePath + " in platform " + platformKey.getApplicationName() + "-" + platformKey.getPlatformName()); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/exceptions/InvalidDiffSourceException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.platforms.exceptions; 2 | 3 | public class InvalidDiffSourceException extends IllegalArgumentException { 4 | public InvalidDiffSourceException(String msg) { 5 | super(msg); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/exceptions/InvalidPropertyValorisationException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.domain.platforms.exceptions; 22 | 23 | public class InvalidPropertyValorisationException extends IllegalArgumentException { 24 | 25 | public InvalidPropertyValorisationException(String message) { 26 | super(message); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/exceptions/PlatformNotFoundException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.platforms.exceptions; 2 | 3 | import org.hesperides.core.domain.exceptions.NotFoundException; 4 | import org.hesperides.core.domain.platforms.entities.Platform; 5 | 6 | public class PlatformNotFoundException extends NotFoundException { 7 | public PlatformNotFoundException(Platform.Key platformKey) { 8 | super("Could not find platform info for " + platformKey.getApplicationName() + "-" + platformKey.getPlatformName()); 9 | } 10 | 11 | public PlatformNotFoundException(String platformId) { 12 | super("Could not find platform info for " + platformId); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/exceptions/PropertyPatternNotMatchedException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.platforms.exceptions; 2 | 3 | public class PropertyPatternNotMatchedException extends InvalidPropertyValorisationException { 4 | 5 | public PropertyPatternNotMatchedException(String propertyName, String pattern) { 6 | super(String.format("The value of the property \"%s\" doesn't match the pattern \"%s\"", propertyName, pattern)); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/exceptions/RequiredPropertyNotValorisedException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.platforms.exceptions; 2 | 3 | public class RequiredPropertyNotValorisedException extends InvalidPropertyValorisationException { 4 | 5 | public RequiredPropertyNotValorisedException(String propertyName) { 6 | super(String.format("The value of property %s is required", propertyName)); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/exceptions/UnreplayablePlatformEventsException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.platforms.exceptions; 2 | 3 | import org.hesperides.core.domain.exceptions.NotFoundException; 4 | 5 | public class UnreplayablePlatformEventsException extends NotFoundException { 6 | public UnreplayablePlatformEventsException(Long timestamp, Throwable throwable) { 7 | super("Could not replay platform events" + (timestamp == null ? "" : " for timestamp " + timestamp) + ": " + throwable.getMessage()); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/queries/views/ModulePlatformView.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.platforms.queries.views; 2 | 3 | import lombok.Value; 4 | import org.hesperides.core.domain.platforms.entities.Platform; 5 | 6 | @Value 7 | public class ModulePlatformView { 8 | 9 | String applicationName; 10 | String platformName; 11 | 12 | public String toString() { 13 | return new Platform.Key(applicationName, platformName).toString(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/queries/views/SearchApplicationResultView.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.platforms.queries.views; 2 | 3 | import lombok.Value; 4 | 5 | @Value 6 | public class SearchApplicationResultView { 7 | String applicationName; 8 | } 9 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/queries/views/SearchPlatformResultView.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.platforms.queries.views; 2 | 3 | import lombok.Value; 4 | 5 | @Value 6 | public class SearchPlatformResultView { 7 | String platformName; 8 | } 9 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/queries/views/properties/PlatformPropertiesView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.domain.platforms.queries.views.properties; 22 | 23 | import lombok.Value; 24 | 25 | import java.util.List; 26 | 27 | @Value 28 | public class PlatformPropertiesView { 29 | 30 | String applicationName; 31 | String platformName; 32 | boolean isProductionPlatform; 33 | List deployedModules; 34 | 35 | @Value 36 | public static class DeployedModule { 37 | String propertiesPath; 38 | boolean isArchivedModule; 39 | List properties; 40 | } 41 | 42 | @Value 43 | public static class Property { 44 | String name; 45 | String value; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/platforms/queries/views/properties/PropertySearchResultView.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.platforms.queries.views.properties; 2 | 3 | import lombok.Value; 4 | import org.hesperides.core.domain.modules.entities.Module; 5 | 6 | import java.util.Map; 7 | import java.util.Set; 8 | 9 | import static java.util.Collections.emptySet; 10 | 11 | @Value 12 | public class PropertySearchResultView { 13 | String propertyName; 14 | String propertyValue; 15 | String applicationName; 16 | String platformName; 17 | boolean isProductionPlatform; 18 | String propertiesPath; 19 | 20 | public PropertySearchResultView hideProductionPasswordOrExcludeIfSearchedByValue( 21 | Map> passwordsByModule, 22 | boolean isSearchByValue) { 23 | 24 | Module.Key moduleKey = Module.Key.fromPropertiesPath(propertiesPath); 25 | Set modulePasswords = passwordsByModule.getOrDefault(moduleKey, emptySet()); 26 | boolean isProductionPassword = isProductionPlatform && modulePasswords.contains(propertyName); 27 | 28 | String filteredPropertyValue = isProductionPassword ? "******" : propertyValue; 29 | boolean excludeProperty = isProductionPassword && isSearchByValue; 30 | 31 | return excludeProperty ? null : new PropertySearchResultView( 32 | propertyName, 33 | filteredPropertyValue, 34 | applicationName, 35 | platformName, 36 | isProductionPlatform, 37 | propertiesPath); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/security/UserRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.domain.security; 22 | 23 | import org.axonframework.queryhandling.QueryHandler; 24 | import org.hesperides.core.domain.security.entities.User; 25 | import org.hesperides.core.domain.security.queries.views.DirectoryGroupsView; 26 | 27 | import java.util.Optional; 28 | 29 | public interface UserRepository { 30 | 31 | /*** QUERY HANDLERS ***/ 32 | 33 | @QueryHandler 34 | Optional onGetUserQuery(GetUserQuery query); 35 | 36 | @QueryHandler 37 | DirectoryGroupsView onResolveDirectoryGroupCNsQuery(ResolveDirectoryGroupCNsQuery query); 38 | } 39 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/security/commands/ApplicationDirectoryGroupsCommands.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.security.commands; 2 | 3 | import org.axonframework.commandhandling.gateway.CommandGateway; 4 | import org.hesperides.core.domain.security.CreateApplicationDirectoryGroupsCommand; 5 | import org.hesperides.core.domain.security.UpdateApplicationDirectoryGroupsCommand; 6 | import org.hesperides.core.domain.security.entities.ApplicationDirectoryGroups; 7 | import org.hesperides.core.domain.security.entities.User; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Component; 10 | 11 | @Component 12 | public class ApplicationDirectoryGroupsCommands { 13 | 14 | private final CommandGateway commandGateway; 15 | 16 | @Autowired 17 | public ApplicationDirectoryGroupsCommands(CommandGateway commandGateway) { 18 | this.commandGateway = commandGateway; 19 | } 20 | 21 | public void createApplicationDirectoryGroups(ApplicationDirectoryGroups applicationDirectoryGroups, User user) { 22 | commandGateway.sendAndWait(new CreateApplicationDirectoryGroupsCommand(applicationDirectoryGroups, user)); 23 | } 24 | 25 | public void updateApplicationDirectoryGroups(String id, ApplicationDirectoryGroups applicationDirectoryGroups, User user) { 26 | commandGateway.sendAndWait(new UpdateApplicationDirectoryGroupsCommand(id, applicationDirectoryGroups, user)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/security/entities/ApplicationDirectoryGroups.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.domain.security.entities; 22 | 23 | import lombok.Value; 24 | 25 | import java.util.List; 26 | 27 | @Value 28 | public class ApplicationDirectoryGroups { 29 | String applicationName; 30 | List directoryGroupDNs; 31 | } 32 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/security/entities/springauthorities/ApplicationProdRole.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.domain.security.entities.springauthorities; 22 | 23 | import org.springframework.security.core.GrantedAuthority; 24 | 25 | public class ApplicationProdRole implements GrantedAuthority { 26 | 27 | public static final String PROD_USER_SUFFIX = "_PROD_USER"; 28 | 29 | private final String applicationName; 30 | 31 | public ApplicationProdRole(String applicationName) { 32 | this.applicationName = applicationName + PROD_USER_SUFFIX; 33 | } 34 | 35 | @Override 36 | public String getAuthority() { 37 | return applicationName; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/security/entities/springauthorities/GlobalRole.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.domain.security.entities.springauthorities; 22 | 23 | import org.springframework.security.core.GrantedAuthority; 24 | 25 | public class GlobalRole implements GrantedAuthority { 26 | 27 | public static final String IS_PROD = "GLOBAL_IS_PROD"; 28 | public static final String IS_TECH = "GLOBAL_IS_TECH"; 29 | 30 | private final String authority; 31 | 32 | public GlobalRole(String authority) { 33 | this.authority = authority; 34 | } 35 | 36 | @Override 37 | public String getAuthority() { 38 | return authority; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/security/exceptions/CreateDirectoryGroupsForbiddenException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.domain.security.exceptions; 22 | 23 | import org.hesperides.core.domain.exceptions.ForbiddenOperationException; 24 | 25 | public class CreateDirectoryGroupsForbiddenException extends ForbiddenOperationException { 26 | public CreateDirectoryGroupsForbiddenException(String applicationName) { 27 | super("You're not allowed to create the directory groups for the application " + applicationName); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/security/exceptions/UpdateDirectoryGroupsForbiddenException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.domain.security.exceptions; 22 | 23 | import org.hesperides.core.domain.exceptions.ForbiddenOperationException; 24 | 25 | public class UpdateDirectoryGroupsForbiddenException extends ForbiddenOperationException { 26 | public UpdateDirectoryGroupsForbiddenException(String applicationName) { 27 | super("You're not allowed to update the directory groups for the application " + applicationName); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/security/exceptions/UserNotFoundException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.security.exceptions; 2 | 3 | import org.hesperides.core.domain.exceptions.NotFoundException; 4 | 5 | public class UserNotFoundException extends NotFoundException { 6 | public UserNotFoundException(String username) { 7 | super("Could not find user with name " + username); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/security/queries/UserQueries.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.security.queries; 2 | 3 | import org.axonframework.queryhandling.QueryGateway; 4 | import org.hesperides.commons.axon.AxonQueries; 5 | import org.hesperides.core.domain.security.GetUserQuery; 6 | import org.hesperides.core.domain.security.entities.User; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.Optional; 10 | 11 | @Component 12 | public class UserQueries extends AxonQueries { 13 | protected UserQueries(QueryGateway queryGateway) { 14 | super(queryGateway); 15 | } 16 | 17 | public Optional getOptionalUser(String username) { 18 | return querySyncOptional(new GetUserQuery(username), User.class); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/security/queries/views/DirectoryGroupsView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.domain.security.queries.views; 22 | 23 | import lombok.Value; 24 | import org.springframework.util.CollectionUtils; 25 | 26 | import java.util.List; 27 | 28 | import static java.util.Collections.emptyList; 29 | 30 | @Value 31 | public class DirectoryGroupsView { 32 | List unresolvedDirectoryGroupCNs; 33 | List ambiguousDirectoryGroupCNs; 34 | List directoryGroupDNs; 35 | 36 | public static DirectoryGroupsView allUnresolved(List unresolvedDirectoryGroupCNs) { 37 | return new DirectoryGroupsView(unresolvedDirectoryGroupCNs, emptyList(), emptyList()); 38 | } 39 | 40 | public boolean hasUnresolvedOrAmbiguousCNs() { 41 | return !CollectionUtils.isEmpty(unresolvedDirectoryGroupCNs) || 42 | !CollectionUtils.isEmpty(ambiguousDirectoryGroupCNs); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/technos/exception/DuplicateTechnoException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.technos.exception; 2 | 3 | import org.hesperides.core.domain.exceptions.DuplicateException; 4 | import org.hesperides.core.domain.templatecontainers.entities.TemplateContainer; 5 | 6 | public class DuplicateTechnoException extends DuplicateException { 7 | public DuplicateTechnoException(TemplateContainer.Key technoKey) { 8 | super("could not create a techno with key: " + technoKey.getNamespaceWithoutPrefix() + " as it already exists"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/technos/exception/TechnoNotFoundException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.domain.technos.exception; 22 | 23 | import org.hesperides.core.domain.exceptions.NotFoundException; 24 | import org.hesperides.core.domain.templatecontainers.entities.TemplateContainer; 25 | 26 | public class TechnoNotFoundException extends NotFoundException { 27 | public TechnoNotFoundException(TemplateContainer.Key key) { 28 | super("Could not find techno info for " + key.getNamespaceWithoutPrefix()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/technos/exception/UndeletableTechnoInUseException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.technos.exception; 2 | 3 | import org.hesperides.core.domain.exceptions.DuplicateException; 4 | import org.hesperides.core.domain.templatecontainers.entities.TemplateContainer; 5 | import org.hesperides.core.domain.templatecontainers.queries.TemplateContainerKeyView; 6 | 7 | import java.util.List; 8 | import java.util.stream.Collectors; 9 | 10 | public class UndeletableTechnoInUseException extends DuplicateException { 11 | public UndeletableTechnoInUseException(TemplateContainer.Key technoKey, List technoModulesViews) { 12 | super("Techno " + technoKey.getNamespaceWithoutPrefix() + " cannot be deleted as it is used by: " 13 | + technoModulesViews.stream().map(TemplateContainerKeyView::toString).collect(Collectors.joining(" - "))); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/templatecontainers/entities/IterableProperty.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.templatecontainers.entities; 2 | 3 | import com.github.mustachejava.Code; 4 | import com.github.mustachejava.codes.IterableCode; 5 | import com.github.mustachejava.codes.ValueCode; 6 | import lombok.EqualsAndHashCode; 7 | import lombok.Value; 8 | 9 | import java.util.ArrayList; 10 | import java.util.HashSet; 11 | import java.util.List; 12 | import java.util.Set; 13 | 14 | @Value 15 | @EqualsAndHashCode(callSuper = true) 16 | public class IterableProperty extends AbstractProperty { 17 | 18 | List properties; 19 | 20 | public IterableProperty(String name, List properties) { 21 | super(name); 22 | this.properties = properties; 23 | } 24 | 25 | /** 26 | * Méthode récursive permettant d'extraire les propriétés et les propriétés itérables contenues dans une propriété itérable. 27 | * 28 | * @param code 29 | * @return 30 | */ 31 | public static IterableProperty extractIterablePropertyFromMustacheCode(IterableCode code) { 32 | String name = code.getName(); 33 | Set properties = new HashSet<>(); 34 | 35 | for (Code childCode : code.getCodes()) { 36 | if (childCode instanceof ValueCode) { 37 | properties.add(Property.extractProperty(childCode.getName())); 38 | } else if (childCode instanceof IterableCode) { 39 | properties.add(extractIterablePropertyFromMustacheCode((IterableCode) childCode)); 40 | } 41 | } 42 | return new IterableProperty(name, new ArrayList<>(properties)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/templatecontainers/exceptions/InvalidTemplateException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.templatecontainers.exceptions; 2 | 3 | public class InvalidTemplateException extends IllegalArgumentException { 4 | 5 | public InvalidTemplateException(String templateKey, String filename, String fieldName, Throwable cause) { 6 | super(String.format("Invalid field \"%s\" in template %s for module %s : %s", 7 | fieldName, filename, templateKey, cause.getMessage()), cause); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/templatecontainers/exceptions/PropertyWithSameNameAsIterablePropertyException.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.templatecontainers.exceptions; 2 | 3 | public class PropertyWithSameNameAsIterablePropertyException extends IllegalArgumentException { 4 | public PropertyWithSameNameAsIterablePropertyException(String templateKey, String filename, String propertyName) { 5 | super(String.format("Can't use a property with the same name as the Iterable Property \"%s\" in template %s for module %s", 6 | propertyName, filename, templateKey)); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/templatecontainers/queries/AbstractPropertyView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.domain.templatecontainers.queries; 22 | 23 | import lombok.Value; 24 | import lombok.experimental.NonFinal; 25 | 26 | import java.util.List; 27 | import java.util.function.Function; 28 | import java.util.stream.Stream; 29 | 30 | @Value 31 | @NonFinal 32 | public abstract class AbstractPropertyView { 33 | 34 | String name; 35 | 36 | protected abstract Stream flattenProperties(); 37 | 38 | /** 39 | * Retourne un stream contenant toutes les propriétés simples, 40 | * y compris celles des propriétés itérables. 41 | */ 42 | public static Stream getAllSimpleProperties(List abstractProperties) { 43 | return abstractProperties.stream() 44 | .map(AbstractPropertyView::flattenProperties) 45 | .flatMap(Function.identity()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/templatecontainers/queries/IterablePropertyView.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.templatecontainers.queries; 2 | 3 | import lombok.EqualsAndHashCode; 4 | import lombok.Value; 5 | 6 | import java.util.Collections; 7 | import java.util.List; 8 | import java.util.Optional; 9 | import java.util.function.Function; 10 | import java.util.stream.Stream; 11 | 12 | @Value 13 | @EqualsAndHashCode(callSuper = true) 14 | public class IterablePropertyView extends AbstractPropertyView { 15 | 16 | List properties; 17 | 18 | public IterablePropertyView(String name, List properties) { 19 | super(name); 20 | this.properties = properties; 21 | } 22 | 23 | @Override 24 | protected Stream flattenProperties() { 25 | return Optional.ofNullable(properties) 26 | .orElseGet(Collections::emptyList) 27 | .stream() 28 | .map(AbstractPropertyView::flattenProperties) 29 | .flatMap(Function.identity()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/domain/src/main/java/org/hesperides/core/domain/templatecontainers/queries/TemplateContainerKeyView.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.templatecontainers.queries; 2 | 3 | import lombok.Value; 4 | import org.hesperides.core.domain.technos.entities.Techno; 5 | import org.hesperides.core.domain.templatecontainers.entities.TemplateContainer; 6 | 7 | @Value 8 | public class TemplateContainerKeyView { 9 | 10 | String name; 11 | String version; 12 | Boolean isWorkingCopy; 13 | 14 | @Override 15 | public String toString() { 16 | return name + "/" + version + "/" + TemplateContainer.getVersionType(isWorkingCopy); 17 | } 18 | 19 | public Techno.Key toTechnoKey() { 20 | return new Techno.Key(name, version, TemplateContainer.getVersionType(isWorkingCopy)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /core/domain/src/main/kotlin/org/hesperides/core/domain/events/Events.kt: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.events 2 | 3 | import org.hesperides.core.domain.security.UserEvent 4 | 5 | data class GetLastToFirstEventsQuery(val aggregateIdentifier: String, val eventTypes: Array>, val page: Int, val size: Int) 6 | data class GetLastToFirstPlatformModulePropertiesUpdatedEvents(val aggregateIdentifier: String, val propertiesPath: String, val page: Int, val size: Int) 7 | -------------------------------------------------------------------------------- /core/domain/src/main/kotlin/org/hesperides/core/domain/security/Authorization.kt: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.security 2 | 3 | import org.axonframework.modelling.command.TargetAggregateIdentifier 4 | import org.hesperides.core.domain.security.entities.ApplicationDirectoryGroups 5 | import org.hesperides.core.domain.security.entities.User 6 | 7 | // Command 8 | 9 | data class CreateApplicationDirectoryGroupsCommand(val applicationDirectoryGroups: ApplicationDirectoryGroups, val user: User) 10 | data class UpdateApplicationDirectoryGroupsCommand(@TargetAggregateIdentifier val id: String, val applicationDirectoryGroups: ApplicationDirectoryGroups, val user: User) 11 | 12 | // Event 13 | 14 | data class ApplicationDirectoryGroupsCreatedEvent(val id: String, val applicationDirectoryGroups: ApplicationDirectoryGroups, override val user: String) : UserEvent(user) 15 | data class ApplicationDirectoryGroupsUpdatedEvent(val id: String, val applicationDirectoryGroups: ApplicationDirectoryGroups, override val user: String) : UserEvent(user) 16 | 17 | // Queries 18 | 19 | data class GetApplicationDirectoryGroupsQuery(val applicationName: String) 20 | data class ResolveDirectoryGroupCNsQuery(val directoryGroupCNs: List) 21 | -------------------------------------------------------------------------------- /core/domain/src/main/kotlin/org/hesperides/core/domain/security/User.kt: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.domain.security 2 | 3 | // Tous les événements de l'application sont déclenchés par un utilisateur. 4 | // Rendre cette classe abstraite pose des problèmes de désérialisation de 5 | // la classe `org.hesperides.core.domain.events.queries.EventView` par Axon. 6 | // On marque le champ user `@Transient` pour éviter des erreurs de champ 7 | // dupliqué lors de la désérialisation via Gson des événements. 8 | open class UserEvent(@Transient open val user: String) 9 | 10 | // Command 11 | 12 | // Event 13 | 14 | // Queries 15 | 16 | data class GetUserQuery(val username: String) 17 | -------------------------------------------------------------------------------- /core/domain/src/test/java/org/hesperides/core/domain/files/InstanceFileViewTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.domain.files; 22 | 23 | import org.junit.Test; 24 | 25 | import static org.hesperides.core.domain.files.InstanceFileView.buildLegacyFileLocation; 26 | import static org.junit.Assert.assertEquals; 27 | 28 | public class InstanceFileViewTest { 29 | 30 | @Test 31 | public void testBuildLegacyFileLocation() { 32 | assertEquals("location/filename", buildLegacyFileLocation("location", "filename")); 33 | assertEquals("location//filename", buildLegacyFileLocation("location/", "filename")); 34 | assertEquals("location//filename", buildLegacyFileLocation("location", "/filename")); 35 | assertEquals("location///filename", buildLegacyFileLocation("location/", "/filename")); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /core/domain/src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /core/infrastructure/src/main/java/org/hesperides/core/infrastructure/MinimalPlatformRepository.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.infrastructure; 2 | 3 | import org.hesperides.core.infrastructure.mongo.platforms.documents.PlatformDocument; 4 | 5 | import java.util.Optional; 6 | 7 | /* 8 | * Cette interface minimale est un sous-ensemble de MongoRepository. 9 | * Elle permet d'identifier clairement quelles méthodes sont nécessaires aux @EventHandler 10 | * dans MongoPlatformProjectionRepository. 11 | */ 12 | public interface MinimalPlatformRepository { 13 | 14 | PlatformDocument save(PlatformDocument platformDoc); 15 | 16 | Optional findById(String id); 17 | 18 | void deleteById(String id); 19 | } 20 | -------------------------------------------------------------------------------- /core/infrastructure/src/main/java/org/hesperides/core/infrastructure/axon/SecureXStreamSerializer.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.infrastructure.axon; 2 | 3 | import com.thoughtworks.xstream.XStream; 4 | import org.axonframework.serialization.xml.XStreamSerializer; 5 | 6 | public class SecureXStreamSerializer { 7 | 8 | private static XStreamSerializer _instance; 9 | 10 | public static XStreamSerializer get() { 11 | if (_instance == null) { 12 | _instance = secureXStreamSerializer(); 13 | } 14 | return _instance; 15 | } 16 | 17 | private static XStreamSerializer secureXStreamSerializer() { 18 | XStream xStream = new XStream(); 19 | xStream.setClassLoader(SecureXStreamSerializer.class.getClassLoader()); 20 | xStream.allowTypesByWildcard(new String[]{ 21 | "org.axonframework.**", 22 | "org.hesperides.**" 23 | }); 24 | return XStreamSerializer.builder().xStream(xStream).build(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core/infrastructure/src/main/java/org/hesperides/core/infrastructure/mongo/Collections.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.infrastructure.mongo; 2 | 3 | public class Collections { 4 | public static final String DOMAINEVENTS = "domainevents"; 5 | public static final String MODULE = "module"; 6 | public static final String PLATFORM = "platform"; 7 | public static final String TECHNO = "techno"; 8 | public static final String APPLICATION_DIRECTORY_GROUPS = "application_directory_groups"; 9 | } 10 | -------------------------------------------------------------------------------- /core/infrastructure/src/main/java/org/hesperides/core/infrastructure/mongo/events/EventDocument.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.infrastructure.mongo.events; 2 | 3 | import com.thoughtworks.xstream.XStream; 4 | import lombok.Data; 5 | import org.hesperides.core.domain.events.queries.EventView; 6 | import org.hesperides.core.domain.security.UserEvent; 7 | import org.springframework.data.mongodb.core.index.Indexed; 8 | import org.springframework.data.mongodb.core.mapping.Document; 9 | 10 | import java.time.Instant; 11 | 12 | import static org.hesperides.core.infrastructure.mongo.Collections.DOMAINEVENTS; 13 | 14 | @Data 15 | @Document(collection = DOMAINEVENTS) 16 | public class EventDocument { 17 | 18 | @Indexed 19 | private String aggregateIdentifier; 20 | private String type; 21 | private int sequenceNumber; 22 | private String serializedPayload; 23 | private String timestamp; 24 | private String payloadType; 25 | private String serializedMetadata; 26 | private String eventIdentifier; 27 | 28 | public EventView toEventView() { 29 | XStream xStream = new XStream(); 30 | // Afin d'éviter le message "Security framework of XStream 31 | // not initialized, XStream is probably vulnerable" 32 | // cf. https://stackoverflow.com/questions/44698296/security-framework-of-xstream-not-initialized-xstream-is-probably-vulnerable 33 | xStream.allowTypesByWildcard(new String[]{ 34 | "org.hesperides.core.domain.**" 35 | }); 36 | 37 | return new EventView( 38 | payloadType, 39 | (UserEvent) xStream.fromXML(serializedPayload), 40 | Instant.parse(timestamp) 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /core/infrastructure/src/main/java/org/hesperides/core/infrastructure/mongo/events/MongoEventRepository.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.infrastructure.mongo.events; 2 | 3 | import org.springframework.data.domain.Pageable; 4 | import org.springframework.data.mongodb.repository.MongoRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.List; 8 | 9 | @Repository 10 | public interface MongoEventRepository extends MongoRepository { 11 | 12 | List findAllByAggregateIdentifierOrderByTimestampDesc(String aggregateIdentifier, Pageable pageable); 13 | 14 | List findAllByAggregateIdentifierAndPayloadTypeInOrderByTimestampDesc( 15 | String aggregateIdentifier, List payloadTypes, Pageable pageable); 16 | 17 | void deleteAllByAggregateIdentifier(String aggregateIdentifier); 18 | 19 | List findAllByAggregateIdentifierAndPayloadTypeAndSerializedPayloadLikeOrderByTimestampDesc( 20 | String aggregateIdentifier, String payloadType, String serializedPayload, Pageable pageable); 21 | } 22 | -------------------------------------------------------------------------------- /core/infrastructure/src/main/java/org/hesperides/core/infrastructure/mongo/platforms/documents/PlatformKeyDocument.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.infrastructure.mongo.platforms.documents; 22 | 23 | import lombok.Data; 24 | import lombok.NoArgsConstructor; 25 | import org.hesperides.core.domain.platforms.entities.Platform; 26 | import org.springframework.data.mongodb.core.mapping.Document; 27 | 28 | import java.io.Serializable; 29 | 30 | @Data 31 | @Document 32 | @NoArgsConstructor 33 | public class PlatformKeyDocument implements Serializable { 34 | 35 | private String applicationName; 36 | private String platformName; 37 | 38 | public PlatformKeyDocument(Platform.Key platformKey) { 39 | this.applicationName = platformKey.getApplicationName(); 40 | this.platformName = platformKey.getPlatformName(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /core/infrastructure/src/main/java/org/hesperides/core/infrastructure/security/LdapCNSearcher.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.infrastructure.security; 2 | 3 | import org.springframework.ldap.core.DirContextOperations; 4 | 5 | /* 6 | * Cette interface permet de "passer par un attribut" pour que le cache fonctionne, 7 | * cf. https://stackoverflow.com/a/48867068/636849 8 | */ 9 | public interface LdapCNSearcher { 10 | 11 | DirContextOperations searchCN(String username, String password); 12 | } 13 | -------------------------------------------------------------------------------- /core/infrastructure/src/main/java/org/hesperides/core/infrastructure/security/groups/ParentGroupsDNRetriever.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.infrastructure.security.groups; 2 | 3 | import java.util.HashSet; 4 | 5 | public interface ParentGroupsDNRetriever { 6 | 7 | HashSet retrieveParentGroupDNs(String dn); 8 | } 9 | -------------------------------------------------------------------------------- /core/infrastructure/src/main/resources/db/changelog/db.changelog-hesperides-1.0.yaml: -------------------------------------------------------------------------------- 1 | databaseChangeLog: 2 | - changeSet: 3 | id: 1 4 | author: victorsalaun 5 | changes: 6 | - createTable: 7 | tableName: module 8 | columns: 9 | - column: 10 | name: name 11 | type: varchar(255) 12 | constraints: 13 | nullable: false 14 | - column: 15 | name: version 16 | type: varchar(255) 17 | constraints: 18 | nullable: false 19 | - column: 20 | name: version_type 21 | type: integer 22 | constraints: 23 | nullable: false 24 | - column: 25 | name: version_id 26 | type: bigint 27 | - addPrimaryKey: 28 | columnNames: name, version, version_type 29 | constraintName: pk_module 30 | schemaName: public 31 | tableName: module 32 | -------------------------------------------------------------------------------- /core/infrastructure/src/main/resources/db/changelog/db.changelog-master.yaml: -------------------------------------------------------------------------------- 1 | databaseChangeLog: 2 | 3 | # 4 | # Axon Framework changes 5 | # 6 | - include: 7 | file: classpath:db/changelog/db.changelog-axon-3.2.yaml 8 | 9 | # 10 | # Hesperides changes 11 | # 12 | - include: 13 | file: classpath:db/changelog/db.changelog-hesperides-1.0.yaml -------------------------------------------------------------------------------- /core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | org.hesperides 6 | hesperides 7 | 4.3-SNAPSHOT 8 | 9 | 10 | 4.0.0 11 | core 12 | pom 13 | 14 | 15 | presentation 16 | application 17 | domain 18 | infrastructure 19 | 20 | 21 | -------------------------------------------------------------------------------- /core/presentation/src/main/java/org/hesperides/core/presentation/io/OnlyPrintableCharacters.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.presentation.io; 2 | 3 | 4 | import javax.validation.Constraint; 5 | import javax.validation.Payload; 6 | import javax.validation.ReportAsSingleViolation; 7 | import javax.validation.constraints.NotEmpty; 8 | import javax.validation.constraintvalidation.SupportedValidationTarget; 9 | import javax.validation.constraintvalidation.ValidationTarget; 10 | import java.lang.annotation.Documented; 11 | import java.lang.annotation.Retention; 12 | import java.lang.annotation.Target; 13 | 14 | import static java.lang.annotation.ElementType.FIELD; 15 | import static java.lang.annotation.ElementType.METHOD; 16 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 17 | 18 | /** 19 | * Vérifie que la propriété annotée ne contient pas de caractère invalide (< 0x20). 20 | * Cette annotation hérite de @NotEmpty qui hérite elle-même de @NotNull. 21 | * La propriété doit donc est renseignée et valide. 22 | * 23 | * @since issue #232 24 | */ 25 | @Documented 26 | @Constraint(validatedBy = {OnlyPrintableCharactersValidator.class}) 27 | @SupportedValidationTarget(ValidationTarget.ANNOTATED_ELEMENT) 28 | @Target({METHOD, FIELD}) 29 | @Retention(RUNTIME) 30 | @ReportAsSingleViolation 31 | @NotEmpty 32 | public @interface OnlyPrintableCharacters { 33 | /** 34 | * @return validation target, used in error message if value is found invalid 35 | */ 36 | String subject(); 37 | 38 | String message() default "{subject} contains an invalid character"; 39 | 40 | Class[] groups() default {}; 41 | 42 | Class[] payload() default {}; 43 | } 44 | -------------------------------------------------------------------------------- /core/presentation/src/main/java/org/hesperides/core/presentation/io/OnlyPrintableCharactersValidator.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.presentation.io; 2 | 3 | import javax.validation.ConstraintValidator; 4 | import javax.validation.ConstraintValidatorContext; 5 | 6 | public class OnlyPrintableCharactersValidator implements ConstraintValidator { 7 | @Override 8 | public void initialize(OnlyPrintableCharacters constraintAnnotation) { 9 | // no-op 10 | } 11 | 12 | @Override 13 | public boolean isValid(String value, ConstraintValidatorContext context) { 14 | final int len = value == null ? 0 : value.length(); 15 | for (int i = 0; i < len; i++) { 16 | if (value.charAt(i) < 0x21) { 17 | return false; 18 | } 19 | } 20 | // so null and empty strings are considered VALID by this validation, as recommended 21 | // (http://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#section-constraint-validator) 22 | return true; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/presentation/src/main/java/org/hesperides/core/presentation/io/events/ModuleCreatedEventIO.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.presentation.io.events; 2 | 3 | import lombok.Value; 4 | import org.hesperides.core.domain.modules.ModuleCreatedEvent; 5 | import org.hesperides.core.domain.modules.entities.Module; 6 | 7 | @Value 8 | public class ModuleCreatedEventIO { 9 | private Module moduleCreated; // only field used by legacy front is .name 10 | 11 | public ModuleCreatedEventIO(ModuleCreatedEvent moduleCreatedEvent) { 12 | this.moduleCreated = moduleCreatedEvent.getModule(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /core/presentation/src/main/java/org/hesperides/core/presentation/io/events/TemplateCreatedEventIO.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.presentation.io.events; 2 | 3 | import lombok.Value; 4 | import org.hesperides.core.domain.modules.TemplateCreatedEvent; 5 | import org.hesperides.core.domain.templatecontainers.entities.Template; 6 | 7 | @Value 8 | public class TemplateCreatedEventIO { 9 | private String moduleName; 10 | private String moduleVersion; 11 | private Template created; // only field used by legacy front is .name 12 | 13 | public TemplateCreatedEventIO(TemplateCreatedEvent templateCreatedEvent) { 14 | this.created = templateCreatedEvent.getTemplate(); 15 | this.moduleName = this.created.getTemplateContainerKey().getName(); 16 | this.moduleVersion = this.created.getTemplateContainerKey().getVersion(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/presentation/src/main/java/org/hesperides/core/presentation/io/events/TemplateUpdatedEventIO.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.presentation.io.events; 2 | 3 | import lombok.Value; 4 | import org.hesperides.core.domain.modules.TemplateUpdatedEvent; 5 | import org.hesperides.core.domain.templatecontainers.entities.Template; 6 | 7 | @Value 8 | public class TemplateUpdatedEventIO { 9 | private String moduleName; 10 | private String moduleVersion; 11 | private Template updated; // only field used by legacy front is .name 12 | 13 | public TemplateUpdatedEventIO(TemplateUpdatedEvent templateUpdatedEvent) { 14 | this.updated = templateUpdatedEvent.getTemplate(); 15 | this.moduleName = this.updated.getTemplateContainerKey().getName(); 16 | this.moduleVersion = this.updated.getTemplateContainerKey().getVersion(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/presentation/src/main/java/org/hesperides/core/presentation/io/platforms/AllApplicationsDetailOutput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.presentation.io.platforms; 22 | 23 | import lombok.Value; 24 | 25 | import java.util.List; 26 | 27 | @Value 28 | public class AllApplicationsDetailOutput { 29 | String generated; 30 | List applications; 31 | } 32 | -------------------------------------------------------------------------------- /core/presentation/src/main/java/org/hesperides/core/presentation/io/platforms/ApplicationDirectoryGroupsInput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.presentation.io.platforms; 22 | 23 | import lombok.Value; 24 | 25 | import javax.validation.constraints.NotNull; 26 | import java.util.List; 27 | import java.util.Map; 28 | 29 | @Value 30 | public class ApplicationDirectoryGroupsInput { 31 | // La clef est une liste de CNs - Ex: "ABC_PROD_USER": ["GG_XX", "GG_ZZ"] 32 | @NotNull 33 | Map> directoryGroups; 34 | } 35 | -------------------------------------------------------------------------------- /core/presentation/src/main/java/org/hesperides/core/presentation/io/platforms/SearchResultOutput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.presentation.io.platforms; 22 | 23 | import lombok.Value; 24 | import org.hesperides.core.domain.platforms.queries.views.SearchApplicationResultView; 25 | import org.hesperides.core.domain.platforms.queries.views.SearchPlatformResultView; 26 | 27 | @Value 28 | public class SearchResultOutput { 29 | 30 | String name; 31 | 32 | public SearchResultOutput(SearchPlatformResultView view) { 33 | this.name = view.getPlatformName(); 34 | } 35 | 36 | public SearchResultOutput(SearchApplicationResultView view) { 37 | this.name = view.getApplicationName(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /core/presentation/src/main/java/org/hesperides/core/presentation/io/platforms/properties/FlatPasswordsOutput.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.presentation.io.platforms.properties; 2 | 3 | import lombok.Value; 4 | import org.hesperides.core.domain.platforms.queries.views.properties.PlatformPropertiesView; 5 | 6 | import java.util.List; 7 | 8 | import static java.util.stream.Collectors.toList; 9 | 10 | @Value 11 | public class FlatPasswordsOutput { 12 | String passwordName; 13 | String passwordValue; 14 | String applicationName; 15 | String platformName; 16 | boolean isProductionPlatform; 17 | String propertiesPath; 18 | boolean isArchivedModule; 19 | 20 | public static List fromViews(List applicationsPasswords) { 21 | return applicationsPasswords.stream() 22 | .flatMap(platform -> platform.getDeployedModules().stream() 23 | .flatMap(deployedModule -> deployedModule.getProperties().stream() 24 | .map(password -> new FlatPasswordsOutput( 25 | password.getName(), 26 | password.getValue(), 27 | platform.getApplicationName(), 28 | platform.getPlatformName(), 29 | platform.isProductionPlatform(), 30 | deployedModule.getPropertiesPath(), 31 | deployedModule.isArchivedModule() 32 | )))) 33 | .collect(toList()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /core/presentation/src/main/java/org/hesperides/core/presentation/io/platforms/properties/GlobalPropertyUsageOutput.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.presentation.io.platforms.properties; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import com.google.gson.annotations.SerializedName; 5 | import lombok.Value; 6 | 7 | @Value 8 | public class GlobalPropertyUsageOutput { 9 | 10 | // On conserve `inModel` pour être rétrocompatible mais le nom 11 | // de cette propriété n'est pas pertinent. 12 | boolean inModel; 13 | 14 | // `isRemovedFromTemplate` est fonctionnellement 15 | // l'inverse d'`inModel`, mais plus parlant. 16 | // boolean isRemovedFromTemplate; 17 | 18 | @SerializedName("path") 19 | @JsonProperty("path") 20 | String propertiesPath; 21 | } 22 | -------------------------------------------------------------------------------- /core/presentation/src/main/java/org/hesperides/core/presentation/io/platforms/properties/PropertySearchResultOutput.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.presentation.io.platforms.properties; 2 | 3 | import lombok.Value; 4 | import org.hesperides.core.domain.platforms.queries.views.properties.PropertySearchResultView; 5 | 6 | import java.util.List; 7 | 8 | import static java.util.stream.Collectors.toList; 9 | 10 | @Value 11 | public class PropertySearchResultOutput { 12 | 13 | String propertyName; 14 | String propertyValue; 15 | String applicationName; 16 | String platformName; 17 | String propertiesPath; 18 | 19 | public PropertySearchResultOutput(PropertySearchResultView view) { 20 | propertyName = view.getPropertyName(); 21 | propertyValue = view.getPropertyValue(); 22 | applicationName = view.getApplicationName(); 23 | platformName = view.getPlatformName(); 24 | propertiesPath = view.getPropertiesPath(); 25 | } 26 | 27 | public static List fromViews(List properties) { 28 | return properties.stream().map(PropertySearchResultOutput::new).collect(toList()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core/presentation/src/main/java/org/hesperides/core/presentation/io/platforms/properties/diff/DualDifferingPropertyOutput.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.presentation.io.platforms.properties.diff; 2 | 3 | import lombok.EqualsAndHashCode; 4 | import lombok.Value; 5 | import org.hesperides.core.domain.platforms.entities.properties.diff.SimpleDifferingProperty; 6 | 7 | @Value 8 | @EqualsAndHashCode(callSuper = true) 9 | public class DualDifferingPropertyOutput extends AbstractDifferingPropertyOutput { 10 | 11 | PropertyDiffValueOutput left; 12 | PropertyDiffValueOutput right; 13 | 14 | DualDifferingPropertyOutput(SimpleDifferingProperty simpleDifferingProperty) { 15 | super(simpleDifferingProperty.getName()); 16 | this.left = new PropertyDiffValueOutput(simpleDifferingProperty.getLeft()); 17 | this.right = new PropertyDiffValueOutput(simpleDifferingProperty.getRight()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core/presentation/src/main/java/org/hesperides/core/presentation/io/platforms/properties/diff/IterableDifferingPropertyOutput.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.presentation.io.platforms.properties.diff; 2 | 3 | import lombok.EqualsAndHashCode; 4 | import lombok.Value; 5 | import org.hesperides.core.domain.platforms.entities.properties.diff.IterableDifferingProperty; 6 | import org.hesperides.core.domain.platforms.entities.properties.visitors.IterablePropertyVisitor; 7 | 8 | import java.util.List; 9 | import java.util.stream.Collectors; 10 | 11 | @Value 12 | @EqualsAndHashCode(callSuper = true) 13 | class IterableDifferingPropertyOutput extends AbstractDifferingPropertyOutput { 14 | 15 | List items; 16 | 17 | IterableDifferingPropertyOutput(IterableDifferingProperty iterableDifferingProperty) { 18 | super(iterableDifferingProperty.getName()); 19 | this.items = PropertiesDiffOutput.fromPropertiesDiffs(iterableDifferingProperty.getDifferingItems()); 20 | } 21 | 22 | private IterableDifferingPropertyOutput(String name, List items) { 23 | super(name); 24 | this.items = items; 25 | } 26 | 27 | static IterableDifferingPropertyOutput onlyCommon(IterablePropertyVisitor propertyVisitor) { 28 | return new IterableDifferingPropertyOutput( 29 | propertyVisitor.getName(), 30 | propertyVisitor.getItems().stream() 31 | .map(PropertiesDiffOutput::onlyCommon) 32 | .collect(Collectors.toList())); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core/presentation/src/main/java/org/hesperides/core/presentation/io/platforms/properties/diff/NonDifferingPropertyOutput.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.presentation.io.platforms.properties.diff; 2 | 3 | import lombok.EqualsAndHashCode; 4 | import lombok.Value; 5 | import org.hesperides.core.domain.platforms.entities.properties.visitors.SimplePropertyVisitor; 6 | 7 | @Value 8 | @EqualsAndHashCode(callSuper = true) 9 | class NonDifferingPropertyOutput extends AbstractDifferingPropertyOutput { 10 | 11 | PropertyDiffValueOutput value; 12 | 13 | NonDifferingPropertyOutput(SimplePropertyVisitor propertyVisitor) { 14 | super(propertyVisitor.getName()); 15 | this.value = new PropertyDiffValueOutput(propertyVisitor); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /core/presentation/src/main/java/org/hesperides/core/presentation/io/platforms/properties/diff/PropertyDiffValueOutput.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.presentation.io.platforms.properties.diff; 2 | 3 | import lombok.NonNull; 4 | import lombok.Value; 5 | import org.hesperides.core.domain.platforms.entities.properties.ValuedPropertyTransformation; 6 | import org.hesperides.core.domain.platforms.entities.properties.visitors.SimplePropertyVisitor; 7 | import org.springframework.lang.Nullable; 8 | 9 | @Value 10 | class PropertyDiffValueOutput { 11 | @Nullable 12 | String finalValue; 13 | @Nullable 14 | String defaultValue; 15 | @Nullable 16 | String storedValue; // Correspond à la valeur en base / renseignée dans l'IHM 17 | @NonNull 18 | ValuedPropertyTransformation[] transformations; 19 | 20 | PropertyDiffValueOutput(SimplePropertyVisitor propertyVisitor) { 21 | if (propertyVisitor != null) { 22 | finalValue = propertyVisitor.getValueOrDefault().orElse(null); 23 | defaultValue = propertyVisitor.getDefaultValue().orElse(null); 24 | storedValue = propertyVisitor.getInitialValue(); 25 | transformations = propertyVisitor.getTransformations(); 26 | } else { 27 | finalValue = null; 28 | defaultValue = null; 29 | storedValue = null; 30 | transformations = new ValuedPropertyTransformation[]{}; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /core/presentation/src/main/java/org/hesperides/core/presentation/io/templatecontainers/PartialTemplateIO.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.presentation.io.templatecontainers; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Value; 5 | import org.hesperides.core.domain.templatecontainers.queries.TemplateView; 6 | import org.hesperides.core.presentation.io.OnlyPrintableCharacters; 7 | 8 | @Value 9 | @AllArgsConstructor 10 | public class PartialTemplateIO { 11 | 12 | @OnlyPrintableCharacters(subject = "name") 13 | String name; 14 | String namespace; 15 | @OnlyPrintableCharacters(subject = "filename") 16 | String filename; 17 | @OnlyPrintableCharacters(subject = "location") 18 | String location; 19 | 20 | public PartialTemplateIO(TemplateView templateView) { 21 | this.name = templateView.getName(); 22 | this.namespace = templateView.getNamespace(); 23 | this.filename = templateView.getFilename(); 24 | this.location = templateView.getLocation(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core/presentation/src/main/java/org/hesperides/core/presentation/security/HttpFirewallConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.core.presentation.security; 22 | 23 | import org.springframework.context.annotation.Bean; 24 | import org.springframework.context.annotation.Configuration; 25 | import org.springframework.security.web.firewall.HttpFirewall; 26 | import org.springframework.security.web.firewall.StrictHttpFirewall; 27 | 28 | @Configuration 29 | public class HttpFirewallConfiguration { 30 | 31 | @Bean 32 | public HttpFirewall httpFirewall() { 33 | final StrictHttpFirewall httpFirewall = new StrictHttpFirewall(); 34 | // C'est une faille de sécurité mais le legacy le permet: 35 | httpFirewall.setAllowUrlEncodedPercent(true); 36 | httpFirewall.setAllowUrlEncodedSlash(true); 37 | return httpFirewall; 38 | } 39 | } -------------------------------------------------------------------------------- /core/presentation/src/main/java/org/hesperides/core/presentation/swagger/SpringfoxJsonToGsonAdapter.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.presentation.swagger; 2 | 3 | import com.google.gson.JsonElement; 4 | import com.google.gson.JsonParser; 5 | import com.google.gson.JsonSerializationContext; 6 | import com.google.gson.JsonSerializer; 7 | import springfox.documentation.spring.web.json.Json; 8 | 9 | import java.lang.reflect.Type; 10 | 11 | public class SpringfoxJsonToGsonAdapter implements JsonSerializer { 12 | 13 | @Override 14 | public JsonElement serialize(Json json, Type type, JsonSerializationContext context) { 15 | final JsonParser parser = new JsonParser(); 16 | return parser.parse(json.value()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/presentation/src/test/java/org/hesperides/core/presentation/config/TestAppConfig.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.core.presentation.config; 2 | 3 | import org.springframework.context.annotation.ComponentScan; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 6 | 7 | @Configuration 8 | @ComponentScan({"org.hesperides.core.presentation.controllers", "org.hesperides.core.presentation.swagger"}) 9 | @EnableWebMvc 10 | public class TestAppConfig { 11 | } 12 | -------------------------------------------------------------------------------- /docker/docker-compose-mongo.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | 5 | mongo: 6 | image: "mongo:3.4.14" 7 | ports: 8 | - "27017:27017" 9 | restart: always 10 | networks: 11 | - hesperides-network 12 | 13 | networks: 14 | 15 | hesperides-network: 16 | driver: bridge 17 | -------------------------------------------------------------------------------- /docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | 5 | hesperides: 6 | image: hesperides/hesperides:latest 7 | build: 8 | context: .. 9 | dockerfile: Dockerfile 10 | ports: 11 | - "8080:8080" 12 | environment: 13 | - SPRING_PROFILES_ACTIVE=noldap,fake_mongo 14 | restart: always 15 | networks: 16 | - hesperides-network 17 | 18 | networks: 19 | 20 | hesperides-network: 21 | driver: bridge 22 | -------------------------------------------------------------------------------- /docker_entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -o pipefail -o errexit -o nounset 3 | if [ -z "${MONGO_URI:-}" ]; then 4 | if ! echo "${SPRING_PROFILES_ACTIVE:-}" | grep -qF fake_mongo; then 5 | echo 'Either $MONGO_URI must be defined or $SPRING_PROFILES_ACTIVE must contain "fake_mongo"' >&2 6 | exit 1 7 | fi 8 | else 9 | echo "Creating Hesperides Test collection..." 10 | if ! mongosh $MONGO_URI mongo_test_create_collections.js; then 11 | echo -e 'Not enough permissions to create a collection: connected to a non-PRIMARY node ?\nCheck that $MONGO_URI contains replicaSet=...' >&2 12 | exit 1 13 | fi 14 | echo "Creating Hesperides collections..." 15 | mongosh $MONGO_URI mongo_create_collections.js 16 | fi 17 | # If args were passed to this script, execute them as a command, else do nothing: 18 | exec "${@:-true}" 19 | -------------------------------------------------------------------------------- /documentation/architecture/docker.md: -------------------------------------------------------------------------------- 1 | # Docker 2 | 3 | Hespérides est dockerisée à chaque build via [Travis](https://travis-ci.com/voyages-sncf-technologies/hesperides/) et pushée sur le [hub Docker](https://hub.docker.com/r/hesperides). 4 | Les noms des tags des images docker correspondent aux noms des branches sur GitHub. 5 | 6 | 7 | # Dockerfile 8 | 9 | Pour construire une image docker pour Hespérides nous utilisons un fichier de type `Dockerfile`. 10 | 11 | Ce fichier indique : 12 | - l'image de base : `openjdk:8-jre-alpine` 13 | - nous ajoutons notre jar construit suite au build maven 14 | - la commande pour lancer la jar 15 | - nous exposons les ports d'écoutés par le jar 16 | 17 | 18 | # Docker Compose 19 | 20 | Chaque partenaire externe a son fichier docker-compose dans le dossier `docker` permettant de se lancer en local : 21 | 22 | docker-compose -f [docker-compose-file] up 23 | -------------------------------------------------------------------------------- /documentation/architecture/draw.io/hexagonal.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 7VnLkqIwFP0athYQHrrsth8zi6myqhczs0xDhFQDoUJ8zddPkAAmwRYVR6fsdtHJ4eYSzz03uYkGmKbrVwrz+AcJUWLYZrg2wJNh25Zje/xfiWwqxPesCogoDoVRC7zhP0iApkAXOESFZMgISRjOZTAgWYYCJmGQUrKSzeYkkd+awwhpwFsAEx39iUMWV+jYNFv8G8JRzJQH7zD4iChZZOJ1hg3m27/qcQprV8K+iGFIVjsQeDbAlBLCqla6nqKkpLZmrRr3sudpM22KMtZrgFONWMJkIb76jBpTYDxMCu4CMkwyw/YS7uzxnfJWVLa+kC4kxMvDRjwUHXbXGdrafc/mFBaMLgK2oEhIk23qbOAqzctmjNYw4oIAjzmiOEUM0Rad1RAX8eMqxgy95TAoh634GsGxmKUJ71m8yV9FPprMKpE5TpIpSQjdvhG8+OWnxEnGxPLAtSr6YmYdahfQElGG1juQUP8rInyKdMNN6qd1Jm6U/qpNe9cTWLyT8k6d8lAsNVHju8033hAptyf9XC39dPIlrmyFSBGZdB2VC/FonpBVEEPKRiFk8B0WaE8w+vI9AMWeK1PsuDrFXQx7QxDs9yD4dtQ9ANtjRc+mTrZl2Trb4yHYHt8b254ibfAv2Z4cZhtl4UNZDvFeRjL0GXOggyFODN384j2z7vwuOyO37K4x+yU8le32yV5eC7KgQV1hicqDQRohJmMolKoznf3dxblj5agxihJewSzlmq6LcvGGGcF8xk1wHU8Oru3KHqqvIwbtFlmKn4nsB/iKn4oCzc82/s2X7icJr0MSWp3wkOcJDuraDqZlQmXvRV6VBl/9q/bN/612HAp5IinE2V0Vn81xt96sx462fQB/oi9wtm+fv3808+23fwQJLAocbAnkBaYOf05x37334B7h39YeIUfQ85WNvfceofixFT/D7RF1lK8S9qagsOSCwj6vbhh/aeI8TYBrakIUkqZWSJa92c5ib/YWiXvzxaWnHNSc8anV5Wkq4UGDmx2zvDQoPpmvqc5XulnkjcrjyRLUbyL7SfCoA81e9dyIKoByoGyie6wqVEfAvdzi0eMS6w4iN5mMXIly69R131FSzb7gwt91YLy72KmEO6dGTheBc8HY9bjbPOL+57ituTN+h/dl75phtn1lTQQDJSi4YJB7XKmeG+Tmkm/kO75cl5tmY9FdiPVRgFSFXVUBBwPXVwGWcnJ3naEUwLvtz7+VefsTO3j+Cw== 5 | 6 | -------------------------------------------------------------------------------- /documentation/architecture/images/axon-iq-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sncf-connect-tech/hesperides/90995d20e0a213cf4e98457ab7958aa35393164d/documentation/architecture/images/axon-iq-logo.png -------------------------------------------------------------------------------- /documentation/architecture/images/cqrs_event_sourcing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sncf-connect-tech/hesperides/90995d20e0a213cf4e98457ab7958aa35393164d/documentation/architecture/images/cqrs_event_sourcing.png -------------------------------------------------------------------------------- /documentation/architecture/images/hexagonal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sncf-connect-tech/hesperides/90995d20e0a213cf4e98457ab7958aa35393164d/documentation/architecture/images/hexagonal.png -------------------------------------------------------------------------------- /documentation/architecture/images/mongodb-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sncf-connect-tech/hesperides/90995d20e0a213cf4e98457ab7958aa35393164d/documentation/architecture/images/mongodb-logo.png -------------------------------------------------------------------------------- /documentation/architecture/images/spring-boot-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sncf-connect-tech/hesperides/90995d20e0a213cf4e98457ab7958aa35393164d/documentation/architecture/images/spring-boot-logo.png -------------------------------------------------------------------------------- /documentation/architecture/mongodb.md: -------------------------------------------------------------------------------- 1 | # MongoDB 2 | 3 | _cf._ [lightweight-architecture-decision-records/database](../lightweight-architecture-decision-records/database.md) pour les détails du choix de base de donnée. 4 | 5 | ## Archi du cluster 6 | 7 | Dans le cas d'Hesperides, nous recommendons l'utilisation d'un cluster de 2 noeuds Mongo en lecture/écriture sur 2 datacenters, plus un 3e servant d'arbitre en cas de _split brain_. 8 | 9 | ## Configuration du client 10 | 11 | La configuration du client Mongo se fait via la variable d'environnement `MONGO_URI` qui contiennent 12 | la liste des noeuds du cluster à utiliser et les options de connexion à employer. 13 | 14 | ## Consultation des options de connexion 15 | 16 | Un _HealthIndicator_ Spring Boot expose ces informations dans un endpoint HTTP: 17 | 18 | curl -s http://localhost:8080/rest/manage/health 19 | 20 | ## Erreurs 21 | 22 | ### MongoWaitQueueFullException: Too many threads are already waiting for a connection. Max number of threads (maxWaitQueueSize) of 50 has been exceeded 23 | 24 | _cf._ https://stackoverflow.com/a/54981196/636849 pour configurer cette limite. 25 | -------------------------------------------------------------------------------- /documentation/architecture/sentry-error-message-filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sncf-connect-tech/hesperides/90995d20e0a213cf4e98457ab7958aa35393164d/documentation/architecture/sentry-error-message-filter.png -------------------------------------------------------------------------------- /documentation/domain_model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sncf-connect-tech/hesperides/90995d20e0a213cf4e98457ab7958aa35393164d/documentation/domain_model.png -------------------------------------------------------------------------------- /documentation/lightweight-architecture-decision-records/ACLs_pseudo_UML.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sncf-connect-tech/hesperides/90995d20e0a213cf4e98457ab7958aa35393164d/documentation/lightweight-architecture-decision-records/ACLs_pseudo_UML.png -------------------------------------------------------------------------------- /documentation/lightweight-architecture-decision-records/aggregate_identifiers.md: -------------------------------------------------------------------------------- 1 | # Identifiants d'agrégats 2 | 3 | Les agrégats Axon sont identifiés par un attribut ayant l'annotation `@AggregateIdentifier` qui est unique et lui permet de les distinguer. 4 | 5 | Lors de la refonte, nous avons dans un premier temps décidé de l'appliquer sur la clé fonctionnelle (l'objet `Key`) des technos, modules et plateformes. 6 | 7 | L'application existante permettant de supprimer une entité puis de la créer à nouveau en utilisant la même clé, nous avons résolu cette problématique en utilisant un identifiant généré aléatoirement (`UUID`). 8 | 9 | Mais un bug ([#779](https://github.com/voyages-sncf-technologies/hesperides/issues/779)) a révélé que cela permettait la création de doublons lorsque plusieurs requêtes de création identiques était déclenchées au même moment. 10 | 11 | La solution a été d'utiliser un hash de la clé fonctionnelle comme identifiant d'agrégat et de supprimer les événements passés de cet agrégrat lorsqu'il est *recréé*. -------------------------------------------------------------------------------- /documentation/lightweight-architecture-decision-records/database.md: -------------------------------------------------------------------------------- 1 | # Nouveau SGBD pour l'Event Store et l'état final 2 | 3 | ## Tests de performance 4 | 5 | | |Mongo|Postgres|Maria| 6 | |---|---|---|---| 7 | |Insérer un million d'évènements|24s|125s|160s| 8 | |Insérer 40 000 modules|1s|10s|7s| 9 | |Récupérer 40 000 modules|605ms|11s|292ms| 10 | |*Recherche de modules limitée à 30 résultats*|33ms|23ms|39ms| 11 | |*Stocker des gros templates (5 et 50Mo)*|Limité à 16Mo|OK|Limité à 16Mo| 12 | |*Récupérer des gros templates*|49ms|111ms|64ms| 13 | 14 | ## Conclusion 15 | 16 | Il n'y a pas grandes différences de performance. Mongo et Maria sont limités en taille à l'insertion à 16Mo. Nous savons aujourd'hui qu'il existe des templates qui dépassent cette taille. Ce sont des cas marginaux qui seront gérés de manière particulière lors de la récupération des données existantes. 17 | 18 | Mongo a au moins deux avantages : 19 | * La définition des entités est plus simple que pour JPA 20 | * Un driver ReactiveMongo existe et nous permettrait de faire des appels non bloquants 21 | 22 | L'avantage d'une base de données compatible JPA donne un plus grand choix de base de données. 23 | 24 | Dans les deux cas, le résultat du test de performance sur la recherche de modules nous permet de nous passer d'Elasticsearch. 25 | 26 | Et le vainqueur est... **Mongo** ! -------------------------------------------------------------------------------- /documentation/lightweight-architecture-decision-records/ddd_cqrs_event_sourcing.md: -------------------------------------------------------------------------------- 1 | En regardant l'application legacy, on constate qu'elle utilise un système d'event sourcing / cqrs. 2 | 3 | Le problème est que le code est complètement mélangé. 4 | Les informations/concepts "métiers" sont noyés dans du bruit technique (cache, virtual...) 5 | 6 | Il a donc été décidé de refondre l'application en appliquant les principes du DDD 7 | 8 | Par contre on peut également conserver le concept d'event sourcing, d'autant plus qu'on veut garder la base iso existant. 9 | 10 | Pour simplifier l'implémentation event sourcing, on pourra se tourner vers un framework adhoc: https://docs.axonframework.org/v/3.1/part3/spring-boot-autoconfig.html 11 | -------------------------------------------------------------------------------- /documentation/lightweight-architecture-decision-records/deprecated_endpoints.md: -------------------------------------------------------------------------------- 1 | # Points d'accès dépréciés 2 | 3 | Nous mettons à jour l'API petit à petit. Cela implique parfois de déprécier 4 | certains endpoints afin de les remplacer sans les supprimer. 5 | 6 | Nous tenons par la même occasion à prévenir les différents clients qui 7 | appellent l'API. Pour cela, nous utilisons des en-têtes de réponse HTTP 8 | définies selon le standard RFC : https://tools.ietf.org/html/draft-dalal-deprecation-header-00 9 | 10 | Exemple : 11 | 12 | return ResponseEntity.ok() 13 | .header("Deprecation", "version=\"2019-04-23\"") // Version du build 14 | .header("Sunset", "Wed Apr 24 00:00:00 CEST 2020") // Date de suppression du endpoint 15 | .header("Link", "/nouveau-endpoint") // Où trouver la nouvelle ressource 16 | .body(...); // Corps de la réponse 17 | 18 | Voici une commande utile pour lister toutes les dates de _Sunset_ définies pour nos APIs dépréciées : 19 | 20 | grep Sunset core/presentation/src/main/java/org/hesperides/core/presentation/controllers/* 21 | -------------------------------------------------------------------------------- /documentation/lightweight-architecture-decision-records/events_history/index.md: -------------------------------------------------------------------------------- 1 | # Historique des évènements 2 | 3 | ## Ressources actuelles 4 | 5 | /events/modules/{name}/{version}/{type} 6 | /events/platforms/{application_name}/{platform_name} 7 | /events/{stream} 8 | 9 | Ces ressources seront conservées mais dépréciées. 10 | 11 | ## Besoins 12 | 13 | * Visualisation des modifications des valorisations de propriétés 14 | * Visualisation des changements de versions de modules déployés 15 | * Visualisation des ajouts/suppressions de modules déployés 16 | * Visualisation des modifications de versions de platformes 17 | * Visualisation des ajouts/suppressions de templates (dans un module ou une techno) 18 | * Comparer les valorisations d'un module entre 2 versions 19 | 20 | 3 cas d'utilisations dans des modales _frontend_ : 21 | 1. [Historique des valorisations d'un module déployé](properties_events.md) 22 | 1. [Historique au niveau d'une plateforme](platform_events.md) 23 | 1. [Historique d'un module ou d'une techno](template_container_events.md) 24 | -------------------------------------------------------------------------------- /documentation/lightweight-architecture-decision-records/events_history/template_container_events.md: -------------------------------------------------------------------------------- 1 | # Historique d'un module ou d'une techno 2 | 3 | * Templates ajoutés, modifiés ou supprimés 4 | * Diff des modifications apportés aux templates (ligne par ligne comme le diff Git) 5 | 6 | [À compléter] 7 | -------------------------------------------------------------------------------- /documentation/lightweight-architecture-decision-records/java_11.md: -------------------------------------------------------------------------------- 1 | Passage à Java 11 2 | ================= 3 | 4 | Lors de la refonte du _backend_, Java 8 a été employé. 5 | 6 | Début 2020, avec la [fin de vie](https://en.wikipedia.org/wiki/Java_version_history) de cette version annoncée pour l'année en cours, 7 | il a été decidé de basculer l'application en Java 11 LTS (_Long Term Support_). 8 | 9 | Côté runtime / image Docker, la version OpenJDK est employée. 10 | -------------------------------------------------------------------------------- /documentation/lightweight-architecture-decision-records/letter_case_sensitivity_in_rest_api.md: -------------------------------------------------------------------------------- 1 | # Casse des identifiants dans l'API REST 2 | 3 | Voici les règles en vigueur en termes de casse des identifants (d'application, module, template...) : 4 | - lors de création (`POST`) d'entités, Hesperides est **sensible** à la casse, 5 | mais interdit la création d'entité ayant un nom identique mais une casse différente 6 | - lors de consultation (`GET`), modification (`PUT`) ou suppression (`DELETE`) d'entités, Hesperides est **insensible** à la casse. 7 | 8 | ## Implémentation 9 | 10 | Pour mettre cela en place techniquement, nous avons opté pour mettre en place des [collations](https://docs.mongodb.com/manual/reference/collation/) 11 | sur les collections MongoDB concernées, afin de rendre leurs champs `key` insensible à la casse. 12 | 13 | Comme `spring-data-mongodb` ne fournit aucune moyen d'affiner la création des collections, 14 | ou de l'effectuer manuellement, nous nous sommes résolu à effectuer la création des collections **avant** le lancement de l'application, 15 | dans un script d'[_entrypoint_ Docker](/docker_entrypoint.sh). 16 | 17 | ## Tests 18 | 19 | Comme les tests BDD validant ce fonctionnement dépendent de l'utilisation d'un serveur MongoDB, 20 | nous avons tagué ces tests en `@require-real-mongo`, et ils ne sont pas exécutés avec les autres tests Cucumber 21 | en mode "bouchonné" (avec `mongo-java-server`), uniquement en mode "tests d'intégration". 22 | 23 | Pour ne lancer que les tests bouchonnés dans IntelliJ, il suffit d'ajouter ceci dans `Edit configurations > Program arguments`: 24 | 25 | -Dcucumber.options="--tags ~@require-real-mongo,~@require-real-ad" 26 | -------------------------------------------------------------------------------- /documentation/lightweight-architecture-decision-records/mongo_optim.md: -------------------------------------------------------------------------------- 1 | # xAlreadyExists(...) 2 | 3 | Pour nos requêtes de vérification de l'existence d'une entité à partir de son identifiant, plutôt que de tenter de récupérer l'entité elle-même et de tester son existence, il est préférable de compter le nombre d'entités correspondant à cet identifiant. 4 | 5 | Comme ceci : 6 | 7 | return xRepository.countByKey(key) > 0; 8 | 9 | C'est une optimisation qui n'est pas négligeable étant donné le nombre de requêtes de ce type. 10 | -------------------------------------------------------------------------------- /documentation/lightweight-architecture-decision-records/move_to_spring_boot.md: -------------------------------------------------------------------------------- 1 | Il a été décidé de dropper définitivement dropwizard pour le remplacer par spring boot. 2 | 3 | Cela implique une refonte majeure de l'application. -------------------------------------------------------------------------------- /documentation/lightweight-architecture-decision-records/regression_testing.md: -------------------------------------------------------------------------------- 1 | # Tests de non-régression 2 | 3 | Nous avons mis en place les tests de non-régression dans le batch de migration 4 | des données afin valider la rétrocompatibilité de la refonte. 5 | 6 | Le principe était d'appeler les endpoints GET du legacy et de la refonte, 7 | et de comparer les résultats afin d'en sortir des diffs. 8 | 9 | Nous souhaitons inclure ces tests dans la refonte et pouvoir les déclencher ponctuellement. 10 | 11 | Le but est de les déclencher lorsqu'on modifie, comme c'est prévu, le coeur de 12 | l'application existante. Par exemple, quand on touchera au modèle de propriétés. 13 | 14 | ## Spécifications 15 | 16 | Le principe reste le même : comparer les résultats des endpoints GET sur les technos, 17 | les modules et les plateformes entre la version N et la version N+1, sur un même jeu de données. 18 | 19 | ## Paramètres 20 | 21 | # Paramètres de connexion 22 | REGRESSIONTEST_USERNAME 23 | REGRESSIONTEST_PASSWORD 24 | REGRESSIONTEST_LATEST_URL 25 | REGRESSIONTEST_TESTING_URL 26 | 27 | # Entités à tester 28 | REGRESSIONTEST_VALIDATE_TECHNOS (default: true) 29 | REGRESSIONTEST_VALIDATE_MODULES (default: true) 30 | REGRESSIONTEST_VALIDATE_PLATFORMS (default: true) 31 | 32 | # Logs pendant le déroulement des tests, en plus des logs de fin 33 | REGRESSIONTEST_LOGWHILETESTING (default: false) 34 | 35 | # Niveau de logs 36 | LOG_LEVEL (default: DEBUG) -------------------------------------------------------------------------------- /documentation/lightweight-architecture-decision-records/swagger_customization.md: -------------------------------------------------------------------------------- 1 | # Swagger 2 | 3 | Nous utilisons la librairie Springfox pour proposer le service Swagger v2 via l'url `/rest/swagger-ui.html`. 4 | 5 | Nous avons choisi la version `2.8.0` car la dernière en date (`2.9.2`) ajoute beaucoup d'informations dont nous n'avons pas besoin dans l'interface. 6 | 7 | De plus, afin de simplifier au maximum cette interface, nous avons effectué les modifications suivantes : 8 | 9 | * Nous utilisons notre propre `swagger-ui.html`, avec un peu de CSS pour cacher certaines zones 10 | * Un peu de personnalisation via `SwaggerConfiguration` 11 | * Chaque controller contient l'annotation `@Api(tags = "x. Something", description = " ")` car : 12 | 13 | * C'est le moyen que nous avons trouver de trier les ressources 14 | * La description auto-générée (`Something Controller`) n'est pas utile 15 | 16 | -------------------------------------------------------------------------------- /documentation/lightweight-architecture-decision-records/tests_strategy.md: -------------------------------------------------------------------------------- 1 | # Notre stratégie de tests 2 | 3 | Il y a 4 niveaux de tests automatisés : 4 | * Tests unitaires 5 | * Tests end-to-end 6 | * Tests d'intégration 7 | * Tests de non régression 8 | 9 | Les tests unitaires sont utiles dans des cas particuliers comme, typiquement, le mapping entre les évènements de la nouvelle application et ceux de l'ancienne application (stockés dans le Redis). Ce sont des tests JUnit classiques. 10 | 11 | Les tests end-to-end et d'intégration ont la même base de tests. La seule différence est que la couche infrastructure est mockée pour les tests end-to-end, contrairement aux tests d'intégration. Cette base de tests est rédigée sous forme de tests fonctionnels à l'aide du framework Cucumber. 12 | 13 | Les tests end-to-end couvrent l'application à partir de l'appel d'un endpoint jusqu'à la couche infrastructure. La couche infrastructure est mockée. Cette partie de l'application est couverte par certains TU et par les tests d'intégration. 14 | 15 | Les tests d'intégration sont faits sur une plateforme d'intégration et couvrent l'application dans son intégralité, incluant les partenaires externes dont Redis et Elasticsearch. 16 | 17 | Les tests de non-régression s'effectuent sur une plateforme à l'extérieur de VSCT (par exemple Heroku) et en mode boîte noire. 18 | 19 | *Dans le but d'avoir une approche BDD, nous prévoyons de rédiger les tests fonctionnels correspondant à chaque fonctionnalité, avant leur implémentation.* -------------------------------------------------------------------------------- /documentation/lightweight-architecture-decision-records/use_axon_framework.md: -------------------------------------------------------------------------------- 1 | # Why ? 2 | 3 | Le framework [Axon](http://www.axonframework.org/) permet de gérer toute la plomberie eventsourcing / cqrs: 4 | 5 | * event store 6 | * transactions (détection de conflits) 7 | * snapshots ! 8 | 9 | c'est clairement intéressant, on a pas envie de gérer ça à la main. 10 | 11 | # Par où commencer ? 12 | 13 | Tout d'abord, il faut avoir des notions sur les concepts d'Event Sourcing et CQRS. 14 | 15 | Pour cela, on peut lire la doc Axon ici: https://docs.axonframework.org/part1/architecture-overview.html 16 | Utile aussi: http://cqrs.nu/ 17 | 18 | Un fois qu'on à les bases, on peut commencer à coder: 19 | 20 | Chez spring, il y a un petit tutorial simple: http://www.baeldung.com/axon-cqrs-event-sourcing 21 | 22 | Ensuite on passe au déploiement dans l'application. 23 | 24 | # Spring autoconfigure 25 | 26 | On va utiliser spring avec axon comme décrit dans la doc ici: https://docs.axonframework.org/part3/spring-boot-autoconfig.html 27 | 28 | En gros: 29 | * Les commandes, les aggrégats et les events font parties du domaine. On les déclare dans le module adhoc. 30 | * Les eventbus, eventstore, etc. c'est de l'infrastructure. 31 | 32 | On va voir si on peut tuner chaque élément pour coller à l'existant hespéride. 33 | 34 | ## Query processing 35 | 36 | On peut utiliser le framework pour faire les queries (la partie read de CQRS) faut voir comment ça marche. 37 | 38 | # Migration des events actuels 39 | 40 | Un problème qu'on va rapidement avoir sera la relecture des events legacy dans la nouvelle version. 41 | cf. https://docs.axonframework.org/part3/repositories-and-event-stores.html#event-upcasting pour voir si ça peut aider. -------------------------------------------------------------------------------- /documentation/lightweight-architecture-decision-records/use_gson.md: -------------------------------------------------------------------------------- 1 | # Pourquoi Gson ? 2 | 3 | Nous utilisons Gson pour sérialiser/désérialiser : 4 | - les objets correspondant aux events du legacy 5 | - les inputs de la couche présentation 6 | 7 | Contrairement à Jackson, Gson est compatible avec les annotations Lombok 8 | et nous permet de réduire la quantité de code à maintenir. 9 | 10 | ## Serialize null 11 | 12 | Pour être iso-legacy, nous avons décidé de sérialiser les champs dont la valeur est `null`. S'il est nécessaire d'exclure un champ qui est null, il faut créer un Serializer (voir `PropertyOutput.Serializer`). 13 | 14 | ## Swagger 15 | 16 | Swagger ne gère pas nativement le fait d'utiliser Gson plutôt que Jackson. C'est pourquoi on retrouve sur les IO l'annotation @JsonProperty, pour Swagger, en plus de l'annotation @SerializedName, pour Gson. 17 | 18 | De plus, Swagger n'aime pas le type primitif boolean donc on utilise désormais Boolean. 19 | 20 | Endpoint pour accéder au Swagger : /rest/swagger-ui.html 21 | 22 | ## Classes abstraites 23 | 24 | La sérialisation et désérialisation de classes abstraites n'est pas gérée nativement par Gson. En cas de besoin, il faut créer un Adapter (voir `AbstractValuedPropertyIO.Adapter`). -------------------------------------------------------------------------------- /documentation/lightweight-architecture-decision-records/use_kotlin.md: -------------------------------------------------------------------------------- 1 | # Pourquoi Kotlin ? 2 | 3 | Le framework Axon nécessite de créer une classe par Command/Event/Query. 4 | 5 | Ces classes ne contiennent que des propriétés, ce qui fait beaucoup de classes pour pas grand chose, 6 | même avec l'utilisation de Lombok. 7 | 8 | Kotlin permet de palier à ça, sans ajouter de complexité (juste une nouvelle syntaxe). 9 | Pour l'instant, on ne l'utilise que pour ces 3 cas (Command/Event/Query), mais à voir pour les Exception. -------------------------------------------------------------------------------- /documentation/lightweight-architecture-decision-records/use_lombok.md: -------------------------------------------------------------------------------- 1 | # Pourquoi Lombok ? 2 | 3 | Dans le code legacy, il y a pas mal de code du genre HashCode/equals, etc. 4 | 5 | De plus on souhaite travailler avec des objets Immutables. 6 | 7 | Lombok est un outil qui permet de générer le code à la volée pour réduire tout le bruit technique induit par les getters, 8 | setter, etc. 9 | 10 | Il gère également les objets immutables, les builders. 11 | 12 | Utile pour garder propre les définitions de commandes/events -------------------------------------------------------------------------------- /documentation/postman/postman.md: -------------------------------------------------------------------------------- 1 | # Postman 2 | 3 | https://www.getpostman.com/ 4 | 5 | Importez: 6 | 7 | * hesperides.postman_collection.json (contient les requêtes) 8 | * hesperides_local.postman_environment.json (contient les variables) 9 | 10 | En plus des variables fournies, deux variables globales sont à créer : 11 | * username 12 | * password 13 | 14 | Les différents versionID (liés aux templates et modules) sont auto-incrémentés, et remis à 0 lorsque le module ou le template est supprimé -------------------------------------------------------------------------------- /heroku.yml: -------------------------------------------------------------------------------- 1 | build: 2 | docker: 3 | # Using the Docker Hub published image: 4 | web: Dockerfile.heroku 5 | # We can also build it from the sources: 6 | # worker: Dockerfile 7 | -------------------------------------------------------------------------------- /mongo_create_collections.js: -------------------------------------------------------------------------------- 1 | // On crée les 3 collections avec une collation rendant leur "key" insensible à la casse. 2 | // Cette création n'a réellement lieu que si les collections n'existe pas déjà, 3 | // en cas de modification des paramètres de collation par exemple, il faut donc supprimer les collections au préalable. 4 | ['module', 'platform', 'techno', 'application_directory_groups'].forEach(collectionName => { 5 | if (!db.getCollectionNames().includes(collectionName)) { 6 | printjson(db.createCollection(collectionName, {collation: {locale: 'fr', strength: 2}})); 7 | printjson(db[collectionName].createIndex({key: 1})); 8 | print(collectionName, 'indexes:'); 9 | printjson(db[collectionName].getIndexes()); 10 | } else { 11 | print("The '" + collectionName + "' collection already exists."); 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /mongo_test_create_collections.js: -------------------------------------------------------------------------------- 1 | // On crée une collection de test pour valider les permissions associées à l'utilisateur 2 | let test_collection = "hesperides_test"; 3 | if (!db.getCollectionNames().includes(test_collection)) { 4 | printjson(db.createCollection(test_collection)); 5 | } else { 6 | print("The '" + test_collection + "' collection already exists."); 7 | } 8 | -------------------------------------------------------------------------------- /tests/activedirectory-integration/README.md: -------------------------------------------------------------------------------- 1 | Those tests require a real ActiveDirectory instance to connect to. 2 | 3 | They use the BDD _features_ defined in the `tests/bdd` module and tagged `@require-real-ad` or `@auth-related`. 4 | 5 | ## Execution 6 | 7 | mvn verify -pl tests/activedirectory-integration 8 | -Dauth.lambdaUsername="" 9 | -Dauth.lambdaPassword="" 10 | -Dauth.prodUsername="" 11 | -Dauth.prodPassword="" 12 | -Dauth.nogroupUsername="" 13 | -Dauth.nogroupPassword="" 14 | -Dauth.prodGroupCn="" 15 | -Dauth.otherGroupCn="" 16 | -Djavax.net.ssl.trustStore=.../path/to/certificates/trustore 17 | -------------------------------------------------------------------------------- /tests/activedirectory-integration/src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /tests/bdd/src/main/java/org/hesperides/test/bdd/commons/DataTableHelper.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.test.bdd.commons; 2 | 3 | import static org.apache.commons.lang3.StringUtils.EMPTY; 4 | import static org.apache.commons.lang3.StringUtils.SPACE; 5 | 6 | public final class DataTableHelper { 7 | 8 | // À partir de la version 5 de Cucumber, les cellules vides des `DataTable` 9 | // sont remplacées par la valeur `null`, ce qui n'était pas le cas avant. 10 | // Elles étaient considérées comme des chaînes de caractères vides (`""`). 11 | // Cette méthode utilitaire permet de ne pas avoir à modifier toutes les 12 | // features impactées par cette évolution. 13 | public static String decodeValue(String value) { 14 | String result; 15 | if (value == null) { 16 | result = EMPTY; 17 | } else if (value.contains("")) { 18 | result = value.replace("", SPACE); 19 | } else if ("".equals(value)) { 20 | result = null; 21 | } else { 22 | result = value; 23 | } 24 | return result; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/bdd/src/main/java/org/hesperides/test/bdd/configuration/TestDatabaseCleaner.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.test.bdd.configuration; 2 | 3 | import org.bson.Document; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.data.mongodb.core.MongoTemplate; 7 | 8 | @Configuration 9 | public class TestDatabaseCleaner { 10 | @Autowired 11 | private MongoTemplate mongoTemplate; 12 | 13 | public void wipeOutCollections() { 14 | for (String collection : mongoTemplate.getCollectionNames()) { 15 | // Ne pas utiliser `.drop()` sur les collections pour ne pas supprimer 16 | // les collations créées dans mongo_create_collections.js 17 | mongoTemplate.getCollection(collection).deleteMany(new Document()); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/bdd/src/main/java/org/hesperides/test/bdd/configuration/TestExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.test.bdd.configuration; 2 | 3 | import org.hesperides.commons.SpringProfiles; 4 | import org.hesperides.core.presentation.exceptions.GlobalExceptionHandler; 5 | import org.springframework.context.annotation.Profile; 6 | import org.springframework.web.bind.annotation.ControllerAdvice; 7 | 8 | @ControllerAdvice 9 | @Profile(SpringProfiles.TEST) 10 | public class TestExceptionHandler extends GlobalExceptionHandler { 11 | @Override 12 | protected void beforeHandling(Exception exception) { 13 | exception.printStackTrace(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/bdd/src/main/java/org/hesperides/test/bdd/configuration/TestRestTemplateConfig.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.test.bdd.configuration; 2 | 3 | import com.google.gson.Gson; 4 | import org.springframework.boot.test.web.client.LocalHostUriTemplateHandler; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.core.env.Environment; 8 | import org.springframework.web.util.DefaultUriBuilderFactory; 9 | 10 | @Configuration 11 | public class TestRestTemplateConfig { 12 | @Bean 13 | public DefaultUriBuilderFactory defaultUriBuilderFactory() { 14 | return new DefaultUriBuilderFactory(); 15 | } 16 | 17 | @Bean 18 | public CustomRestTemplate buildRestTemplate(Environment environment, Gson gson, DefaultUriBuilderFactory defaultUriBuilderFactory) { 19 | return new CustomRestTemplate(gson, new LocalHostUriTemplateHandler(environment, "http", defaultUriBuilderFactory)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/bdd/src/main/java/org/hesperides/test/bdd/technos/scenarios/GetTechnosModel.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.test.bdd.technos.scenarios; 2 | 3 | import io.cucumber.java8.En; 4 | import org.hesperides.core.presentation.io.templatecontainers.ModelOutput; 5 | import org.hesperides.test.bdd.commons.HesperidesScenario; 6 | import org.hesperides.test.bdd.technos.TechnoBuilder; 7 | import org.hesperides.test.bdd.technos.TechnoClient; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | 10 | import java.util.Collections; 11 | 12 | import static org.junit.Assert.assertEquals; 13 | 14 | public class GetTechnosModel extends HesperidesScenario implements En { 15 | 16 | @Autowired 17 | private TechnoClient technoClient; 18 | @Autowired 19 | private TechnoBuilder technoBuilder; 20 | 21 | public GetTechnosModel() { 22 | 23 | When("^I( try to)? get the model of this techno$", (String tryTo) -> technoClient.getModel(technoBuilder.build(), tryTo)); 24 | 25 | Then("^the model of this techno contains the properties$", () -> { 26 | assertOK(); 27 | ModelOutput expectedModel = technoBuilder.buildPropertiesModel(); 28 | ModelOutput actualModel = testContext.getResponseBody(); 29 | assertEquals(expectedModel, actualModel); 30 | }); 31 | 32 | Then("^the techno model is empty$", () -> { 33 | assertOK(); 34 | ModelOutput expectedModel = new ModelOutput(Collections.emptySet(), Collections.emptySet()); 35 | ModelOutput actualModel = testContext.getResponseBody(); 36 | assertEquals(expectedModel, actualModel); 37 | }); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/bdd/src/main/java/org/hesperides/test/bdd/technos/scenarios/ReleaseTechnos.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.test.bdd.technos.scenarios; 2 | 3 | import io.cucumber.java8.En; 4 | import org.hesperides.test.bdd.commons.HesperidesScenario; 5 | import org.hesperides.test.bdd.technos.TechnoBuilder; 6 | import org.hesperides.test.bdd.technos.TechnoClient; 7 | import org.hesperides.test.bdd.technos.TechnoHistory; 8 | import org.hesperides.test.bdd.templatecontainers.TestVersionType; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | 11 | import static org.apache.commons.lang3.StringUtils.isEmpty; 12 | 13 | public class ReleaseTechnos extends HesperidesScenario implements En { 14 | 15 | @Autowired 16 | private TechnoClient technoClient; 17 | @Autowired 18 | private TechnoBuilder technoBuilder; 19 | @Autowired 20 | private TechnoHistory technoHistory; 21 | 22 | public ReleaseTechnos() { 23 | 24 | When("^I( try to)? release this techno$", (String tryTo) -> { 25 | release(tryTo); 26 | }); 27 | 28 | Then("^the techno release is rejected with a not found error$", this::assertNotFound); 29 | 30 | Then("^the techno release is rejected with a conflict error$", this::assertConflict); 31 | } 32 | 33 | public void release(String tryTo) { 34 | technoClient.releaseTechno(technoBuilder.build(), tryTo); 35 | if (isEmpty(tryTo)) { 36 | technoBuilder.withVersionType(TestVersionType.RELEASE); 37 | technoBuilder.updateTemplatesNamespace(); 38 | technoHistory.addTechnoBuilder(technoBuilder); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/bdd/src/main/java/org/hesperides/test/bdd/technos/scenarios/SearchTechnos.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.test.bdd.technos.scenarios; 2 | 3 | import io.cucumber.java8.En; 4 | import org.hesperides.test.bdd.commons.HesperidesScenario; 5 | import org.hesperides.test.bdd.technos.TechnoClient; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | 8 | import static org.junit.Assert.assertEquals; 9 | 10 | public class SearchTechnos extends HesperidesScenario implements En { 11 | 12 | @Autowired 13 | private TechnoClient technoClient; 14 | 15 | public SearchTechnos() { 16 | 17 | When("^I search for one specific techno$", () -> technoClient.searchTechnos("test-techno 0.3")); 18 | 19 | When("^I search for some of these technos(?:, limiting the number of results to (\\d+))?$", (Integer resultsCount) -> { 20 | technoClient.searchTechnos("test-techno", resultsCount == null ? 0 : resultsCount); 21 | }); 22 | 23 | When("^I search for a techno that does not exist$", () -> technoClient.searchTechnos("nope")); 24 | 25 | When("I search for the techno named {string}", (String searchInput) -> technoClient.searchTechnos(searchInput)); 26 | 27 | Then("^the techno is found$", () -> { 28 | assertOK(); 29 | assertEquals(1, testContext.getResponseBodyArrayLength()); 30 | }); 31 | 32 | Then("^the list of techno results is limited to (\\d+) items$", (Integer limit) -> { 33 | assertOK(); 34 | assertEquals(limit.intValue(), testContext.getResponseBodyArrayLength()); 35 | }); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/bdd/src/main/java/org/hesperides/test/bdd/versions/GetApplicationVersion.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.test.bdd.versions; 2 | 3 | import io.cucumber.java8.En; 4 | import org.hesperides.test.bdd.commons.HesperidesScenario; 5 | 6 | import java.util.Map; 7 | 8 | import static org.junit.Assert.assertNotNull; 9 | 10 | public class GetApplicationVersion extends HesperidesScenario implements En { 11 | 12 | public GetApplicationVersion() { 13 | 14 | When("^I get the application versions$", () -> { 15 | restTemplate.getForEntity("/versions", Map.class); 16 | }); 17 | 18 | Then("^the versions are returned$", () -> { 19 | assertOK(); 20 | Map map = testContext.getResponseBodyAsMap(); 21 | assertNotNull(map.get("version")); 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | logging.level: 2 | org.hesperides.core.domain: 3 | templatecontainers.entities.AbstractProperty: INFO 4 | modules.commands.ModuleAggregate: INFO 5 | platforms.commands.PlatformAggregate: INFO 6 | org.springframework: 7 | data.mongodb.core.MongoTemplate: INFO -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/authorizations/get-application-directory-groups.feature: -------------------------------------------------------------------------------- 1 | @require-real-ad 2 | Feature: Get application directory groups 3 | 4 | Background: 5 | Given an authenticated prod user 6 | 7 | Scenario: retrieve directory groups associated with an application 8 | Given an application associated with the directory group ANOTHER_GROUP 9 | When I get the application detail 10 | Then the application details contains the directory group ANOTHER_GROUP -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/authorizations/get-user-authorities.feature: -------------------------------------------------------------------------------- 1 | @require-real-ad 2 | Feature: Get user authorities 3 | 4 | Scenario: retrieve a user's directory groups 5 | Given a lambda user belonging to the directory group A_GROUP 6 | When I get the current user information 7 | Then A_GROUP is listed under the user directory groups 8 | 9 | Scenario: retrieve directory groups associated with an application 10 | Given an authenticated prod user 11 | And an application ABC associated with the directory group A_GROUP 12 | And a lambda user belonging to the directory group A_GROUP 13 | When I get the current user information 14 | Then ABC_PROD_USER is listed under the user authority roles 15 | 16 | #issue-667 17 | @require-user-without-group 18 | Scenario: retrieve a user that has no authorities 19 | Given a user that does not belong to any group 20 | When I get the current user information 21 | Then the user is retrieved without any group 22 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/events/get-module-events.feature: -------------------------------------------------------------------------------- 1 | Feature: Get module events 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: get the events of a newly created module 7 | Given an existing module 8 | When I get the events of this module 9 | Then 1 event is returned 10 | And event at index 0 is a ModuleCreatedEvent event type 11 | 12 | Scenario: create a new module, add a template and read its events 13 | Given an existing module with a template 14 | When I get the events of this module 15 | Then 2 events are returned 16 | And event at index 0 is a TemplateCreatedEvent event type 17 | And event at index 1 is a ModuleCreatedEvent event type 18 | 19 | Scenario: get the events of a module that doesn't exist 20 | Given a module that doesn't exist 21 | When I get the events of this module 22 | Then 0 event is returned 23 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/events/get-platform-events.feature: -------------------------------------------------------------------------------- 1 | Feature: Get platform events 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: get the events of a newly created platform 7 | Given an existing platform 8 | When I get the events of this platform 9 | Then 1 event is returned 10 | And event at index 0 is a PlatformCreatedEvent event type 11 | 12 | Scenario: create a new platform, change its version and read its events 13 | Given an existing platform 14 | And I update this platform, changing the version 15 | When I get the events of this platform 16 | Then 2 events are returned 17 | And event at index 0 is a PlatformUpdatedEvent event type 18 | And event at index 1 is a PlatformCreatedEvent event type 19 | 20 | Scenario: get the events of a platform that doesn't exist 21 | Given a platform that doesn't exist 22 | When I get the events of this platform 23 | Then 0 event is returned 24 | 25 | Scenario: get the comments of updated properties events 26 | Given an existing module 27 | And an existing platform with this module 28 | And I update the properties with the comment "I hope I don't type this for nothing..." 29 | When I get the events of this platform 30 | Then one of the events should contain the comment "I hope I don't type this for nothing..." 31 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/modules/delete-modules.feature: -------------------------------------------------------------------------------- 1 | Feature: Delete modules 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: delete an existing module 7 | Given an existing module 8 | When I delete this module 9 | Then the module is successfully deleted 10 | 11 | Scenario: delete a released module 12 | Given an existing released module 13 | When I delete this module 14 | Then the module is successfully deleted 15 | 16 | Scenario: delete a module that doesn't exist 17 | Given a module that doesn't exist 18 | When I try to delete this module 19 | Then the module deletion is rejected with a not found error 20 | 21 | Scenario: delete an existing module used by a platform 22 | Given an existing module 23 | And an existing platform with this module 24 | When I try to delete this module 25 | Then the module deletion is rejected with a conflict error 26 | 27 | Scenario: delete an existing module used by a deleted platform 28 | Given an existing module 29 | And an existing platform with this module 30 | When I delete this platform 31 | And the platform is successfully deleted 32 | And I delete this module 33 | Then the module is successfully deleted 34 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/modules/get-modules-name.feature: -------------------------------------------------------------------------------- 1 | Feature: Get modules name 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: get a list of all the modules names 7 | Given a list of 12 modules with different names 8 | When I get the modules name 9 | Then a list of 12 elements is returned 10 | 11 | Scenario: get a list of all the modules name 12 | Given a list of 12 modules with the same name 13 | When I get the modules name 14 | Then a list of 1 element is returned -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/modules/get-modules-types.feature: -------------------------------------------------------------------------------- 1 | Feature: Get modules type 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: get the types of a released module 7 | Given an existing released module 8 | When I get the module types 9 | Then a list containing workingcopy and release is returned 10 | 11 | Scenario: get the types of a module that is not released 12 | Given an existing module 13 | When I get the module types 14 | Then a list containing workingcopy is returned 15 | 16 | Scenario: get the types of a module that doesn't exist 17 | Given a module that doesn't exist 18 | When I get the module types 19 | Then an empty list is returned -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/modules/get-modules-using-techno.feature: -------------------------------------------------------------------------------- 1 | Feature: Get modules using techno 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: get modules using techno 7 | Given an existing techno 8 | And an existing module named "M1" with this techno 9 | And an existing module named "M2" with this techno 10 | When I get the modules using this techno 11 | Then the modules using this techno are successfully retrieved 12 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/modules/get-modules-versions.feature: -------------------------------------------------------------------------------- 1 | Feature: Get modules versions 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: get the list of versions of an existing module 7 | Given a module with 4 versions 8 | When I get the module versions 9 | Then a list of 4 elements is returned 10 | 11 | Scenario: get the list of versions of a module that doesn't exist 12 | Given a module that doesn't exist 13 | When I get the module versions 14 | Then a list of 0 elements is returned 15 | 16 | Scenario: get a single version of a module that has been released 17 | Given an existing released module 18 | When I get the module versions 19 | Then a list of 1 element is returned 20 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/modules/release-modules.feature: -------------------------------------------------------------------------------- 1 | Feature: Release modules 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: release an existing module 7 | Given an existing module 8 | When I release this module 9 | Then the module is successfully released 10 | 11 | Scenario: release an already released module with the same version 12 | Given an existing released module 13 | When I try to release this module 14 | Then the module release is rejected with a conflict error 15 | 16 | Scenario: release an existing module with a different version 17 | Given an existing module 18 | When I release this module in version "2.0.0" 19 | Then the module is successfully released 20 | 21 | Scenario: release a module that doesn't exist 22 | Given a module that doesn't exist 23 | When I try to release this module 24 | Then the module release is rejected with a not found error 25 | 26 | Scenario: release a module without specifying its version 27 | Given an existing module 28 | When I try to release this module without specifying its version 29 | Then the module release is rejected with a bad request error 30 | 31 | #issue-378 32 | Scenario: trying to release a module that has an unreleased techno should fail 33 | Given an existing techno 34 | And an existing module with this techno 35 | When I try to release this module 36 | Then the module release is rejected with a conflict error 37 | 38 | Scenario: release a module that has a released techno 39 | Given an existing released techno 40 | And an existing module with this techno 41 | When I release this module 42 | Then the module is successfully released 43 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/modules/templates/delete-module-templates.feature: -------------------------------------------------------------------------------- 1 | Feature: Delete module templates 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: delete an existing template in a module 7 | Given an existing module with a template 8 | When I delete this module template 9 | Then the module template is successfully deleted 10 | 11 | Scenario: delete an existing template in a released module 12 | Given an existing released module with a template 13 | When I try to delete this module template 14 | Then the module template delete is rejected with a method not allowed error 15 | 16 | Scenario: delete a template that doesn't exist in a module 17 | Given an existing module 18 | And a template that doesn't exist in this module 19 | When I try to delete this module template 20 | Then the module template delete is rejected with a not found error 21 | 22 | Scenario: delete a template of a module that doesn't exist 23 | Given a module that doesn't exist 24 | When I try to delete this module template 25 | Then the module template delete is rejected with a not found error 26 | 27 | Scenario: delete a template with a slash within the title 28 | Given a template named "conf/domains.json" 29 | And an existing module with this template 30 | When I delete this module template 31 | Then the module template is successfully deleted 32 | 33 | Scenario: delete a template with a url-encoded slash within the title 34 | Given a template named "conf/domains.json" 35 | And an existing module with this template 36 | When I delete this module template using an url-encoded template name 37 | Then the module template is successfully deleted 38 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/modules/templates/update-module-templates.feature: -------------------------------------------------------------------------------- 1 | Feature: Update module templates 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: update an existing template in a module 7 | Given an existing module with a template 8 | And a template to update 9 | When I update this module template 10 | Then the module template is successfully updated 11 | 12 | Scenario: update an existing template in a released module 13 | Given an existing released module with a template 14 | And a template to update 15 | When I try to update this module template 16 | Then the module template update is rejected with a method not allowed error 17 | 18 | Scenario: update a template that doesn't exist in a module 19 | Given an existing module 20 | And a template that doesn't exist in this module 21 | When I try to update this module template 22 | Then the module template update is rejected with a not found error 23 | 24 | Scenario: update an outdated template 25 | Given an existing module with a template 26 | And the template is outdated 27 | When I try to update this module template 28 | Then the module template update is rejected with a conflict error 29 | 30 | Scenario: update a template of a module that doesn't exist 31 | Given a module that doesn't exist 32 | And a template to update 33 | When I try to update this module template 34 | Then the module template update is rejected with a not found error -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/modules/update-modules.feature: -------------------------------------------------------------------------------- 1 | Feature: Update modules 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: update an existing module 7 | Given an existing techno 8 | And an existing module with this techno 9 | When I update this module 10 | Then the module is successfully updated 11 | 12 | Scenario: update a released module 13 | Given an existing released module 14 | When I try to update this module 15 | Then the module update is rejected with a bad request error 16 | 17 | Scenario: update a module that doesn't exist 18 | Given a module that doesn't exist 19 | When I try to update this module 20 | Then the module update is rejected with a not found error 21 | 22 | Scenario: update an outdated module 23 | Given an existing module 24 | When I try to update this module using the wrong version_id 25 | Then the module update is rejected with a conflict error 26 | 27 | Scenario: update a module that has been deleted 28 | Given an existing module 29 | And I delete this module 30 | When I try to update this module 31 | Then the module update is rejected with a not found error 32 | 33 | Scenario: update a module with a techno that doesn't exist 34 | Given an existing module 35 | And a techno that doesn't exist 36 | When I try to update this module adding this techno 37 | Then the module update is rejected with a not found error 38 | 39 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/platforms/applications/search-applications.feature: -------------------------------------------------------------------------------- 1 | Feature: Search applications 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: search for an existing application 7 | Given a list of 12 applications prefixed by "app" 8 | When I search for the application "app-6" 9 | Then the application search result contains 1 entry 10 | And the application "app-6" is found 11 | 12 | Scenario: search for multiple applications 13 | Given a list of 12 applications prefixed by "app" 14 | When I search for the application "app" 15 | Then the application search result contains 12 entries 16 | 17 | Scenario: search for multiple applications with only one letter 18 | Given a list of 12 applications prefixed by "app" 19 | When I search for the application "a" 20 | Then the application search result contains 12 entries 21 | 22 | Scenario: search for an application that doesn't exist 23 | Given a list of 12 applications prefixed by "app" 24 | When I search for the application "app-13" 25 | Then the application search result contains 0 entries 26 | 27 | Scenario: search for an application without specifying the name 28 | Given a list of 12 applications prefixed by "app" 29 | When I search for the application "" 30 | Then the application search result contains 12 entries 31 | 32 | @require-real-mongo 33 | Scenario: search for applications is case-insensitive 34 | Given an application named AVG 35 | When I search for the application "avg" 36 | Then the application search result contains 1 entry 37 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/platforms/delete-platforms.feature: -------------------------------------------------------------------------------- 1 | Feature: Delete platforms 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: delete an existing platform 7 | Given an existing platform 8 | When I delete this platform 9 | Then the platform is successfully deleted 10 | 11 | Scenario: delete a platform that doesn't exist 12 | Given a platform that doesn't exist 13 | When I try to delete this platform 14 | Then the platform deletion is rejected with a not found error 15 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/platforms/get-platform-at-point-in-time.feature: -------------------------------------------------------------------------------- 1 | Feature: Get platform at a given point in time 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: get the detail of an existing platform at a specific time in the past 7 | Given an existing module with properties 8 | And an existing platform with this module and valued properties 9 | When I update this platform, removing this module 10 | And I get the platform detail at a specific time in the past 11 | Then the initial platform detail is successfully retrieved 12 | 13 | Scenario: get the detail of an existing platform at a time where it did not exist 14 | Given an existing module with properties 15 | And an existing platform with this module and valued properties 16 | When I try to get the platform detail at the time of the EPOCH 17 | Then the resource is not found 18 | 19 | Scenario: get properties of a platform with valued properties at a specific time in the past 20 | Given an existing module with properties 21 | And an existing platform with this module and valued properties 22 | When I update the properties 23 | And I get the platform properties for this module at a specific time in the past 24 | Then the initial platform properties are successfully retrieved 25 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/platforms/get-platforms-using-module.feature: -------------------------------------------------------------------------------- 1 | Feature: Get platforms using module 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: get platforms using the same module 7 | Given an existing module 8 | And an existing platform named "P1" with this module 9 | And an existing platform named "P2" with this module 10 | When I get the platforms using this module 11 | Then the platforms using this module are successfully retrieved 12 | 13 | #issue-685 14 | Scenario: get platforms using module with modules with the same name or the same version 15 | Given an existing module named "module-a" with version "1" 16 | And an existing platform named "P1" with this module 17 | And an existing module named "module-a" with version "2" 18 | And an existing platform named "P2" with this module 19 | And an existing module named "module-b" with version "1" 20 | And an existing platform named "P3" with this module 21 | When I get the platforms using this module 22 | Then 1 platform is retrieved 23 | 24 | #issue-765 25 | Scenario: get platforms using a module that was removed from a platform 26 | Given an existing module 27 | And an existing platform with this module 28 | And I update this platform, clearing the modules 29 | When I get the platforms using this module 30 | Then 0 platforms are retrieved -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/platforms/restore-platforms.feature: -------------------------------------------------------------------------------- 1 | Feature: Restore platforms 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: restore a deleted platform 7 | Given an existing module with properties and global properties 8 | And an existing platform with this module and an instance and valued properties and global properties and instance properties 9 | When I delete and restore this platform 10 | Then the platform is successfully restored with its properties and everything 11 | 12 | Scenario: update a restored platform 13 | Given an existing platform 14 | And I delete and restore this platform 15 | When I update this platform 16 | Then the platform is successfully updated 17 | 18 | Scenario: restore an existing platform 19 | Given an existing platform 20 | When I try to restore this platform 21 | Then the request is rejected with a bad request error 22 | 23 | @require-real-mongo 24 | Scenario: restore a deleted platform with a different letter case 25 | Given an existing module with properties and global properties 26 | And an existing platform with this module and an instance and valued properties and global properties and instance properties 27 | When I delete and restore this platform with the wrong letter case 28 | Then the platform is successfully restored with its properties and everything 29 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/technos/copy-technos.feature: -------------------------------------------------------------------------------- 1 | Feature: Copy technos 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: copy an existing techno 7 | Given an existing techno with properties 8 | When I create a copy of this techno 9 | Then the techno is successfully duplicated 10 | And the model of the techno is the same 11 | 12 | Scenario: copy a released techno 13 | Given an existing released techno with properties 14 | When I create a copy of this techno 15 | Then the techno is successfully duplicated 16 | 17 | Scenario: copy a techno that doesn't exist 18 | Given a techno that doesn't exist 19 | When I try to create a copy of this techno 20 | Then the techno copy is rejected with a not found error 21 | 22 | Scenario: copy a techno with the same key 23 | Given an existing techno 24 | When I try to create a copy of this techno, using the same key 25 | Then the techno copy is rejected with a conflict error 26 | 27 | Scenario: copy a released techno with the same key 28 | Given an existing released techno 29 | When I try to create a copy of this techno, using the same key 30 | Then the techno copy is rejected with a conflict error 31 | 32 | #issue-828 33 | Scenario: copy a techno and specify an empty name 34 | When I try to create a copy of a techno, using an empty name 35 | Then the request is rejected with a bad request error 36 | 37 | #issue-828 38 | Scenario: copy a techno and specify an empty version 39 | When I try to create a copy of a techno, using an empty version 40 | Then the request is rejected with a bad request error 41 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/technos/create-technos.feature: -------------------------------------------------------------------------------- 1 | Feature: Create technos 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: create a new techno 7 | Given a techno to create 8 | When I create this techno 9 | Then the techno is successfully created 10 | 11 | Scenario: create a techno that already exists 12 | Given an existing techno 13 | And a techno to create with the same name and version 14 | When I try to create this techno 15 | Then the techno creation is rejected with a conflict error 16 | 17 | @require-real-mongo 18 | Scenario: forbid creation of a techno with a same name but different letter case 19 | Given an existing techno 20 | And a techno to create with the same name and version but different letter case 21 | When I try to create this techno 22 | Then the techno creation is rejected with a conflict error 23 | 24 | Scenario: create a techno after it has been deleted 25 | Given an existing techno 26 | When I delete this techno 27 | And I create this techno 28 | Then the techno is successfully created 29 | 30 | Scenario: trying to create a techno more than once at the same time should fail for one of them 31 | Given a techno to create 32 | When I try to create this techno more than once at the same time 33 | Then only one techno creation is successful 34 | But the techno is actually created 35 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/technos/delete-technos.feature: -------------------------------------------------------------------------------- 1 | Feature: Delete technos 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: delete an existing techno 7 | Given an existing techno 8 | When I delete this techno 9 | Then the techno is successfully deleted 10 | 11 | Scenario: delete a released techno 12 | Given an existing released techno 13 | When I delete this techno 14 | Then the techno is successfully deleted 15 | 16 | Scenario: delete a techno that doesn't exist 17 | Given a techno that doesn't exist 18 | When I try to delete this techno 19 | Then the techno deletion is rejected with a not found error 20 | 21 | Scenario: delete a techno with its templates 22 | Given an existing techno 23 | When I delete this techno 24 | Then this techno templates are also deleted 25 | 26 | Scenario: delete a techno in use by a module 27 | Given an existing techno 28 | And an existing module with this techno 29 | When I try to delete this techno 30 | Then the techno deletion is rejected with a conflict error 31 | 32 | Scenario: delete an existing techno used by a deleted module 33 | Given an existing techno 34 | And an existing module with this techno 35 | When I delete this module 36 | And the module is successfully deleted 37 | And I delete this techno 38 | Then the techno is successfully deleted 39 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/technos/get-technos-name.feature: -------------------------------------------------------------------------------- 1 | Feature: Get technos names 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: get a list of all the technos names 7 | Given a list of 12 technos with different names 8 | When I get the technos name 9 | Then a list of 12 elements is returned 10 | 11 | Scenario: get a list of all the technos name 12 | Given a list of 12 technos with the same name 13 | When I get the technos name 14 | Then a list of 1 element is returned -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/technos/get-technos-types.feature: -------------------------------------------------------------------------------- 1 | Feature: Get technos type 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: get the types of a released techno 7 | Given an existing released techno 8 | When I get the techno types 9 | Then a list containing workingcopy and release is returned 10 | 11 | Scenario: get the types of a techno that is not released 12 | Given an existing techno 13 | When I get the techno types 14 | Then a list containing workingcopy is returned 15 | 16 | Scenario: get the types of a techno that doesn't exist 17 | Given a techno that doesn't exist 18 | When I get the techno types 19 | Then an empty list is returned -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/technos/get-technos-versions.feature: -------------------------------------------------------------------------------- 1 | Feature: Get technos versions 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: get the list of versions of an existing techno 7 | Given a techno with 4 versions 8 | When I get the techno versions 9 | Then a list of 4 elements is returned 10 | 11 | Scenario: get the list of versions of a techno that doesn't exist 12 | Given a techno that doesn't exist 13 | When I get the techno versions 14 | Then a list of 0 elements is returned -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/technos/get-technos.feature: -------------------------------------------------------------------------------- 1 | Feature: Get technos details 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: get the detail of an existing techno 7 | Given an existing techno 8 | When I get the techno detail 9 | Then the techno detail is successfully retrieved 10 | 11 | @require-real-mongo 12 | Scenario: get the detail of an existing techno with the wrong letter case 13 | Given an existing techno 14 | When I get the techno detail with the wrong letter case 15 | Then the techno detail is successfully retrieved 16 | 17 | Scenario: get the detail of a released techno 18 | Given an existing released techno 19 | When I get the techno detail 20 | Then the techno detail is successfully retrieved 21 | 22 | Scenario: get the detail of the working copy of a techno that doesn't exist 23 | Given a techno that doesn't exist 24 | When I try to get the techno detail 25 | Then the resource is not found 26 | 27 | Scenario: get the detail of a released techno that only exist as working copy 28 | Given an existing techno 29 | When I try to get the techno detail for a techno type "release" 30 | Then the resource is not found 31 | 32 | Scenario: get the detail of a techno with an invalid techno type 33 | Given an existing techno 34 | When I try to get the techno detail for a techno type "unknown" 35 | Then the request is rejected with a bad request error 36 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/technos/release-technos.feature: -------------------------------------------------------------------------------- 1 | Feature: Release technos 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: release an existing techno 7 | Given an existing techno 8 | When I release this techno 9 | Then the techno is successfully released 10 | 11 | Scenario: release a techno that doesn't exist 12 | Given a techno that doesn't exist 13 | When I try to release this techno 14 | Then the techno release is rejected with a not found error 15 | 16 | Scenario: release a techno with an existing key 17 | Given an existing techno 18 | When I release this techno 19 | And I try to release this techno 20 | Then the techno release is rejected with a conflict error 21 | 22 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/technos/search-technos.feature: -------------------------------------------------------------------------------- 1 | Feature: Search technos 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: search for an existing techno 7 | Given a list of 12 technos 8 | When I search for one specific techno 9 | Then the techno is found 10 | 11 | Scenario: search for existing technos 12 | Given a list of 12 technos 13 | When I search for some of these technos 14 | Then the list of techno results is limited to 10 items 15 | 16 | Scenario: search for a techno that does not exist 17 | Given a list of 12 technos 18 | When I search for a techno that does not exist 19 | Then an empty list is returned 20 | 21 | Scenario: search for a limited number of existing technos 22 | Given a list of 12 technos 23 | When I search for some of these technos, limiting the number of results to 100 24 | Then the list of techno results is limited to 12 items 25 | 26 | #issue-863 27 | Scenario: search for an existing techno using the wrong case 28 | Given an existing techno named "aTechno" 29 | When I search for the techno named "ATECHNO" 30 | Then the techno is found 31 | 32 | #issue-863 33 | Scenario: search for an existing techno using the wrong case again 34 | Given an existing techno named "aTechno" 35 | When I search for the techno named "atechno" 36 | Then the techno is found 37 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/technos/templates/delete-techno-templates.feature: -------------------------------------------------------------------------------- 1 | Feature: Delete techno templates 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: delete an existing template in a techno 7 | Given an existing techno 8 | When I delete this techno template 9 | Then the techno template is successfully deleted 10 | 11 | Scenario: delete an existing template in a released techno 12 | Given an existing released techno 13 | When I try to delete this techno template 14 | Then the techno template delete is rejected with a method not allowed error 15 | 16 | Scenario: delete a template that doesn't exist in a techno 17 | Given an existing techno 18 | And a template that doesn't exist in this techno 19 | When I try to delete this techno template 20 | Then the techno template delete is rejected with a not found error 21 | 22 | Scenario: delete a template of a techno that doesn't exist 23 | Given a techno that doesn't exist 24 | When I try to delete this techno template 25 | Then the techno template delete is rejected with a not found error 26 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/technos/templates/get-techno-templates.feature: -------------------------------------------------------------------------------- 1 | Feature: Get techno templates 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: get the list of templates of an existing techno 7 | Given an existing techno 8 | And multiple templates in this techno 9 | When I get the list of templates of this techno 10 | Then a list of all the templates of the techno is returned 11 | 12 | Scenario: get the list of templates of a released techno 13 | Given an existing techno 14 | And multiple templates in this techno 15 | And I release this techno 16 | When I get the list of templates of this techno 17 | Then a list of all the templates of the techno is returned 18 | 19 | Scenario: get a template of a techno 20 | Given an existing techno 21 | And a template in this techno 22 | When I get this template in this techno 23 | Then the techno template is successfully returned 24 | 25 | Scenario: get a template that doesn't exist in a a techno 26 | Given an existing techno 27 | And a template that doesn't exist in this techno 28 | When I try to get this template in this techno 29 | Then the resource is not found 30 | 31 | Scenario: get the list of templates of a techno that doesn't exist 32 | Given a techno that doesn't exist 33 | When I get the list of templates of this techno 34 | Then an empty list is returned 35 | 36 | Scenario: get a template of a techno that doesn't exist 37 | Given a techno that doesn't exist 38 | When I try to get this template in this techno 39 | Then the resource is not found 40 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/users/get-any-user-information.feature: -------------------------------------------------------------------------------- 1 | @require-real-ad 2 | Feature: Get any user information 3 | 4 | Scenario: get another user information 5 | Given an authenticated lambda user 6 | When I get user information about another prod user 7 | Then user information is returned, without tech role and with prod role 8 | 9 | Scenario: get a non-existing user information 10 | Given an authenticated lambda user 11 | When I get user information about a non-existing user 12 | Then the resource is not found 13 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/users/get-logged-user-information.feature: -------------------------------------------------------------------------------- 1 | @auth-related 2 | Feature: Get current user info information 3 | 4 | Scenario: get current user info information for a tech user 5 | Given an authenticated lambda user 6 | When I get the current user information 7 | Then user information is returned, without tech role and without prod role 8 | 9 | Scenario: get current user info information for a prod user 10 | Given an authenticated prod user 11 | When I get the current user information 12 | Then user information is returned, without tech role and with prod role 13 | 14 | Scenario: current user info provides no credentials 15 | When I try to get the current user information 16 | Then the request is rejected with an unauthorized error 17 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/users/user-logout.feature: -------------------------------------------------------------------------------- 1 | Feature: User logout 2 | 3 | Scenario: a user logout from a browser 4 | Given a known lambda user 5 | When the user log out 6 | Then the request is rejected with an unauthorized error 7 | When the user re-send valid credentials 8 | Then login is successful 9 | -------------------------------------------------------------------------------- /tests/bdd/src/test/resources/versions/get-application-version.feature: -------------------------------------------------------------------------------- 1 | Feature: Get application version 2 | 3 | Background: 4 | Given an authenticated user 5 | 6 | Scenario: get backend and api version 7 | When I get the application versions 8 | Then the versions are returned -------------------------------------------------------------------------------- /tests/mongo-integration/README.md: -------------------------------------------------------------------------------- 1 | Those tests require a real MongoDB instance **and** an external Hesperides instance to connect to. 2 | 3 | They use the BDD _features_ defined in the `tests/bdd` module. 4 | 5 | ## Execution 6 | 7 | mvn verify -pl tests/mongo-integration -Dexec.mainClass=org.hesperides.test.mongo_integration.CucumberMongoIntegTests \ 8 | -Dmongo-integration.remote-base-url=http://localhost:8080/rest \ 9 | -Dauth.lambdaUserName=... -Dauth.lambdaUserPassword=... \ 10 | [-Dmongo-integration.proxy-host=... -Dmongo-integration.proxy-port=...] 11 | -------------------------------------------------------------------------------- /tests/mongo-integration/src/test/java/org/hesperides/test/mongo_integration/config/IntegTestConfig.java: -------------------------------------------------------------------------------- 1 | package org.hesperides.test.mongo_integration.config; 2 | 3 | import org.hesperides.core.infrastructure.axon.AxonConfiguration; 4 | import org.springframework.context.annotation.ComponentScan; 5 | import org.springframework.context.annotation.FilterType; 6 | import org.springframework.context.annotation.PropertySource; 7 | import org.springframework.stereotype.Component; 8 | 9 | import static org.springframework.context.annotation.ComponentScan.Filter; 10 | 11 | @Component 12 | @PropertySource("application-test.yml") 13 | @ComponentScan(basePackages = {"org.hesperides.test.bdd"}) 14 | @ComponentScan(basePackages = {"org.hesperides.core.infrastructure.mongo"}, 15 | excludeFilters = {@Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {AxonConfiguration.class})}) 16 | @ComponentScan(basePackages = {"org.hesperides.commons"}) 17 | public class IntegTestConfig { 18 | } 19 | -------------------------------------------------------------------------------- /tests/mongo-integration/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | mongo-integration.remote-base-url: http://localhost:8080/rest 2 | mongo.uri: mongodb://localhost:27017/hesperides 3 | 4 | logging.level: 5 | org: 6 | hesperides: 7 | core.domain: 8 | templatecontainers.entities.AbstractProperty: INFO 9 | modules.commands.ModuleAggregate: INFO 10 | platforms.commands.PlatformAggregate: INFO 11 | test.bdd.commons.DebuggableRestTemplate: INFO 12 | springframework: 13 | data.mongodb.core.MongoTemplate: INFO 14 | mongodb.driver.protocol.command: INFO -------------------------------------------------------------------------------- /tests/mongo-integration/src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /tests/perfs/README.md: -------------------------------------------------------------------------------- 1 | # Stress testing scenarios for Hesperides API 2 | 3 | ## Utilisation 4 | 5 | mvn gatling:test -Pgatling -Dgatling.simulationClass=HesperidesApi -Dduration=20seconds -Dpercentile99ResponseTimeMax=12000 6 | 7 | ## Options 8 | 9 | -DbaseUrl=http://localhost:8080/rest URL du serveur à tester 10 | -Dauth=tech:password Identifiants de connexion 11 | -DusersPerSecond=5 Nombre d'utilisateurs à injecter par seconde 12 | -Dduration=60seconds Durée de la simulation 13 | -DpercentOkMin=99 % d'appels qui doivent être OK pour que le test soit un succès 14 | -Dpercentile99ResponseTimeMax=5000 temps de réponse max acceptable pour l'ensemble des 1% des requêtes les plus lentes 15 | -Dverbose=true Activation des io sur certains appels 16 | 17 | ## Trace 18 | Pour avoir les log des requests, modifier le `resources/logback.xml` 19 | 20 | 21 | 22 | 23 | 24 | 25 | Les log sont envoyés sur la sortie standard (appender file pas activé) 26 | -------------------------------------------------------------------------------- /tests/perfs/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | %d{HH:mm:ss.SSS} [%-5level] %logger{15} - %msg%n%rEx 7 | false 8 | 9 | 10 | 11 | 12 | target/log_gatling.log 13 | 14 | 15 | target/log_gatling.%d{yyyy-MM-dd-HH-mm}.log 16 | 30 17 | 18 | 19 | true 20 | 21 | %-4relative [%thread] %-5level %logger{35} - %msg%n 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/perfs/src/test/scala/HesperidesApi.scala: -------------------------------------------------------------------------------- 1 | import _root_.scenario.Generic 2 | import conf.Config 3 | import io.gatling.core.Predef.{Simulation, _} 4 | 5 | class HesperidesApi extends Simulation { 6 | setUp( 7 | Generic.modules.inject(constantUsersPerSec(Config.defaultUserPerSeconds) during Config.duration).protocols(Config.httpConf), 8 | Generic.platforms.inject(constantUsersPerSec(Config.defaultUserPerSeconds) during Config.duration).protocols(Config.httpConf) 9 | ).assertions( 10 | global.successfulRequests.percent.gt(Config.percentOkMin), 11 | global.responseTime.percentile4.lt(Config.percentile99ResponseTimeMax) 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /tests/perfs/src/test/scala/conf/Config.scala: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import java.lang.System._ 4 | 5 | import io.gatling.core.Predef._ 6 | import io.gatling.http.Predef._ 7 | 8 | import scala.concurrent.duration.{Duration, FiniteDuration} 9 | 10 | object Config { 11 | 12 | val baseUrl = getProperty("baseUrl", "http://localhost:8080/rest") 13 | val defaultUserPerSeconds = Integer.getInteger("usersPerSecond", 5).toInt 14 | val duration = Duration.create(getProperty("duration", "60seconds")).asInstanceOf[FiniteDuration] 15 | val percentOkMin = Integer.getInteger("percentOkMin", 99).toInt 16 | val percentile99ResponseTimeMax = Integer.getInteger("percentile99ResponseTimeMax", 5000).toInt 17 | val auth = getProperty("auth", "tech:password").split(":") 18 | 19 | val httpConf = http 20 | .baseUrl(baseUrl) 21 | .userAgentHeader("Gatling") 22 | .basicAuth(auth(0), auth(1)) 23 | .disableCaching 24 | 25 | } 26 | -------------------------------------------------------------------------------- /tests/perfs/src/test/scala/feeder/Feeders.scala: -------------------------------------------------------------------------------- 1 | package feeder 2 | 3 | import scala.util.Random 4 | 5 | object Feeders { 6 | val moduleName = Iterator.continually(Map("moduleName" -> Random.alphanumeric.take(20).mkString)) 7 | val moduleVersion = Iterator.continually(Map("moduleVersion" -> s"${Random.nextInt(10)}.${Random.nextInt(10)}.${Random.nextInt(10)}")) 8 | val modulePath = Iterator.continually(Map("modulePath" -> s"${Random.alphanumeric.take(3).mkString.toUpperCase()}")) 9 | val templateName = Iterator.continually(Map("templateName" -> s"${Random.alphanumeric.take(10).mkString}.${Random.alphanumeric.take(3).mkString}")) 10 | val templateDir = Iterator.continually(Map("templateDir" -> s"${Random.alphanumeric.take(3).mkString}/${Random.alphanumeric.take(3).mkString}/${Random.alphanumeric.take(6).mkString}")) 11 | val templateContent = Iterator.continually(Map("templateContent" -> s"${Random.alphanumeric.take(100).mkString}")) 12 | val applicationName = Iterator.continually(Map("applicationName" -> Random.alphanumeric.take(3).mkString.toUpperCase())) 13 | val applicationVersion = Iterator.continually(Map("applicationVersion" -> s"${Random.nextInt(10)}.${Random.nextInt(10)}.${Random.nextInt(10)}")) 14 | val platformName = Iterator.continually(Map("platformName" -> s"${Random.alphanumeric.take(3).mkString.toUpperCase()}")) 15 | val propertyName = Iterator.continually(Map("propertyName" -> s"${Random.alphanumeric.take(10).mkString}")) 16 | val propertyValue = Iterator.continually(Map("propertyValue" -> s"${Random.alphanumeric.take(4).mkString}")) 17 | } 18 | -------------------------------------------------------------------------------- /tests/perfs/src/test/scala/process/Events.scala: -------------------------------------------------------------------------------- 1 | package process 2 | 3 | import io.gatling.core.Predef._ 4 | import io.gatling.http.Predef._ 5 | 6 | object Events { 7 | 8 | val getModules = exec(http("getModuleEvents") 9 | .get("/events/modules/${moduleName}/${moduleVersion}/workingcopy") 10 | .check(status.is(200))) 11 | 12 | val getLegacyModules = exec(http("getLegacyModuleEvents") 13 | .get("/events/module-${moduleName}-${moduleVersion}-wc") 14 | .check(status.is(200))) 15 | 16 | val getPlatforms = exec(http("getPlatformEvents") 17 | .get("/events/platforms/${applicationName}/${platformName}") 18 | .check(status.is(200))) 19 | 20 | val getLegacyPlatforms = exec(http("getLegacyPlatformEvents") 21 | .get("/events/platform-${applicationName}-${platformName}") 22 | .check(status.is(200))) 23 | } 24 | -------------------------------------------------------------------------------- /tests/perfs/src/test/scala/process/Modules.scala: -------------------------------------------------------------------------------- 1 | package process 2 | 3 | import io.gatling.core.Predef._ 4 | import io.gatling.http.Predef._ 5 | 6 | object Modules { 7 | 8 | val create = exec(http("createWorkingcopyModule") 9 | .post("/modules") 10 | .body(StringBody( 11 | """{ 12 | "name": "${moduleName}", 13 | "version": "${moduleVersion}", 14 | "working_copy": true, 15 | "technos": [], 16 | "version_id": 0 17 | }""")).asJson 18 | .check(status.is(201))) 19 | 20 | val addTemplate = exec(http("addTemplateToModule") 21 | .post("/modules/${moduleName}/${moduleVersion}/workingcopy/templates") 22 | .body(StringBody( 23 | """{ 24 | "name": "${templateName}", 25 | "filename": "${templateName}", 26 | "location": "${templateDir}", 27 | "content": "${templateContent}{{${propertyName}}}${templateContent}", 28 | "rights": {}, 29 | "version_id": 0 30 | }""")).asJson 31 | .check(status.is(201))) 32 | 33 | val get = exec(http("getWorkingcopyModule") 34 | .get("/modules/${moduleName}/${moduleVersion}/workingcopy") 35 | .check(status.is(200))) 36 | 37 | val getNotFound = exec(http("getWorkingcopyModule") 38 | .get("/modules/${moduleName}/${moduleVersion}/workingcopy") 39 | .check(status.is(404))) 40 | 41 | val getModel = exec(http("getWorkingcopyModuleModel") 42 | .get("/modules/${moduleName}/${moduleVersion}/workingcopy/model") 43 | .check(status.is(200))) 44 | 45 | val delete = exec(http("deleteWorkingcopyModule") 46 | .delete("/modules/${moduleName}/${moduleVersion}/workingcopy") 47 | .check(status.is(200))) 48 | } 49 | -------------------------------------------------------------------------------- /tests/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | org.hesperides 8 | hesperides 9 | 4.3-SNAPSHOT 10 | 11 | 12 | 4.0.0 13 | org.hesperides.test 14 | tests 15 | pom 16 | 17 | 18 | activedirectory-integration 19 | bdd 20 | mongo-integration 21 | perfs 22 | regression 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/regression/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | org.hesperides.test 8 | tests 9 | 4.3-SNAPSHOT 10 | 11 | 12 | 4.0.0 13 | regression 14 | 15 | 16 | 17 | 18 | org.hesperides 19 | presentation 20 | test 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | test 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-test 30 | test 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-test-autoconfigure 35 | test 36 | 37 | 38 | com.google.code.gson 39 | gson 40 | test 41 | 42 | 43 | -------------------------------------------------------------------------------- /tests/regression/src/test/java/org/hesperides/test/regression/errors/AbstractError.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.test.regression.errors; 22 | 23 | import lombok.Value; 24 | import lombok.experimental.NonFinal; 25 | import lombok.extern.slf4j.Slf4j; 26 | 27 | @Value 28 | @NonFinal 29 | @Slf4j 30 | public abstract class AbstractError { 31 | 32 | String entityKey; 33 | String latestUri; 34 | String testingUri; 35 | String message; 36 | 37 | protected void log(String errorType) { 38 | log.warn(""); 39 | log.warn("****** {} ******", errorType); 40 | log.warn("Latest url: " + latestUri); 41 | log.warn("Testing url: " + testingUri); 42 | log.warn(message); 43 | log.warn(""); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/regression/src/test/java/org/hesperides/test/regression/errors/Diff.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.test.regression.errors; 22 | 23 | import lombok.EqualsAndHashCode; 24 | import lombok.Value; 25 | 26 | @Value 27 | @EqualsAndHashCode(callSuper = true) 28 | public class Diff extends AbstractError { 29 | 30 | public Diff(String entityKey, String latestUri, String testingUri, String message) { 31 | super(entityKey, latestUri, testingUri, message); 32 | } 33 | } -------------------------------------------------------------------------------- /tests/regression/src/test/java/org/hesperides/test/regression/errors/UnexpectedException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file is part of the Hesperides distribution. 4 | * (https://github.com/voyages-sncf-technologies/hesperides) 5 | * Copyright (c) 2016 VSCT. 6 | * 7 | * Hesperides is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation, version 3. 10 | * 11 | * Hesperides is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * 20 | */ 21 | package org.hesperides.test.regression.errors; 22 | 23 | import lombok.EqualsAndHashCode; 24 | import lombok.Value; 25 | import org.apache.commons.lang3.StringUtils; 26 | 27 | @Value 28 | @EqualsAndHashCode(callSuper = true) 29 | public class UnexpectedException extends AbstractError { 30 | 31 | public UnexpectedException(String entityKey, String latestUri, String testingUri, Throwable throwable) { 32 | super(entityKey, latestUri, testingUri, StringUtils.defaultString(throwable.getMessage(), throwable.toString())); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/regression/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | regressionTest: 2 | logWhileTesting: ${REGRESSIONTEST_LOGWHILETESTING:false} 3 | validate: 4 | technos: ${REGRESSIONTEST_VALIDATE_TECHNOS:true} 5 | modules: ${REGRESSIONTEST_VALIDATE_MODULES:true} 6 | platforms: ${REGRESSIONTEST_VALIDATE_PLATFORMS:true} 7 | username: ${REGRESSIONTEST_USERNAME} 8 | password: ${REGRESSIONTEST_PASSWORD} 9 | latest.url: ${REGRESSIONTEST_LATEST_URL} 10 | testing.url: ${REGRESSIONTEST_TESTING_URL} 11 | -------------------------------------------------------------------------------- /tests/regression/src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | --------------------------------------------------------------------------------