From c7162bd95a1ded8f57c1fbba341fdb8f327afa61 Mon Sep 17 00:00:00 2001 From: "@inaki.etxaniz" <inaki.etxaniz@tecnalia.com> Date: Tue, 30 May 2023 18:47:43 +0200 Subject: [PATCH] year 3 version --- .env | 29 +- .env.build | 26 -- .env.gen | 87 ++++++ .env.int | 31 -- .env.local | 12 + .env.piacere | 14 + .env.release | 13 + .gitlab-ci.yml | 170 +++++++---- .gitmodules | 6 +- LICENSE | 201 ------------- build/docker-compose-iec.yaml | 24 -- build/docker-compose.yaml | 25 ++ build/image/docker-compose.yaml | 9 + build/inline-cache/docker-compose.yaml | 15 + .../central-config}/iec/application.yml | 0 .../central-config}/iec/iecBackend.yml | 0 .../central-config}/iec/iecFrontend.yml | 0 development-services | 1 - doc/scenarios/.gitkeep | 0 doc/scenarios/KR-9-IEC.feature | 20 ++ ...alElementsCatalogue-SequenceDiagram.Y2.png | Bin 0 -> 55009 bytes .../53-InfrastructuralElementsCatalogue.puml | 41 +-- docker-compose-artifactory.yaml | 14 + ...ose.yaml => docker-compose-dev-expose.yaml | 9 +- docker-compose-expose.yaml | 6 - docker-compose-jhipster-network-external.yaml | 4 + docker-compose-jhipster-registry-volumes.yaml | 5 + docker-compose-redirect-http.yaml | 14 - docker-compose-traefik-aliases.yaml | 6 + docker-compose-traefik-network-external.yaml | 4 + docker-compose-traefik-network-internal.yaml | 3 + docker-compose-traefik-selfsigned.yaml | 30 -- ...er-compose-iec.yaml => docker-compose.yaml | 34 +-- .../backend/config/DatabaseConfiguration.java | 4 - .../backend/config/SecurityConfiguration.java | 10 +- .../iec/backend/config/WebConfigurer.java | 8 +- .../iec/backend/domain/ExistingResource.java | 240 +++++++++++++++ .../com/piacere/iec/backend/domain/Image.java | 213 ++++++++++++++ .../backend/domain/enumeration/ImageType.java | 35 +++ .../ExistingResourceRepository.java | 17 ++ .../backend/repository/ImageRepository.java | 15 + .../service/ExistingResourceQueryService.java | 122 ++++++++ .../service/ExistingResourceService.java | 52 ++++ .../backend/service/ImageQueryService.java | 118 ++++++++ .../iec/backend/service/ImageService.java | 52 ++++ .../criteria/ExistingResourceCriteria.java | 259 +++++++++++++++++ .../service/criteria/ImageCriteria.java | 239 +++++++++++++++ .../service/dto/ExistingResourceDTO.java | 177 +++++++++++ .../iec/backend/service/dto/ImageDTO.java | 160 ++++++++++ .../service/dto/ServiceAttributeValueDTO.java | 4 +- .../impl/ExistingResourceServiceImpl.java | 80 +++++ .../service/impl/ImageServiceImpl.java | 80 +++++ .../mapper/ExistingResourceMapper.java | 18 ++ .../backend/service/mapper/ImageMapper.java | 22 ++ .../iec/backend/util/CollectionUtil.java | 64 ++++ .../web/rest/ExistingResourceResource.java | 180 ++++++++++++ .../iec/backend/web/rest/ImageResource.java | 183 ++++++++++++ .../backend/web/rest/InstanceResource.java | 2 +- .../backend/web/rest/RootServiceResource.java | 39 ++- .../web/rest/ServiceClassResource.java | 114 -------- .../src/main/resources/config/application.yml | 2 +- ...15090119_added_entity_ExistingResource.xml | 80 +++++ .../20230403121800_added_entity_Image.xml | 77 +++++ .../resources/config/liquibase/master.xml | 3 + git/iec-frontend/iec-frontend.png | Bin 65205 -> 65147 bytes .../src/main/webapp/app/app.constants.ts | 3 + .../app/entities/entity-routing.module.ts | 10 + ...ting-resource-delete-dialog.component.html | 29 ++ ...g-resource-delete-dialog.component.spec.ts | 64 ++++ ...isting-resource-delete-dialog.component.ts | 24 ++ .../existing-resource-detail.component.html | 29 ++ ...existing-resource-detail.component.spec.ts | 38 +++ .../existing-resource-detail.component.ts | 24 ++ .../existing-resource.model.ts | 33 +++ .../existing-resource.module.ts | 15 + .../list/existing-resource.component.html | 119 ++++++++ .../list/existing-resource.component.spec.ts | 100 +++++++ .../list/existing-resource.component.ts | 117 ++++++++ ...g-resource-routing-resolve.service.spec.ts | 82 ++++++ ...isting-resource-routing-resolve.service.ts | 30 ++ .../route/existing-resource-routing.module.ts | 41 +++ .../service/existing-resource.service.spec.ts | 203 +++++++++++++ .../service/existing-resource.service.ts | 101 +++++++ .../existing-resource-update.component.html | 113 +++++++ ...existing-resource-update.component.spec.ts | 120 ++++++++ .../existing-resource-update.component.ts | 121 ++++++++ .../image/detail/image-detail.component.html | 24 ++ .../detail/image-detail.component.spec.ts | 38 +++ .../image/detail/image-detail.component.ts | 31 ++ .../entities/iecBackend/image/image.model.ts | 31 ++ .../entities/iecBackend/image/image.module.ts | 12 + .../image/list/image.component.html | 94 ++++++ .../image/list/image.component.spec.ts | 100 +++++++ .../iecBackend/image/list/image.component.ts | 105 +++++++ .../image-routing-resolve.service.spec.ts | 82 ++++++ .../route/image-routing-resolve.service.ts | 30 ++ .../image/route/image-routing.module.ts | 32 ++ .../image/service/image.service.spec.ts | 203 +++++++++++++ .../iecBackend/image/service/image.service.ts | 83 ++++++ .../detail/root-service-detail.component.ts | 11 + .../app/layouts/navbar/navbar.component.html | 16 + .../src/main/webapp/i18n/en/global.json | 2 + .../i18n/en/iecBackendExistingResource.json | 39 +++ .../main/webapp/i18n/en/iecBackendImage.json | 38 +++ .../src/main/webapp/i18n/es/global.json | 2 + .../i18n/es/iecBackendExistingResource.json | 39 +++ .../main/webapp/i18n/es/iecBackendImage.json | 38 +++ .../startupscripts/02_createTables.sql | 46 +++ .../startupscripts/03_initialData.sql | 275 ++++++++++++++++-- git/jhipster-registry/.env | 7 + git/jhipster-registry/.env.gen | 44 +++ git/jhipster-registry/.env.local | 35 +++ git/jhipster-registry/.gitmodules | 0 git/jhipster-registry/README.md | 31 ++ .../jhipster-registry}/application.yml | 0 .../jhipster-registry/jhipster-registry.yml | 2 +- .../docker-compose-dev-expose.yaml | 4 + .../jhipster-registry/docker-compose-dev.yaml | 10 +- .../docker-compose-heathcheck-kill.yaml | 10 + .../docker-compose-oidc.yaml | 8 + .../docker-compose-tecnalia-ca.yaml | 7 + .../docker-compose-traefik-aliases.yaml | 6 + ...cker-compose-traefik-network-external.yaml | 4 + .../docker-compose-volumes.yaml | 4 + .../jhipster-registry/docker-compose.yaml | 19 +- piacere-build/docker-compose.yaml | 34 +++ release/docker-compose.yaml | 9 + 127 files changed, 5901 insertions(+), 642 deletions(-) delete mode 100755 .env.build create mode 100644 .env.gen delete mode 100755 .env.int create mode 100644 .env.local create mode 100644 .env.piacere create mode 100644 .env.release delete mode 100644 LICENSE delete mode 100755 build/docker-compose-iec.yaml create mode 100644 build/docker-compose.yaml create mode 100644 build/image/docker-compose.yaml create mode 100644 build/inline-cache/docker-compose.yaml rename {central-config => data/jhipster-registry/central-config}/iec/application.yml (100%) mode change 100755 => 100644 rename {central-config => data/jhipster-registry/central-config}/iec/iecBackend.yml (100%) mode change 100755 => 100644 rename {central-config => data/jhipster-registry/central-config}/iec/iecFrontend.yml (100%) mode change 100755 => 100644 delete mode 160000 development-services create mode 100644 doc/scenarios/.gitkeep create mode 100644 doc/scenarios/KR-9-IEC.feature create mode 100644 doc/sequence-diagrams/53-InfrastructuralElementsCatalogue-SequenceDiagram.Y2.png create mode 100644 docker-compose-artifactory.yaml rename docker-compose-iec-dev-expose.yaml => docker-compose-dev-expose.yaml (52%) mode change 100755 => 100644 delete mode 100644 docker-compose-expose.yaml create mode 100644 docker-compose-jhipster-network-external.yaml create mode 100644 docker-compose-jhipster-registry-volumes.yaml delete mode 100755 docker-compose-redirect-http.yaml create mode 100644 docker-compose-traefik-aliases.yaml create mode 100644 docker-compose-traefik-network-external.yaml create mode 100644 docker-compose-traefik-network-internal.yaml delete mode 100755 docker-compose-traefik-selfsigned.yaml rename docker-compose-iec.yaml => docker-compose.yaml (70%) mode change 100755 => 100644 create mode 100644 git/iec-backend/src/main/java/com/piacere/iec/backend/domain/ExistingResource.java create mode 100644 git/iec-backend/src/main/java/com/piacere/iec/backend/domain/Image.java create mode 100644 git/iec-backend/src/main/java/com/piacere/iec/backend/domain/enumeration/ImageType.java create mode 100644 git/iec-backend/src/main/java/com/piacere/iec/backend/repository/ExistingResourceRepository.java create mode 100644 git/iec-backend/src/main/java/com/piacere/iec/backend/repository/ImageRepository.java create mode 100644 git/iec-backend/src/main/java/com/piacere/iec/backend/service/ExistingResourceQueryService.java create mode 100644 git/iec-backend/src/main/java/com/piacere/iec/backend/service/ExistingResourceService.java create mode 100644 git/iec-backend/src/main/java/com/piacere/iec/backend/service/ImageQueryService.java create mode 100644 git/iec-backend/src/main/java/com/piacere/iec/backend/service/ImageService.java create mode 100644 git/iec-backend/src/main/java/com/piacere/iec/backend/service/criteria/ExistingResourceCriteria.java create mode 100644 git/iec-backend/src/main/java/com/piacere/iec/backend/service/criteria/ImageCriteria.java create mode 100644 git/iec-backend/src/main/java/com/piacere/iec/backend/service/dto/ExistingResourceDTO.java create mode 100644 git/iec-backend/src/main/java/com/piacere/iec/backend/service/dto/ImageDTO.java create mode 100644 git/iec-backend/src/main/java/com/piacere/iec/backend/service/impl/ExistingResourceServiceImpl.java create mode 100644 git/iec-backend/src/main/java/com/piacere/iec/backend/service/impl/ImageServiceImpl.java create mode 100644 git/iec-backend/src/main/java/com/piacere/iec/backend/service/mapper/ExistingResourceMapper.java create mode 100644 git/iec-backend/src/main/java/com/piacere/iec/backend/service/mapper/ImageMapper.java create mode 100644 git/iec-backend/src/main/java/com/piacere/iec/backend/util/CollectionUtil.java create mode 100644 git/iec-backend/src/main/java/com/piacere/iec/backend/web/rest/ExistingResourceResource.java create mode 100644 git/iec-backend/src/main/java/com/piacere/iec/backend/web/rest/ImageResource.java create mode 100644 git/iec-backend/src/main/resources/config/liquibase/changelog/20230215090119_added_entity_ExistingResource.xml create mode 100644 git/iec-backend/src/main/resources/config/liquibase/changelog/20230403121800_added_entity_Image.xml create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/delete/existing-resource-delete-dialog.component.html create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/delete/existing-resource-delete-dialog.component.spec.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/delete/existing-resource-delete-dialog.component.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/detail/existing-resource-detail.component.html create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/detail/existing-resource-detail.component.spec.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/detail/existing-resource-detail.component.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/existing-resource.model.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/existing-resource.module.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/list/existing-resource.component.html create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/list/existing-resource.component.spec.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/list/existing-resource.component.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/route/existing-resource-routing-resolve.service.spec.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/route/existing-resource-routing-resolve.service.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/route/existing-resource-routing.module.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/service/existing-resource.service.spec.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/service/existing-resource.service.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/update/existing-resource-update.component.html create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/update/existing-resource-update.component.spec.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/update/existing-resource-update.component.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/detail/image-detail.component.html create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/detail/image-detail.component.spec.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/detail/image-detail.component.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/image.model.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/image.module.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/list/image.component.html create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/list/image.component.spec.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/list/image.component.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/route/image-routing-resolve.service.spec.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/route/image-routing-resolve.service.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/route/image-routing.module.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/service/image.service.spec.ts create mode 100644 git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/service/image.service.ts create mode 100644 git/iec-frontend/src/main/webapp/i18n/en/iecBackendExistingResource.json create mode 100644 git/iec-frontend/src/main/webapp/i18n/en/iecBackendImage.json create mode 100644 git/iec-frontend/src/main/webapp/i18n/es/iecBackendExistingResource.json create mode 100644 git/iec-frontend/src/main/webapp/i18n/es/iecBackendImage.json create mode 100644 git/jhipster-registry/.env create mode 100644 git/jhipster-registry/.env.gen create mode 100644 git/jhipster-registry/.env.local create mode 100644 git/jhipster-registry/.gitmodules create mode 100644 git/jhipster-registry/README.md rename {central-config/jhipster => git/jhipster-registry/data/jhipster-registry/central-config/jhipster-registry}/application.yml (100%) mode change 100755 => 100644 rename central-config/jhipster/registry.yml => git/jhipster-registry/data/jhipster-registry/central-config/jhipster-registry/jhipster-registry.yml (93%) mode change 100755 => 100644 create mode 100644 git/jhipster-registry/docker-compose-dev-expose.yaml rename docker-compose-dev.yaml => git/jhipster-registry/docker-compose-dev.yaml (71%) mode change 100755 => 100644 create mode 100644 git/jhipster-registry/docker-compose-heathcheck-kill.yaml create mode 100644 git/jhipster-registry/docker-compose-oidc.yaml create mode 100644 git/jhipster-registry/docker-compose-tecnalia-ca.yaml create mode 100644 git/jhipster-registry/docker-compose-traefik-aliases.yaml create mode 100644 git/jhipster-registry/docker-compose-traefik-network-external.yaml create mode 100644 git/jhipster-registry/docker-compose-volumes.yaml rename docker-compose-jhipster-registry.yaml => git/jhipster-registry/docker-compose.yaml (75%) mode change 100755 => 100644 create mode 100644 piacere-build/docker-compose.yaml create mode 100644 release/docker-compose.yaml diff --git a/.env b/.env index edf2823..a1ab798 100644 --- a/.env +++ b/.env @@ -1,22 +1,9 @@ -# Reference documentation https://docs.docker.com/compose/environment-variables/ -# Focus default variables as production, to allow direct download and run in production -# Required external variables that must be defined externally are those that have no value - -DEVSVC_BASE_PATH=development-services/ - -#### Production related #### - -DOCKER_REGISTRY_PREFIX=optima-piacere-docker-dev.artifact.tecnalia.com -PROJECT_NAME= -COMPOSE_PROJECT_VERSION=y1 - -TZ=Madrid +ADMIN_USER=piacere ADMIN_PASSWORD=piacerePassword -HTTPS_PORT=8443 -SERVER_HOST=192.168.56.1.nip.io - -# https://docs.docker.com/compose/reference/envvars/#compose_file#compose_project_name -# these are docker-compose related environment variables -COMPOSE_PROJECT_NAME=piacere-production -COMPOSE_FILE=docker-compose-iec.yaml:docker-compose-jhipster-registry.yaml:docker-compose-traefik-selfsigned.yaml:docker-compose-expose.yaml:docker-compose-redirect-http.yaml - +HTTPS_PORT=443 +SERVER_HOST=ci.piacere.digital.tecnalia.dev +COMPOSE_PROJECT_NAME=piacere-iec-production +IMAGE_IEC_MYSQL=optima-piacere-docker-dev.artifact.tecnalia.com/wp5/iec-mysql:y3 +IMAGE_IEC_BACKEND=optima-piacere-docker-dev.artifact.tecnalia.com/wp5/iec-backend:y3 +IMAGE_IEC_FRONTEND=optima-piacere-docker-dev.artifact.tecnalia.com/wp5/iec-frontend:y3 +COMPOSE_FILE=docker-compose.yaml:docker-compose-jhipster-network-external.yaml:docker-compose-traefik-network-external.yaml:release/docker-compose.yaml diff --git a/.env.build b/.env.build deleted file mode 100755 index 6e12ddc..0000000 --- a/.env.build +++ /dev/null @@ -1,26 +0,0 @@ -# Reference documentation https://docs.docker.com/compose/environment-variables/ -# Focus default variables as production, to allow direct download and run in production -# Required external variables that must be defined externally are those that have no value - -DEVSVC_BASE_PATH=development-services/ - -#### Production related #### - -DOCKER_REGISTRY_PREFIX=optima-piacere-docker-dev.artifact.tecnalia.com -PROJECT_NAME= -COMPOSE_PROJECT_VERSION=y1 - -TZ=Madrid -ADMIN_PASSWORD=piacerePassword -HTTPS_PORT=8443 -SERVER_HOST=192.168.56.1.nip.io - -# https://docs.docker.com/compose/reference/envvars/#compose_file#compose_project_name -# these are docker-compose related environment variables -COMPOSE_PROJECT_NAME=piacere-production - -#### Build related #### -DOCKER_BUILDKIT=1 -COMPOSE_DOCKER_CLI_BUILD=1 -COMPOSE_FILE=docker-compose-iec.yaml:build/docker-compose-iec.yaml:docker-compose-traefik-selfsigned.yaml:docker-compose-jhipster-registry.yaml -EXTRA_CA_URL=https://git.code.tecnalia.com/smartdatalab/ca/-/raw/master/ca.crt.pem diff --git a/.env.gen b/.env.gen new file mode 100644 index 0000000..8fd0ecd --- /dev/null +++ b/.env.gen @@ -0,0 +1,87 @@ +# Reference documentation https://docs.docker.com/compose/environment-variables/ +# Focus default variables as production, to allow direct download and run in production +# Required external variables that must be defined externally are those that have no value + +#### Environments managed +# this is the default environment if needed uncomment and adjust +# some conventions on environment prefixes +# - _ENV_LOCAL_ .env.local purpouse is to cache build and start the setup locally using cache images exposing dev ports (i.e 3306, 5432, 8086, ...) for debug and development purposes. It is the default behaviour (_ENV_LOCAL_:build-cache:.env.local) +# - _ENV_CACHE_ .env.cache purpouse is to generate images tagged for build cache from that use BUILDKIT_INLINE_CACHE 1 (_ENV_CACHE_:build-cache:.env.cache) +# - _ENV_RELEASE_ .env.release purpouse is to generate images (that do not use BUILDKIT_INLINE_CACHE 1) tagged for the clients/pilots usage (_ENV_RELEASE_:build-release:.env.release) +# - _ENV_DEPLOY_ .env purpose is to generate non building docker-compose that uses the release to deploy on generic client (_ENV_DEPLOY_:release:.env) +# - _ENV_TEST_ .env.test the purpouse is to test from the cache images the correct behaviour without exposing ports () +# types of building +# - build-cache: it focuses in the generation of images with BUILDKIT_INLINE_CACHE 1 for its usage in the cache-from for subsequent build, for each compose-file in compose-file build it finds build/cache the same name to add it to the build, it will use cache from. +# - build-release: it focuses in the generation of images for distribution it avoid using BUILDKIT_INLINE_CACHE 1 to reduce the size, it will use cache from. +# - cache: it runs using cache images +# - release: it runs using release images +# default enviroment +# _ENVIRONMENTS=_ENV_LOCAL_:build-cache:.env.local +# to add more enviroments use split with ";" +_ENVIRONMENTS=_ENV_LOCAL_:build-cache:.env.local;_ENV_RELEASE_:build-release:.env.release;_ENV_DEPLOY_:release:.env;_ENV_PIACERE_:release:.env.piacere + +#### Common image related #### +DOCKER_REGISTRY_CACHE_PREFIX=cache.euve.digital.tecnalia.dev:5000 +DOCKER_REGISTRY_CACHE_VERSION=latest + +#### Common Build related #### +# DOCKER_BUILDKIT and COMPOSE_DOCKER_CLI_BUILD do not have effect here, we leave them as documentation +# DOCKER_BUILDKIT=1 +# COMPOSE_DOCKER_CLI_BUILD=1 + +### Common Traefik related ### +TRAEFIK_NETWORK_NAME=traefik_network +TRAEFIK_HTTPS_ENTRYPOINT_NAME=websecure +TRAEFIK_HTTP_ENTRYPOINT_NAME=web + +#### Common Production related #### +ADMIN_USER=piacere +ADMIN_PASSWORD=piacerePassword +HTTPS_PORT=443 +SERVER_HOST=ci.piacere.digital.tecnalia.dev + +#### Platform Specific #### +TZ=Madrid + +#### Platform Specific path #### +EXTRA_CA_URL=https://git.code.tecnalia.com/smartdatalab/ca/-/raw/master/ca.crt.pem + +#### Common docker-compose related #### +# https://docs.docker.com/compose/reference/envvars/#compose_file#compose_project_name +# these are docker-compose related environment variables +COMPOSE_PROJECT_NAME=piacere-iec-production +# _ENV_LOCAL_COMPOSE_FILE_BASE= # These are oriented for local vagrant usually it contains local traefik configuration, dev services, etc +# _ENV_RELEASE_COMPOSE_FILE_BASE= # These are oriented for tagging relevant images for upload to official release repositories +# _ENV_DEPLOY_COMPOSE_FILE_BASE= # These are oriented for final deployment it contains production traefik configuration, etc +# _ENV_TEST_COMPOSE_FILE_BASE= # These are oriented for testing +# COMPOSE_FILE_BASE= # (MANDATORY) These are those main services of the project, that will apply to all the scenarios + +COMPOSE_FILE_BASE=docker-compose.yaml +COMPOSE_FILE_BASE_JHIPSTER_NETWORK=docker-compose-jhipster-network-external.yaml + +COMPOSE_FILE= +# COMPOSE_FILE Is generated automatically + +COMPOSE_FILE_BASE_NETWORK=docker-compose-traefik-network-external.yaml + +IEC_CONFIG_PATH= +IEC_BASE_PATH= + +IMAGE_IEC_MYSQL=optima-piacere-docker-dev.artifact.tecnalia.com/wp5/iec-mysql:y3 +IMAGE_IEC_BACKEND=optima-piacere-docker-dev.artifact.tecnalia.com/wp5/iec-backend:y3 +IMAGE_IEC_FRONTEND=optima-piacere-docker-dev.artifact.tecnalia.com/wp5/iec-frontend:y3 +IMAGE_IEC_MYSQL_CACHE=optima-piacere-docker-dev.artifact.tecnalia.com/wp5/iec-mysql:y3 +IMAGE_IEC_BACKEND_CACHE=optima-piacere-docker-dev.artifact.tecnalia.com/wp5/iec-backend:y3 +IMAGE_IEC_FRONTEND_CACHE=optima-piacere-docker-dev.artifact.tecnalia.com/wp5/iec-frontend:y3 + +_ENV_LOCAL_SERVER_HOST=192.168.56.1.nip.io +_ENV_LOCAL_COMPOSE_FILE_BASE_EXPOSE_DEV=docker-compose-dev-expose.yaml +_ENV_LOCAL_COMPOSE_FILE_BASE_LOCAL_JHIPSTER_REGISTRY_VOLUMES=docker-compose-jhipster-registry-volumes.yaml +_ENV_LOCAL_COMPOSE_FILE_BASE_LOCAL_JHIPSTER_REGISTRY=git/jhipster-registry/docker-compose.yaml +_ENV_LOCAL_COMPOSE_FILE_BASE_LOCAL_JHIPSTER_REGISTRY_DEV=git/jhipster-registry/docker-compose-dev.yaml +_ENV_LOCAL_JHIPSTER_REGISTRY_CONFIG_PATH=git/jhipster-registry/ + +_ENV_PIACERE_COMPOSE_FILE_BASE_PIACERE_BUILD=piacere-build/docker-compose.yaml +_ENV_PIACERE_COMPOSE_FILE_BASE_PIACERE_RELEASE=release/docker-compose.yaml +_ENV_PIACERE_COMPOSE_FILE_BASE_ARTIFACTORY=docker-compose-artifactory.yaml +_ENV_PIACERE_COMPOSE_FILE_BASE_TRAEFIK_NETWORK=docker-compose-traefik-network-internal.yaml diff --git a/.env.int b/.env.int deleted file mode 100755 index 7f1a1dc..0000000 --- a/.env.int +++ /dev/null @@ -1,31 +0,0 @@ -# Reference documentation https://docs.docker.com/compose/environment-variables/ -# Focus default variables as production, to allow direct download and run in production -# Required external variables that must be defined externally are those that have no value - -DEVSVC_BASE_PATH=development-services/ - -#### Production related #### - -DOCKER_REGISTRY_PREFIX=optima-piacere-docker-dev.artifact.tecnalia.com -PROJECT_NAME= -COMPOSE_PROJECT_VERSION=y1 - -TZ=Madrid -ADMIN_PASSWORD=piacerePassword -HTTPS_PORT=8443 -SERVER_HOST=192.168.56.1.nip.io - -# https://docs.docker.com/compose/reference/envvars/#compose_file#compose_project_name -# these are docker-compose related environment variables -COMPOSE_PROJECT_NAME=piacere-production - -#### Build related #### -DOCKER_BUILDKIT=1 -COMPOSE_DOCKER_CLI_BUILD=1 -EXTRA_CA_URL=https://git.code.tecnalia.com/smartdatalab/ca/-/raw/master/ca.crt.pem - -#### Development related #### -# CERTIFICATE_SIGNING_KEY_PASSPHRASE= - -COMPOSE_FILE=docker-compose-iec.yaml:docker-compose-iec-dev-expose.yaml:docker-compose-jhipster-registry.yaml:docker-compose-dev.yaml:development-services/docker-compose-traefik-tecnalia-selfsigned.yaml:docker-compose-expose.yaml:docker-compose-redirect-http.yaml:build/docker-compose-iec.yaml:development-services/build/docker-compose-traefik-tecnalia-selfsigned.yaml:development-services/docker-compose.yaml:development-services/docker-compose-expose.yaml:development-services/docker-compose-redirect-http.yaml:development-services/build/docker-compose.yaml - diff --git a/.env.local b/.env.local new file mode 100644 index 0000000..28f9c5b --- /dev/null +++ b/.env.local @@ -0,0 +1,12 @@ +DOCKER_REGISTRY_CACHE_PREFIX=cache.euve.digital.tecnalia.dev:5000 +DOCKER_REGISTRY_CACHE_VERSION=latest +ADMIN_USER=piacere +ADMIN_PASSWORD=piacerePassword +HTTPS_PORT=443 +SERVER_HOST=192.168.56.1.nip.io +EXTRA_CA_URL=https://git.code.tecnalia.com/smartdatalab/ca/-/raw/master/ca.crt.pem +COMPOSE_PROJECT_NAME=piacere-iec-production +IEC_CONFIG_PATH= +IEC_BASE_PATH= +JHIPSTER_REGISTRY_CONFIG_PATH=git/jhipster-registry/ +COMPOSE_FILE=docker-compose.yaml:docker-compose-jhipster-network-external.yaml:docker-compose-traefik-network-external.yaml:docker-compose-dev-expose.yaml:docker-compose-jhipster-registry-volumes.yaml:git/jhipster-registry/docker-compose.yaml:git/jhipster-registry/docker-compose-dev.yaml:build/docker-compose.yaml:build/inline-cache/docker-compose.yaml:build/image/docker-compose.yaml diff --git a/.env.piacere b/.env.piacere new file mode 100644 index 0000000..1542c1f --- /dev/null +++ b/.env.piacere @@ -0,0 +1,14 @@ +TRAEFIK_NETWORK_NAME=traefik_network +ADMIN_USER=piacere +ADMIN_PASSWORD=piacerePassword +HTTPS_PORT=443 +SERVER_HOST=ci.piacere.digital.tecnalia.dev +COMPOSE_PROJECT_NAME=piacere-iec-production +IEC_BASE_PATH= +IMAGE_IEC_MYSQL=optima-piacere-docker-dev.artifact.tecnalia.com/wp5/iec-mysql:y3 +IMAGE_IEC_BACKEND=optima-piacere-docker-dev.artifact.tecnalia.com/wp5/iec-backend:y3 +IMAGE_IEC_FRONTEND=optima-piacere-docker-dev.artifact.tecnalia.com/wp5/iec-frontend:y3 +IMAGE_IEC_MYSQL_CACHE=optima-piacere-docker-dev.artifact.tecnalia.com/wp5/iec-mysql:y3 +IMAGE_IEC_BACKEND_CACHE=optima-piacere-docker-dev.artifact.tecnalia.com/wp5/iec-backend:y3 +IMAGE_IEC_FRONTEND_CACHE=optima-piacere-docker-dev.artifact.tecnalia.com/wp5/iec-frontend:y3 +COMPOSE_FILE=docker-compose.yaml:docker-compose-jhipster-network-external.yaml:docker-compose-traefik-network-external.yaml:piacere-build/docker-compose.yaml:release/docker-compose.yaml:docker-compose-artifactory.yaml:docker-compose-traefik-network-internal.yaml diff --git a/.env.release b/.env.release new file mode 100644 index 0000000..a0c543a --- /dev/null +++ b/.env.release @@ -0,0 +1,13 @@ +DOCKER_REGISTRY_CACHE_PREFIX=cache.euve.digital.tecnalia.dev:5000 +DOCKER_REGISTRY_CACHE_VERSION=latest +ADMIN_USER=piacere +ADMIN_PASSWORD=piacerePassword +HTTPS_PORT=443 +SERVER_HOST=ci.piacere.digital.tecnalia.dev +EXTRA_CA_URL=https://git.code.tecnalia.com/smartdatalab/ca/-/raw/master/ca.crt.pem +COMPOSE_PROJECT_NAME=piacere-iec-production +IEC_BASE_PATH= +IMAGE_IEC_MYSQL=optima-piacere-docker-dev.artifact.tecnalia.com/wp5/iec-mysql:y3 +IMAGE_IEC_BACKEND=optima-piacere-docker-dev.artifact.tecnalia.com/wp5/iec-backend:y3 +IMAGE_IEC_FRONTEND=optima-piacere-docker-dev.artifact.tecnalia.com/wp5/iec-frontend:y3 +COMPOSE_FILE=docker-compose.yaml:docker-compose-jhipster-network-external.yaml:docker-compose-traefik-network-external.yaml:build/docker-compose.yaml:release/docker-compose.yaml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ea76e45..9937bc2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,79 +1,121 @@ -stages: - - build - - deploy - - stop +include: + - project: piacere/private/t23-ci-setup + ref: main + file: + - gitlab-ci-scripts/utils.gitlab-ci.yml + + # Image tag variables generation job ------------- + # Stage: variable-generation --------------------- + - gitlab-ci-scripts/generate-variables.gitlab-ci.yml + + # Downstream t23-ci-setup pipeline trigger job --- + # Stage: integration-tests-publish-deploy -------- + - gitlab-ci-scripts/trigger-downstream.gitlab-ci.yml variables: - GIT_SUBMODULE_STRATEGY: normal + #------------------------ + # Component image tag data + # ------------------------ + COMPONENT_WP: wp3 + IEC_MYSQL_IMAGE_NAME: iec-mysql + IEC_BACKEND_IMAGE_NAME: iec-backend + IEC_FRONTEND_IMAGE_NAME: iec-frontend -.common_variables: - variables: - TZ: Madrid - SERVER_HOST: piacere.esilab.org - SMTP_USER_EMAIL: piacere@esilab.org - PROJECT_NAME: piacere-iec + # ------------------------------------------ + # Space-separated component image abbreviation list + # used to generate image tags and related variables. + # It is also passed to the downstream integration tests, + # publication and deployment pipeline. + # ------------------------------------------ + IMAGE_NAMES: "$IEC_MYSQL_IMAGE_NAME $IEC_BACKEND_IMAGE_NAME $IEC_FRONTEND_IMAGE_NAME" -.master: - extends: - - .common_variables - variables: - # these variables take precedence over .env - # CERTIFICATE_SIGNING_KEY_PASSPHRASE defined in variables at settings/ci_cd - HTTPS_PORT: 8444 - COMPOSE_FILE: "docker-compose.yaml:docker-compose-expose.yaml:docker-compose-dev.yaml" - COMPOSE_PROJECT_NAME: piacere-iec-master - COMPOSE_PROJECT_VERSION: master - ADD_DEFAULT_CA: "true" - only: - - master - tags: - - piacere-iec - - docker - - docker-compose - - master +# The quality stage does not apply here, +# since the base images come from Docker Hub. +# There are no unit tests either. -.build: - script: - - echo "build images" - - docker-compose build --parallel +stages: + - variable-generation +# - quality + - build + - security +# - unit-tests + - integration-tests-publish-deploy -.deploy: - script: - - echo "Deploy to the environment" - - docker-compose up -d --remove-orphans +# Build jobs ---------------------- -.stop: +.build-docker-compose: + # image: docker/compose:1.29.2 # this is too old + image: docker:23.0.1 + stage: build + services: + # - docker:20.10.21-dind # not sure if this is the latest + - docker:dind variables: - GIT_STRATEGY: none + GIT_DEPTH: 1 + GIT_SUBMODULE_STRATEGY: recursive + GIT_SUBMODULE_DEPTH: 1 + DOCKER_BUILDKIT: 1 + COMPOSE_DOCKER_CLI_BUILD: 1 + DOCKER_COMPOSE_PATH: "." + DOCKER_COMPOSE_ENV_FILE_CACHE: ".env.piacere" + DOCKER_COMPOSE_ENV_FILE: ".env.piacere" + before_script: + - !reference [.artifactory-login] script: - - echo "Stops the environment" - - docker-compose down --remove-orphans - -build_master: - stage: build - extends: - - .master - - .build + - apk add docker-compose + - cd $DOCKER_COMPOSE_PATH + - docker-compose --env-file $DOCKER_COMPOSE_ENV_FILE_CACHE --project-directory ./ pull || true + - docker-compose --env-file $DOCKER_COMPOSE_ENV_FILE_CACHE --project-directory ./ config + - docker-compose --env-file $DOCKER_COMPOSE_ENV_FILE --project-directory ./ build + - docker-compose --env-file $DOCKER_COMPOSE_ENV_FILE --project-directory ./ push + - docker-compose --env-file $DOCKER_COMPOSE_ENV_FILE --project-directory ./ config | grep image + tags: + - docker -deploy_master: - stage: deploy +build-temp-docker-compose: extends: - - .master - - .deploy - environment: - name: master - url: https://$SERVER_HOST:8444 - on_stop: stop_master - -stop_master: + - .build-docker-compose variables: - COMPOSE_FILE: "docker-compose.yaml:docker-compose-expose.yaml:docker-compose-dev.yaml" - stage: stop + IMAGE_IEC_MYSQL: "$TMP_IMAGE_IEC_MYSQL" + IMAGE_IEC_BACKEND: "$TMP_IMAGE_IEC_BACKEND" + IMAGE_IEC_FRONTEND: "$TMP_IMAGE_IEC_FRONTEND" + +build-release-docker-compose: extends: - - .master - - .stop - environment: - name: master - action: stop + - .build-docker-compose when: manual +# Security jobs ------------------------ + +# Even though the images come from Docker Hub, we may still +# perform the trivy vulnerability tests. + +# security-trivy-iec-mysql: +# stage: security +# variables: +# TMP_IMAGE: "$TMP_IMAGE_IEC_MYSQL" +# trigger: !reference [.trigger-security-trivy] +# needs: +# - job: build-temp-docker-compose +# - job: generate-variables +# artifacts: true + +# security-trivy-iec-backend: +# stage: security +# variables: +# TMP_IMAGE: "$TMP_IMAGE_IEC_BACKEND" +# trigger: !reference [.trigger-security-trivy] +# needs: +# - job: build-temp-docker-compose +# - job: generate-variables +# artifacts: true + +# security-trivy-iec-frontend: +# stage: security +# variables: +# TMP_IMAGE: "$TMP_IMAGE_IEC_FRONTEND" +# trigger: !reference [.trigger-security-trivy] +# needs: +# - job: build-temp-docker-compose +# - job: generate-variables +# artifacts: true diff --git a/.gitmodules b/.gitmodules index f4475b6..aa0366c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "development-services"] - path = development-services - url = ../../../../smartdatalab/libraries/docker-compose/development-services.git +[submodule "git/jhipster-registry"] + path = git/jhipster-registry + url = ../../../../smartdatalab/libraries/docker-compose/jhipster-registry-deploy.git diff --git a/LICENSE b/LICENSE deleted file mode 100644 index df30cd7..0000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2023 PIACERE / public / The Platform / IOP - IaC Optimized Platform - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/build/docker-compose-iec.yaml b/build/docker-compose-iec.yaml deleted file mode 100755 index a605e6d..0000000 --- a/build/docker-compose-iec.yaml +++ /dev/null @@ -1,24 +0,0 @@ -version: '3.8' - -services: - - iec-mysql: - build: - context: ${IEC_BUILD_RELATIVE_FOLDER}git/iec-mysql - dockerfile: Dockerfile - - iec-backend: - build: - context: ${IEC_BUILD_RELATIVE_FOLDER}git/iec-backend - dockerfile: Dockerfile - args: - BUILDKIT_INLINE_CACHE: 1 - EXTRA_CA_URL: ${EXTRA_CA_URL:?err} - - iec-frontend: - build: - context: ${IEC_BUILD_RELATIVE_FOLDER}git/iec-frontend - dockerfile: Dockerfile - args: - BUILDKIT_INLINE_CACHE: 1 - EXTRA_CA_URL: ${EXTRA_CA_URL:?err} diff --git a/build/docker-compose.yaml b/build/docker-compose.yaml new file mode 100644 index 0000000..39c9b16 --- /dev/null +++ b/build/docker-compose.yaml @@ -0,0 +1,25 @@ +services: + iec-mysql: + build: + context: ${IEC_BASE_PATH}git/iec-mysql + dockerfile: Dockerfile + cache_from: + - ${DOCKER_REGISTRY_CACHE_PREFIX}/piacere/iec-mysql:${DOCKER_REGISTRY_CACHE_VERSION:?err} + + iec-backend: + build: + context: ${IEC_BASE_PATH}git/iec-backend + dockerfile: Dockerfile + args: + EXTRA_CA_URL: ${EXTRA_CA_URL:?err} + cache_from: + - ${DOCKER_REGISTRY_CACHE_PREFIX}/piacere/iec-backend:${DOCKER_REGISTRY_CACHE_VERSION:?err} + + iec-frontend: + build: + context: ${IEC_BASE_PATH}git/iec-frontend + dockerfile: Dockerfile + args: + EXTRA_CA_URL: ${EXTRA_CA_URL:?err} + cache_from: + - ${DOCKER_REGISTRY_CACHE_PREFIX}/piacere/iec-frontend:${DOCKER_REGISTRY_CACHE_VERSION:?err} diff --git a/build/image/docker-compose.yaml b/build/image/docker-compose.yaml new file mode 100644 index 0000000..206ed79 --- /dev/null +++ b/build/image/docker-compose.yaml @@ -0,0 +1,9 @@ +services: + iec-mysql: + image: ${DOCKER_REGISTRY_CACHE_PREFIX}/piacere/iec-mysql:${DOCKER_REGISTRY_CACHE_VERSION:?err} + + iec-backend: + image: ${DOCKER_REGISTRY_CACHE_PREFIX}/piacere/iec-backend:${DOCKER_REGISTRY_CACHE_VERSION:?err} + + iec-frontend: + image: ${DOCKER_REGISTRY_CACHE_PREFIX}/piacere/iec-frontend:${DOCKER_REGISTRY_CACHE_VERSION:?err} diff --git a/build/inline-cache/docker-compose.yaml b/build/inline-cache/docker-compose.yaml new file mode 100644 index 0000000..956fffd --- /dev/null +++ b/build/inline-cache/docker-compose.yaml @@ -0,0 +1,15 @@ +services: + iec-mysql: + build: + args: + BUILDKIT_INLINE_CACHE: 1 # For multistage docker + + iec-backend: + build: + args: + BUILDKIT_INLINE_CACHE: 1 # For multistage docker + + iec-frontend: + build: + args: + BUILDKIT_INLINE_CACHE: 1 # For multistage docker diff --git a/central-config/iec/application.yml b/data/jhipster-registry/central-config/iec/application.yml old mode 100755 new mode 100644 similarity index 100% rename from central-config/iec/application.yml rename to data/jhipster-registry/central-config/iec/application.yml diff --git a/central-config/iec/iecBackend.yml b/data/jhipster-registry/central-config/iec/iecBackend.yml old mode 100755 new mode 100644 similarity index 100% rename from central-config/iec/iecBackend.yml rename to data/jhipster-registry/central-config/iec/iecBackend.yml diff --git a/central-config/iec/iecFrontend.yml b/data/jhipster-registry/central-config/iec/iecFrontend.yml old mode 100755 new mode 100644 similarity index 100% rename from central-config/iec/iecFrontend.yml rename to data/jhipster-registry/central-config/iec/iecFrontend.yml diff --git a/development-services b/development-services deleted file mode 160000 index 355ef89..0000000 --- a/development-services +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 355ef897f9b68ae57d381e611bd106d7fc68b38c diff --git a/doc/scenarios/.gitkeep b/doc/scenarios/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/doc/scenarios/KR-9-IEC.feature b/doc/scenarios/KR-9-IEC.feature new file mode 100644 index 0000000..3cde68f --- /dev/null +++ b/doc/scenarios/KR-9-IEC.feature @@ -0,0 +1,20 @@ +Feature: PIACERE Design Time + +Scenario: IOP working +Given the IOP need the Catalogue data to calculate optimizations + When the IOP invokes the IEC + Then the IEC returns the available elements in json format + +Feature: PIACERE Run Time + +Scenario: A project is being deployed +Given the deployment is successcul + Then the PRC sends to the IEC the info about the deployed elements + And the IEC stores the information, including which service is deployed (type, id...) + And the IEC (periodically) connects to monitoring + And gets information about the deployed services + +Scenario: A project is being undeployed +Given the undeployment is successcul + Then the PRC sends to the IEC the info about the deployed elements + And the IEC stores the information, including which service is undeployed (type, id...) diff --git a/doc/sequence-diagrams/53-InfrastructuralElementsCatalogue-SequenceDiagram.Y2.png b/doc/sequence-diagrams/53-InfrastructuralElementsCatalogue-SequenceDiagram.Y2.png new file mode 100644 index 0000000000000000000000000000000000000000..26cc2b3755d37a7acccf523d142a53d6b735e6e3 GIT binary patch literal 55009 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�bEr!++45<a!R}Tnt!LbAANtbSKIpC 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 literal 0 HcmV?d00001 diff --git a/doc/sequence-diagrams/53-InfrastructuralElementsCatalogue.puml b/doc/sequence-diagrams/53-InfrastructuralElementsCatalogue.puml index 40edc95..dcda1b0 100755 --- a/doc/sequence-diagrams/53-InfrastructuralElementsCatalogue.puml +++ b/doc/sequence-diagrams/53-InfrastructuralElementsCatalogue.puml @@ -1,32 +1,37 @@ @startuml participant "GUI/IDE eclipse" as DESIDE -participant "Infrastructural\nElements\nCatalogue" as DBINFRACAT #99FF99 +participant "Infrastructural\nElements\nCatalogue" as IECDB #99FF99 participant "IaC Optimizer Platform (IOP)" as IAIOP participant "Runtime Controller (PRC)" as RTPRC -participant "IaC Execution Manager (IEM)" as RTIEM participant PerformanceMonitoring as IAMON participant SecurityMonitoring as SECMON -group Element endorsement (static information) -DESIDE->DBINFRACAT: Include element information (12) -DBINFRACAT->DESIDE: Confirmation + +== DESIGN TIME == +group Catalogue update +DESIDE -> IECDB: Element endorsement (26) +note left: New \n element +note right: Include element \n (static information) end + +== RUN TIME == group IOP interaction -IAIOP->DBINFRACAT: Information request\n about available elements\n & dynamic info if it exists (35) -DBINFRACAT->IAIOP: Information provision\n about available elements\n & dynamic info if it exists -end -group Information about instances (dynamic information I) -RTIEM ->RTPRC: Deployment response -RTPRC ->DBINFRACAT: Infrastructural element deployed and related instance info (37) -' 17 should be removed IEC is not going to call Runtime controller, and we do not expect any data stream between IEC and PRC -end -group Information about monitoring (dynamic information II) to support IOP -IAMON -> DBINFRACAT: Monitoring Information, ie average availability last year (32) -SECMON -> DBINFRACAT: Monitoring Information, ie average security last year (33) +IECDB <- IAIOP: Request (24) +return: Information about \n available elements \n & dynamic info end -group Information about element tore down (dynamic information III) -RTPRC -> DBINFRACAT: Instance tore down (37) +group Information about instances and monitoring (dynamic information) +IECDB <- RTPRC: Infrastructural element deployed and related instance info (21) +note right: New \n deployment + + loop while monitoring + IECDB <- IAMON: Monitoring Information, ie average availability last year (20) + note right: (dynamic \n information) + IECDB <- SECMON: Monitoring Information, ie average security last year (19) + end + +RTPRC -> IECDB: Instance tore down (23) +note right: Undeploy end 'note over InfrastruturalElementsCatalogue:Is the IOP always called by RuntimeController? diff --git a/docker-compose-artifactory.yaml b/docker-compose-artifactory.yaml new file mode 100644 index 0000000..6786dc9 --- /dev/null +++ b/docker-compose-artifactory.yaml @@ -0,0 +1,14 @@ +services: + iec-mysql: + build: + labels: + com.jfrog.artifactory.retention.maxCount: 6 + iec-backend: + build: + labels: + com.jfrog.artifactory.retention.maxCount: 6 + iec-frontend: + build: + labels: + com.jfrog.artifactory.retention.maxCount: 6 + diff --git a/docker-compose-iec-dev-expose.yaml b/docker-compose-dev-expose.yaml old mode 100755 new mode 100644 similarity index 52% rename from docker-compose-iec-dev-expose.yaml rename to docker-compose-dev-expose.yaml index e3ca2be..5ce4bc4 --- a/docker-compose-iec-dev-expose.yaml +++ b/docker-compose-dev-expose.yaml @@ -1,4 +1,3 @@ -version: '3.8' services: jhipster-registry: ports: @@ -7,3 +6,11 @@ services: iec-mysql: ports: - 3306:3306 + + iec-frontend: + ports: + - 8080:8080 + + iec-backend: + ports: + - 8081:8081 diff --git a/docker-compose-expose.yaml b/docker-compose-expose.yaml deleted file mode 100644 index 377e9d2..0000000 --- a/docker-compose-expose.yaml +++ /dev/null @@ -1,6 +0,0 @@ -version: '3.8' - -services: - traefik: - ports: - - ${HTTPS_PORT:?err}:${HTTPS_PORT:?err} diff --git a/docker-compose-jhipster-network-external.yaml b/docker-compose-jhipster-network-external.yaml new file mode 100644 index 0000000..98d5833 --- /dev/null +++ b/docker-compose-jhipster-network-external.yaml @@ -0,0 +1,4 @@ +networks: + jhipster_network: + name: jhipster_network + external: true diff --git a/docker-compose-jhipster-registry-volumes.yaml b/docker-compose-jhipster-registry-volumes.yaml new file mode 100644 index 0000000..30989c7 --- /dev/null +++ b/docker-compose-jhipster-registry-volumes.yaml @@ -0,0 +1,5 @@ +services: + jhipster-registry: + volumes: + - ./${JHIPSTER_REGISTRY_CONFIG_PATH}data/jhipster-registry/central-config/jhipster-registry:/central-config/jhipster-registry + - ./${IEC_CONFIG_PATH}data/jhipster-registry/central-config/iec:/central-config/iec diff --git a/docker-compose-redirect-http.yaml b/docker-compose-redirect-http.yaml deleted file mode 100755 index bd4a9c7..0000000 --- a/docker-compose-redirect-http.yaml +++ /dev/null @@ -1,14 +0,0 @@ -version: "3.8" - -services: - traefik: - labels: - # global redirect to https - - "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)" - - "traefik.http.routers.http-catchall.entrypoints=web" - - "traefik.http.routers.http-catchall.middlewares=redirect-to-https" - - "traefik.http.routers.http-catchall.service=api@internal" - - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" - - "traefik.http.middlewares.redirect-to-https.redirectscheme.port=${HTTPS_PORT:?err}" - ports: - - 80:80 diff --git a/docker-compose-traefik-aliases.yaml b/docker-compose-traefik-aliases.yaml new file mode 100644 index 0000000..67f8df0 --- /dev/null +++ b/docker-compose-traefik-aliases.yaml @@ -0,0 +1,6 @@ +services: + traefik: + networks: + traefik_network: + aliases: + - iec.${SERVER_HOST} diff --git a/docker-compose-traefik-network-external.yaml b/docker-compose-traefik-network-external.yaml new file mode 100644 index 0000000..95623b3 --- /dev/null +++ b/docker-compose-traefik-network-external.yaml @@ -0,0 +1,4 @@ +networks: + traefik_network: + name: traefik_network + external: true diff --git a/docker-compose-traefik-network-internal.yaml b/docker-compose-traefik-network-internal.yaml new file mode 100644 index 0000000..97d6f4f --- /dev/null +++ b/docker-compose-traefik-network-internal.yaml @@ -0,0 +1,3 @@ +networks: + traefik_network: + name: ${TRAEFIK_NETWORK_NAME:?err} diff --git a/docker-compose-traefik-selfsigned.yaml b/docker-compose-traefik-selfsigned.yaml deleted file mode 100755 index 19dabf5..0000000 --- a/docker-compose-traefik-selfsigned.yaml +++ /dev/null @@ -1,30 +0,0 @@ -version: "3.8" - -services: - ## Common structure - traefik: - image: traefik:v2.5.2 - restart: always - hostname: ${SERVER_HOST} - command: - --api=true - --api.insecure=true - --serverstransport.insecureskipverify=true - --ping=true - --providers.docker=true - --providers.docker.constraints="Label(`com.docker.compose.project`, `${COMPOSE_PROJECT_NAME}`)" - --providers.docker.exposedbydefault=false - --entrypoints.web.address=:80 - --entrypoints.websecure.address=:${HTTPS_PORT:?err} - --entrypoints.websecure.http.tls=true - # --log.level=DEBUG - volumes: - - /var/run/docker.sock:/var/run/docker.sock - networks: - default: - aliases: - - ${SERVER_HOST:?err} - -networks: - default: - \ No newline at end of file diff --git a/docker-compose-iec.yaml b/docker-compose.yaml old mode 100755 new mode 100644 similarity index 70% rename from docker-compose-iec.yaml rename to docker-compose.yaml index a40996e..41dbaa8 --- a/docker-compose-iec.yaml +++ b/docker-compose.yaml @@ -1,23 +1,14 @@ -version: '3.8' - services: - traefik: - networks: - default: - aliases: - - iec.${SERVER_HOST} iec-mysql: - image: ${DOCKER_REGISTRY_PREFIX}${PROJECT_NAME}/wp5/iec-mysql:${COMPOSE_PROJECT_VERSION:?err} restart: always volumes: - iec-mysql_data:/var/lib/mysql + networks: + default: iec-backend: - image: ${DOCKER_REGISTRY_PREFIX}${PROJECT_NAME}/wp5/iec-backend:${COMPOSE_PROJECT_VERSION:?err} restart: always - depends_on: - - jhipster-registry environment: # SPRING_PROFILES_ACTIVE: prod,api-docs,no-liquibase GLOBAL_PASSWORD: ${ADMIN_PASSWORD} @@ -25,26 +16,27 @@ services: # SPRING_CLOUD_CONFIG_URI: https://admin:${ADMIN_PASSWORD}@jhipster-registry.${SERVER_HOST}:${HTTPS_PORT}/config # SPRING_R2DBC_URL: r2dbc:mysql://iec-mysql:3306/iecBackend?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&createDatabaseIfNotExist=true # SPRING_LIQUIBASE_URL: jdbc:mysql://iec-mysql:3306/iecBackend?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&createDatabaseIfNotExist=true + networks: + default: + jhipster_network: iec-frontend: - image: ${DOCKER_REGISTRY_PREFIX}${PROJECT_NAME}/wp5/iec-frontend:${COMPOSE_PROJECT_VERSION:?err} restart: always - depends_on: - - jhipster-registry environment: GLOBAL_PASSWORD: ${ADMIN_PASSWORD} JHIPSTER_CORS_ALLOWEDORIGINS: "https://iec.${SERVER_HOST:?err}:${HTTPS_PORT}" + networks: + default: + jhipster_network: + traefik_network: labels: - "traefik.enable=true" + - "traefik.docker.network=traefik_network" - "traefik.http.routers.iec-frontend.entrypoints=websecure" - "traefik.http.routers.iec-frontend.rule=Host(`iec.${SERVER_HOST:?err}`)" -networks: - # https://github.com/docker/compose/issues/4336 - default: - driver: bridge - ipam: - driver: default - volumes: iec-mysql_data: + +networks: + default: diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/config/DatabaseConfiguration.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/config/DatabaseConfiguration.java index 8d7e8c9..16634d2 100644 --- a/git/iec-backend/src/main/java/com/piacere/iec/backend/config/DatabaseConfiguration.java +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/config/DatabaseConfiguration.java @@ -1,13 +1,9 @@ package com.piacere.iec.backend.config; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.transaction.annotation.EnableTransactionManagement; -import tech.jhipster.config.JHipsterConstants; @Configuration @EnableJpaRepositories("com.piacere.iec.backend.repository") diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/config/SecurityConfiguration.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/config/SecurityConfiguration.java index c57adb7..c2ed40c 100644 --- a/git/iec-backend/src/main/java/com/piacere/iec/backend/config/SecurityConfiguration.java +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/config/SecurityConfiguration.java @@ -1,18 +1,18 @@ package com.piacere.iec.backend.config; -import com.piacere.iec.backend.security.*; -import com.piacere.iec.backend.security.jwt.*; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; -import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter; import org.zalando.problem.spring.web.advice.security.SecurityProblemSupport; + +import com.piacere.iec.backend.security.AuthoritiesConstants; +import com.piacere.iec.backend.security.jwt.JWTConfigurer; +import com.piacere.iec.backend.security.jwt.TokenProvider; + import tech.jhipster.config.JHipsterProperties; @EnableWebSecurity diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/config/WebConfigurer.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/config/WebConfigurer.java index 7679769..9e3bdfa 100644 --- a/git/iec-backend/src/main/java/com/piacere/iec/backend/config/WebConfigurer.java +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/config/WebConfigurer.java @@ -1,19 +1,19 @@ package com.piacere.iec.backend.config; -import javax.servlet.*; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.boot.web.server.*; import org.springframework.boot.web.servlet.ServletContextInitializer; -import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; -import org.springframework.core.env.Profiles; import org.springframework.util.CollectionUtils; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; + import tech.jhipster.config.JHipsterProperties; /** diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/domain/ExistingResource.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/domain/ExistingResource.java new file mode 100644 index 0000000..d0bab74 --- /dev/null +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/domain/ExistingResource.java @@ -0,0 +1,240 @@ +package com.piacere.iec.backend.domain; + +import java.io.Serializable; +import java.time.Instant; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; + +/** + * A ExistingResource. + */ +@Entity +@Table(name = "existing_resource") +@Cache(usage = CacheConcurrencyStrategy.READ_WRITE) +public class ExistingResource implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + // @ApiModelProperty(notes = "Resource ID in Catalogue", example = "1") + private Long id; + + @NotNull + @Size(max = 70) + @Column(name = "data_name", length = 70, nullable = false) + private String dataName; + + @NotNull + @Size(max = 70) + @Column(name = "data_type", length = 70, nullable = false) + private String dataType; + + @NotNull + @Size(max = 70) + @Column(name = "name", length = 70, nullable = false) + private String name; + + @NotNull + @Size(max = 70) + @Column(name = "datacenter_id", length = 70, nullable = false) + private String datacenterId; + + @NotNull + @Size(max = 70) + @Column(name = "user", length = 70, nullable = false) + private String user; + + @NotNull + @Size(max = 70) + @Column(name = "provider", length = 70, nullable = false) + private String provider; + + @NotNull + @Column(name = "created_date", nullable = false) + private Instant createdDate; + + @Column(name = "last_modified_date") + private Instant lastModifiedDate; + + @Column(name = "deleted_date") + private Instant deletedDate; + + + // jhipster-needle-entity-add-field - JHipster will add fields here + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public ExistingResource id(Long id) { + this.id = id; + return this; + } + + public String getDataName() { + return dataName; + } + + public ExistingResource dataName(String dataName) { + this.dataName = dataName; + return this; + } + + public void setDataName(String dataName) { + this.dataName = dataName; + } + + public String getDataType() { + return this.dataType; + } + + public ExistingResource dataType(String dataType) { + this.dataType = dataType; + return this; + } + + public void setDataType(String dataType) { + this.dataType = dataType; + } + + public String getName() { + return this.name; + } + + public ExistingResource name(String name) { + this.name = name; + return this; + } + + public void setName(String name) { + this.name = name; + } + + public String getDatacenterId() { + return this.datacenterId; + } + + public ExistingResource datacenterId(String datacenterId) { + this.datacenterId = datacenterId; + return this; + } + + public void setDatacenterId(String datacenterId) { + this.datacenterId = datacenterId; + } + + public String getUser() { + return user; + } + + public ExistingResource user(String user) { + this.user = user; + return this; + } + + public void setUser(String user) { + this.user = user; + } + + public String getProvider() { + return this.provider; + } + + public ExistingResource provider(String provider) { + this.provider = provider; + return this; + } + + public void setProvider(String provider) { + this.provider = provider; + } + + public Instant getCreatedDate() { + return this.createdDate; + } + + public ExistingResource createdDate(Instant createdDate) { + this.createdDate = createdDate; + return this; + } + + public void setCreatedDate(Instant createdDate) { + this.createdDate = createdDate; + } + + public Instant getLastModifiedDate() { + return this.lastModifiedDate; + } + + public ExistingResource lastModifiedDate(Instant lastModifiedDate) { + this.lastModifiedDate = lastModifiedDate; + return this; + } + + public void setLastModifiedDate(Instant lastModifiedDate) { + this.lastModifiedDate = lastModifiedDate; + } + + public Instant getDeletedDate() { + return this.deletedDate; + } + + public ExistingResource deletedDate(Instant deletedDate) { + this.deletedDate = deletedDate; + return this; + } + + public void setDeletedDate(Instant deletedDate) { + this.deletedDate = deletedDate; + } + + // jhipster-needle-entity-add-getters-setters - JHipster will add getters and setters here + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ExistingResource)) { + return false; + } + return id != null && id.equals(((ExistingResource) o).id); + } + + @Override + public int hashCode() { + // see https://vladmihalcea.com/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/ + return getClass().hashCode(); + } + + // prettier-ignore + @Override + public String toString() { + return "ExistingResource{" + + "id=" + getId() + + ", dataName='" + getDataName() + "'" + + ", dataType='" + getDataType() + "'" + + ", name='" + getName() + "'" + + ", datacenterId='" + getDatacenterId() + "'" + + ", user='" + getUser() + "'" + + ", provider='" + getProvider() + "'" + + ", createdDate='" + getCreatedDate() + "'" + + ", lastModifiedDate='" + getLastModifiedDate() + "'" + + ", deletedDate='" + getDeletedDate() + "'" + + "}"; + } +} diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/domain/Image.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/domain/Image.java new file mode 100644 index 0000000..f3b16ac --- /dev/null +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/domain/Image.java @@ -0,0 +1,213 @@ +package com.piacere.iec.backend.domain; + +import java.io.Serializable; +import java.time.Instant; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; + +/** + * An Image. + */ +@Entity +@Table(name = "image") +@Cache(usage = CacheConcurrencyStrategy.READ_WRITE) +public class Image implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotNull + @Size(max = 10) + @Column(name = "image_type", length = 10, nullable = false) + private String imageType; + + @Size(max = 100) + @Column(name = "image_name", length = 100, nullable = true) + private String imageName; + + @Size(max = 255) + @Column(name = "image_url", length = 255, nullable = true) + private String imageUrl; + + @Column(name = "image_description", nullable = true) + private String imageDescription; + + @NotNull + @Size(max = 70) + @Column(name = "image_provider", length = 70, nullable = false) + private String imageProvider; + + @NotNull + @Column(name = "created_date", nullable = false) + private Instant createdDate; + + @Column(name = "last_modified_date") + private Instant lastModifiedDate; + + @Column(name = "deleted_date") + private Instant deletedDate; + + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Image id(Long id) { + this.id = id; + return this; + } + + public String getImageType() { + return imageType; + } + + public Image imageType(String imageType) { + this.imageType = imageType; + return this; + } + + public void setImageType(String imageType) { + this.imageType = imageType; + } + + public String getImageName() { + return this.imageName; + } + + public Image imageName(String imageName) { + this.imageName = imageName; + return this; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public String getImageUrl() { + return this.imageUrl; + } + + public Image imageUrl(String imageUrl) { + this.imageUrl = imageUrl; + return this; + } + + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } + + public String getImageDescription() { + return this.imageDescription; + } + + public Image imageDescription(String imageDescription) { + this.imageDescription = imageDescription; + return this; + } + + public void setImageDescription(String imageDescription) { + this.imageDescription = imageDescription; + } + + public String getImageProvider() { + return this.imageProvider; + } + + public Image imageProvider(String imageProvider) { + this.imageProvider = imageProvider; + return this; + } + + public void setImageProvider(String imageProvider) { + this.imageProvider = imageProvider; + } + + public Instant getCreatedDate() { + return this.createdDate; + } + + public Image createdDate(Instant createdDate) { + this.createdDate = createdDate; + return this; + } + + public void setCreatedDate(Instant createdDate) { + this.createdDate = createdDate; + } + + public Instant getLastModifiedDate() { + return this.lastModifiedDate; + } + + public Image lastModifiedDate(Instant lastModifiedDate) { + this.lastModifiedDate = lastModifiedDate; + return this; + } + + public void setLastModifiedDate(Instant lastModifiedDate) { + this.lastModifiedDate = lastModifiedDate; + } + + public Instant getDeletedDate() { + return this.deletedDate; + } + + public Image deletedDate(Instant deletedDate) { + this.deletedDate = deletedDate; + return this; + } + + public void setDeletedDate(Instant deletedDate) { + this.deletedDate = deletedDate; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Image)) { + return false; + } + return id != null && id.equals(((Image) o).id); + } + + @Override + public int hashCode() { + return getClass().hashCode(); + } + + // prettier-ignore + @Override + public String toString() { + return "Image{" + + "id=" + getId() + + ", imageType='" + getImageType() + "'" + + ", imageName='" + getImageName() + "'" + + ", imageUrl='" + getImageUrl() + "'" + + ", imageDescription='" + getImageDescription() + "'" + + ", imageProvider='" + getImageProvider() + "'" + + ", createdDate='" + getCreatedDate() + "'" + + ", lastModifiedDate='" + getLastModifiedDate() + "'" + + ", deletedDate='" + getDeletedDate() + "'" + + "}"; + } +} diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/domain/enumeration/ImageType.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/domain/enumeration/ImageType.java new file mode 100644 index 0000000..a53ded4 --- /dev/null +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/domain/enumeration/ImageType.java @@ -0,0 +1,35 @@ +package com.piacere.iec.backend.domain.enumeration; + +/** + * Enumeration for Image types. + * @author Tecnalia + * @version 1.0 + */ +public enum ImageType { + IMAGE_DOCKER("Docker"), + IMAGE_VM("VM"); + + + /** The value. */ + private String value; + + + + /** + * Constructs an Image. + * @param value The value. + */ + private ImageType(final String value) { + this.value = value; + } + + + + /** + * Gets the value. + * @return String + */ + public String getValue() { + return value; + } +} diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/repository/ExistingResourceRepository.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/repository/ExistingResourceRepository.java new file mode 100644 index 0000000..b294047 --- /dev/null +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/repository/ExistingResourceRepository.java @@ -0,0 +1,17 @@ +package com.piacere.iec.backend.repository; + +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.stereotype.Repository; + +import com.piacere.iec.backend.domain.ExistingResource; + +/** + * Spring Data SQL repository for the ExistingResource entity. + */ +@SuppressWarnings("unused") +@Repository +public interface ExistingResourceRepository extends JpaRepository<ExistingResource, Long>, JpaSpecificationExecutor<ExistingResource> { +} diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/repository/ImageRepository.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/repository/ImageRepository.java new file mode 100644 index 0000000..056aa6c --- /dev/null +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/repository/ImageRepository.java @@ -0,0 +1,15 @@ +package com.piacere.iec.backend.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.stereotype.Repository; + +import com.piacere.iec.backend.domain.Image; + +/** + * Spring Data SQL repository for the Image entity. + */ +@SuppressWarnings("unused") +@Repository +public interface ImageRepository extends JpaRepository<Image, Long>, JpaSpecificationExecutor<Image> { +} diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/service/ExistingResourceQueryService.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/ExistingResourceQueryService.java new file mode 100644 index 0000000..e8f4473 --- /dev/null +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/ExistingResourceQueryService.java @@ -0,0 +1,122 @@ +package com.piacere.iec.backend.service; + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +// for static metamodels +import com.piacere.iec.backend.domain.ExistingResource; +import com.piacere.iec.backend.domain.ExistingResource_; +import com.piacere.iec.backend.repository.ExistingResourceRepository; +import com.piacere.iec.backend.service.criteria.ExistingResourceCriteria; +import com.piacere.iec.backend.service.dto.ExistingResourceDTO; +import com.piacere.iec.backend.service.mapper.ExistingResourceMapper; + +import tech.jhipster.service.QueryService; + +/** + * Service for executing complex queries for {@link ExistingResource} entities in the database. + * The main input is a {@link ExistingResourceCriteria} which gets converted to {@link Specification}, + * in a way that all the filters must apply. + * It returns a {@link List} of {@link ExistingResourceDTO} or a {@link Page} of {@link ExistingResourceDTO} which fulfills the criteria. + */ +@Service +@Transactional(readOnly = true) +public class ExistingResourceQueryService extends QueryService<ExistingResource> { + + private final Logger log = LoggerFactory.getLogger(ExistingResourceQueryService.class); + + private final ExistingResourceRepository existingResourceRepository; + + private final ExistingResourceMapper existingResourceMapper; + + public ExistingResourceQueryService(ExistingResourceRepository existingResourceRepository, ExistingResourceMapper existingResourceMapper) { + this.existingResourceRepository = existingResourceRepository; + this.existingResourceMapper = existingResourceMapper; + } + + /** + * Return a {@link List} of {@link ExistingResourceDTO} which matches the criteria from the database. + * @param criteria The object which holds all the filters, which the entities should match. + * @return the matching entities. + */ + @Transactional(readOnly = true) + public List<ExistingResourceDTO> findByCriteria(ExistingResourceCriteria criteria) { + log.debug("find by criteria : {}", criteria); + final Specification<ExistingResource> specification = createSpecification(criteria); + return existingResourceMapper.toDto(existingResourceRepository.findAll(specification)); + } + + /** + * Return a {@link Page} of {@link ExistingResourceDTO} which matches the criteria from the database. + * @param criteria The object which holds all the filters, which the entities should match. + * @param page The page, which should be returned. + * @return the matching entities. + */ + @Transactional(readOnly = true) + public Page<ExistingResourceDTO> findByCriteria(ExistingResourceCriteria criteria, Pageable page) { + log.debug("find by criteria : {}, page: {}", criteria, page); + final Specification<ExistingResource> specification = createSpecification(criteria); + return existingResourceRepository.findAll(specification, page).map(existingResourceMapper::toDto); + } + + /** + * Return the number of matching entities in the database. + * @param criteria The object which holds all the filters, which the entities should match. + * @return the number of matching entities. + */ + @Transactional(readOnly = true) + public long countByCriteria(ExistingResourceCriteria criteria) { + log.debug("count by criteria : {}", criteria); + final Specification<ExistingResource> specification = createSpecification(criteria); + return existingResourceRepository.count(specification); + } + + /** + * Function to convert {@link ExistingResourceCriteria} to a {@link Specification} + * @param criteria The object which holds all the filters, which the entities should match. + * @return the matching {@link Specification} of the entity. + */ + protected Specification<ExistingResource> createSpecification(ExistingResourceCriteria criteria) { + Specification<ExistingResource> specification = Specification.where(null); + if (criteria != null) { + if (criteria.getId() != null) { + specification = specification.and(buildRangeSpecification(criteria.getId(), ExistingResource_.id)); + } + if (criteria.getDataName() != null) { + specification = specification.and(buildStringSpecification(criteria.getDataName(), ExistingResource_.dataName)); + } + if (criteria.getDataType() != null) { + specification = specification.and(buildStringSpecification(criteria.getDataType(), ExistingResource_.dataType)); + } + if (criteria.getName() != null) { + specification = specification.and(buildStringSpecification(criteria.getName(), ExistingResource_.name)); + } + if (criteria.getDatacenterId() != null) { + specification = specification.and(buildStringSpecification(criteria.getDatacenterId(), ExistingResource_.datacenterId)); + } + if (criteria.getUser() != null) { + specification = specification.and(buildStringSpecification(criteria.getUser(), ExistingResource_.user)); + } + if (criteria.getProvider() != null) { + specification = specification.and(buildStringSpecification(criteria.getProvider(), ExistingResource_.provider)); + } + if (criteria.getCreatedDate() != null) { + specification = specification.and(buildRangeSpecification(criteria.getCreatedDate(), ExistingResource_.createdDate)); + } + if (criteria.getLastModifiedDate() != null) { + specification = specification.and(buildRangeSpecification(criteria.getLastModifiedDate(), ExistingResource_.lastModifiedDate)); + } + if (criteria.getDeletedDate() != null) { + specification = specification.and(buildRangeSpecification(criteria.getDeletedDate(), ExistingResource_.deletedDate)); + } + } + return specification; + } +} diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/service/ExistingResourceService.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/ExistingResourceService.java new file mode 100644 index 0000000..d12cc6e --- /dev/null +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/ExistingResourceService.java @@ -0,0 +1,52 @@ +package com.piacere.iec.backend.service; + +import java.util.Optional; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +import com.piacere.iec.backend.service.dto.ExistingResourceDTO; + +/** + * Service Interface for managing {@link com.piacere.iec.backend.domain.ExistingResource}. + */ +public interface ExistingResourceService { + /** + * Save a existingResource. + * + * @param ExistingResourceDTO the entity to save. + * @return the persisted entity. + */ + ExistingResourceDTO save(ExistingResourceDTO existingResourceDTO); + + /** + * Partially updates a existingResource. + * + * @param existingResourceDTO the entity to update partially. + * @return the persisted entity. + */ + Optional<ExistingResourceDTO> partialUpdate(ExistingResourceDTO existingResourceDTO); + + /** + * Get all the existingResources. + * + * @param pageable the pagination information. + * @return the list of entities. + */ + Page<ExistingResourceDTO> findAll(Pageable pageable); + + /** + * Get the "id" existingResource. + * + * @param id the id of the entity. + * @return the entity. + */ + Optional<ExistingResourceDTO> findOne(Long id); + + /** + * Delete the "id" existingResource. + * + * @param id the id of the entity. + */ + void delete(Long id); +} diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/service/ImageQueryService.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/ImageQueryService.java new file mode 100644 index 0000000..490e2ec --- /dev/null +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/ImageQueryService.java @@ -0,0 +1,118 @@ +package com.piacere.iec.backend.service; + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.piacere.iec.backend.domain.Image; +import com.piacere.iec.backend.domain.Image_; +import com.piacere.iec.backend.repository.ImageRepository; +import com.piacere.iec.backend.service.criteria.ImageCriteria; +import com.piacere.iec.backend.service.dto.ImageDTO; +import com.piacere.iec.backend.service.mapper.ImageMapper; + +import tech.jhipster.service.QueryService; + +/** + * Service for executing complex queries for {@link Image} entities in the database. + * The main input is a {@link ImageCriteria} which gets converted to {@link Specification}, + * in a way that all the filters must apply. + * It returns a {@link List} of {@link ImageDTO} or a {@link Page} of {@link ImageDTO} which fulfills the criteria. + */ +@Service +@Transactional(readOnly = true) +public class ImageQueryService extends QueryService<Image> { + + private final Logger log = LoggerFactory.getLogger(ImageQueryService.class); + + private final ImageRepository imageRepository; + + private final ImageMapper imageMapper; + + public ImageQueryService(ImageRepository imageRepository, ImageMapper imageMapper) { + this.imageRepository = imageRepository; + this.imageMapper = imageMapper; + } + + /** + * Return a {@link List} of {@link ImageDTO} which matches the criteria from the database. + * @param criteria The object which holds all the filters, which the entities should match. + * @return the matching entities. + */ + @Transactional(readOnly = true) + public List<ImageDTO> findByCriteria(ImageCriteria criteria) { + log.debug("find by criteria : {}", criteria); + final Specification<Image> specification = createSpecification(criteria); + return imageMapper.toDto(imageRepository.findAll(specification)); + } + + /** + * Return a {@link Page} of {@link ImageDTO} which matches the criteria from the database. + * @param criteria The object which holds all the filters, which the entities should match. + * @param page The page, which should be returned. + * @return the matching entities. + */ + @Transactional(readOnly = true) + public Page<ImageDTO> findByCriteria(ImageCriteria criteria, Pageable page) { + log.debug("find by criteria : {}, page: {}", criteria, page); + final Specification<Image> specification = createSpecification(criteria); + return imageRepository.findAll(specification, page).map(imageMapper::toDto); + } + + /** + * Return the number of matching entities in the database. + * @param criteria The object which holds all the filters, which the entities should match. + * @return the number of matching entities. + */ + @Transactional(readOnly = true) + public long countByCriteria(ImageCriteria criteria) { + log.debug("count by criteria : {}", criteria); + final Specification<Image> specification = createSpecification(criteria); + return imageRepository.count(specification); + } + + /** + * Function to convert {@link ImageCriteria} to a {@link Specification} + * @param criteria The object which holds all the filters, which the entities should match. + * @return the matching {@link Specification} of the entity. + */ + protected Specification<Image> createSpecification(ImageCriteria criteria) { + Specification<Image> specification = Specification.where(null); + if (criteria != null) { + if (criteria.getId() != null) { + specification = specification.and(buildRangeSpecification(criteria.getId(), Image_.id)); + } + if (criteria.getImageType() != null) { + specification = specification.and(buildStringSpecification(criteria.getImageType(), Image_.imageType)); + } + if (criteria.getImageName() != null) { + specification = specification.and(buildStringSpecification(criteria.getImageName(), Image_.imageName)); + } + if (criteria.getImageUrl() != null) { + specification = specification.and(buildStringSpecification(criteria.getImageUrl(), Image_.imageUrl)); + } + if (criteria.getImageDescription() != null) { + specification = specification.and(buildStringSpecification(criteria.getImageDescription(), Image_.imageDescription)); + } + if (criteria.getImageProvider() != null) { + specification = specification.and(buildStringSpecification(criteria.getImageProvider(), Image_.imageProvider)); + } + if (criteria.getCreatedDate() != null) { + specification = specification.and(buildRangeSpecification(criteria.getCreatedDate(), Image_.createdDate)); + } + if (criteria.getLastModifiedDate() != null) { + specification = specification.and(buildRangeSpecification(criteria.getLastModifiedDate(), Image_.lastModifiedDate)); + } + if (criteria.getDeletedDate() != null) { + specification = specification.and(buildRangeSpecification(criteria.getDeletedDate(), Image_.deletedDate)); + } + } + return specification; + } +} diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/service/ImageService.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/ImageService.java new file mode 100644 index 0000000..83e620a --- /dev/null +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/ImageService.java @@ -0,0 +1,52 @@ +package com.piacere.iec.backend.service; + +import java.util.Optional; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +import com.piacere.iec.backend.service.dto.ImageDTO; + +/** + * Service Interface for managing {@link com.piacere.iec.backend.domain.Image}. + */ +public interface ImageService { + /** + * Save an image. + * + * @param ImageDTO the entity to save. + * @return the persisted entity. + */ + ImageDTO save(ImageDTO imageDTO); + + /** + * Partially updates an image. + * + * @param imageDTO the entity to update partially. + * @return the persisted entity. + */ + Optional<ImageDTO> partialUpdate(ImageDTO imageDTO); + + /** + * Get all the images. + * + * @param pageable the pagination information. + * @return the list of entities. + */ + Page<ImageDTO> findAll(Pageable pageable); + + /** + * Get the "id" image. + * + * @param id the id of the entity. + * @return the entity. + */ + Optional<ImageDTO> findOne(Long id); + + /** + * Delete the "id" image. + * + * @param id the id of the entity. + */ + void delete(Long id); +} diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/service/criteria/ExistingResourceCriteria.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/criteria/ExistingResourceCriteria.java new file mode 100644 index 0000000..30cc519 --- /dev/null +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/criteria/ExistingResourceCriteria.java @@ -0,0 +1,259 @@ +package com.piacere.iec.backend.service.criteria; + +import java.io.Serializable; +import java.util.Objects; + +import tech.jhipster.service.Criteria; +import tech.jhipster.service.filter.Filter; +import tech.jhipster.service.filter.InstantFilter; +import tech.jhipster.service.filter.LongFilter; +import tech.jhipster.service.filter.StringFilter; + +/** + * Criteria class for the {@link com.piacere.iec.backend.domain.ExistingResource} entity. This class is used + * in {@link com.piacere.iec.backend.web.rest.ExistingResourceResource} to receive all the possible filtering options from + * the Http GET request parameters. + * For example the following could be a valid request: + * {@code /existing-resources?id.greaterThan=5&attr1.contains=something&attr2.specified=false} + * As Spring is unable to properly convert the types, unless specific {@link Filter} class are used, we need to use + * fix type specific filters. + */ +public class ExistingResourceCriteria implements Serializable, Criteria { + + private static final long serialVersionUID = 1L; + + private LongFilter id; + + private StringFilter dataName; + + private StringFilter dataType; + + private StringFilter name; + + private StringFilter datacenterId; + + private StringFilter user; + + private StringFilter provider; + + private InstantFilter createdDate; + + private InstantFilter lastModifiedDate; + + private InstantFilter deletedDate; + + public ExistingResourceCriteria() {} + + public ExistingResourceCriteria(ExistingResourceCriteria other) { + this.id = other.id == null ? null : other.id.copy(); + this.dataName = other.dataName == null ? null : other.dataName.copy(); + this.dataType = other.dataType == null ? null : other.dataType.copy(); + this.name = other.name == null ? null : other.name.copy(); + this.datacenterId = other.datacenterId == null ? null : other.datacenterId.copy(); + this.user = other.user == null ? null : other.user.copy(); + this.provider = other.provider == null ? null : other.provider.copy(); + this.createdDate = other.createdDate == null ? null : other.createdDate.copy(); + this.lastModifiedDate = other.lastModifiedDate == null ? null : other.lastModifiedDate.copy(); + this.deletedDate = other.deletedDate == null ? null : other.deletedDate.copy(); + } + + @Override + public ExistingResourceCriteria copy() { + return new ExistingResourceCriteria(this); + } + + public LongFilter getId() { + return id; + } + + public LongFilter id() { + if (id == null) { + id = new LongFilter(); + } + return id; + } + + public void setId(LongFilter id) { + this.id = id; + } + + public StringFilter getDataName() { + return dataName; + } + + public StringFilter dataName() { + if (dataName == null) { + dataName = new StringFilter(); + } + return dataName; + } + + public void setDataName(StringFilter dataName) { + this.dataName = dataName; + } + + public StringFilter getDataType() { + return dataType; + } + + public StringFilter dataType() { + if (dataType == null) { + dataType = new StringFilter(); + } + return dataType; + } + + public void setDataType(StringFilter dataType) { + this.dataType = dataType; + } + + public StringFilter getName() { + return name; + } + + public StringFilter name() { + if (name == null) { + name = new StringFilter(); + } + return name; + } + + public void setName(StringFilter name) { + this.name = name; + } + + public StringFilter getDatacenterId() { + return datacenterId; + } + + public StringFilter datacenterId() { + if (datacenterId == null) { + datacenterId = new StringFilter(); + } + return datacenterId; + } + + public void setDatacenterId(StringFilter datacenterId) { + this.datacenterId = datacenterId; + } + + public StringFilter getUser() { + return user; + } + + public StringFilter user() { + if (user == null) { + user = new StringFilter(); + } + return user; + } + + public void setUser(StringFilter user) { + this.user = user; + } + + public StringFilter getProvider() { + return provider; + } + + public StringFilter provider() { + if (provider == null) { + provider = new StringFilter(); + } + return provider; + } + + public void setProvider(StringFilter provider) { + this.provider = provider; + } + + public InstantFilter getCreatedDate() { + return createdDate; + } + + public InstantFilter createdDate() { + if (createdDate == null) { + createdDate = new InstantFilter(); + } + return createdDate; + } + + public void setCreatedDate(InstantFilter createdDate) { + this.createdDate = createdDate; + } + + public InstantFilter getLastModifiedDate() { + return lastModifiedDate; + } + + public InstantFilter lastModifiedDate() { + if (lastModifiedDate == null) { + lastModifiedDate = new InstantFilter(); + } + return lastModifiedDate; + } + + public void setLastModifiedDate(InstantFilter lastModifiedDate) { + this.lastModifiedDate = lastModifiedDate; + } + + public InstantFilter getDeletedDate() { + return deletedDate; + } + + public InstantFilter deletedDate() { + if (deletedDate == null) { + deletedDate = new InstantFilter(); + } + return deletedDate; + } + + public void setDeletedDate(InstantFilter deletedDate) { + this.deletedDate = deletedDate; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final ExistingResourceCriteria that = (ExistingResourceCriteria) o; + return ( + Objects.equals(id, that.id) && + Objects.equals(dataName, that.dataName) && + Objects.equals(dataType, that.dataType) && + Objects.equals(name, that.name) && + Objects.equals(datacenterId, that.datacenterId) && + Objects.equals(user, that.user) && + Objects.equals(provider, that.provider) && + Objects.equals(createdDate, that.createdDate) && + Objects.equals(lastModifiedDate, that.lastModifiedDate) && + Objects.equals(deletedDate, that.deletedDate) + ); + } + + @Override + public int hashCode() { + return Objects.hash(id, dataName, dataType, name, datacenterId, user, provider, createdDate, lastModifiedDate, deletedDate); + } + + // prettier-ignore + @Override + public String toString() { + return "ExistingResourceCriteria{" + + (id != null ? "id=" + id + ", " : "") + + (dataName != null ? "dataName=" + dataName + ", " : "") + + (dataType != null ? "dataType=" + dataType + ", " : "") + + (name != null ? "name=" + name + ", " : "") + + (datacenterId != null ? "datacenterId=" + datacenterId + ", " : "") + + (user != null ? "user=" + user + ", " : "") + + (provider != null ? "provider=" + provider + ", " : "") + + (createdDate != null ? "createdDate=" + createdDate + ", " : "") + + (lastModifiedDate != null ? "lastModifiedDate=" + lastModifiedDate + ", " : "") + + (deletedDate != null ? "deletedDate=" + deletedDate + ", " : "") + + "}"; + } +} diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/service/criteria/ImageCriteria.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/criteria/ImageCriteria.java new file mode 100644 index 0000000..f40789b --- /dev/null +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/criteria/ImageCriteria.java @@ -0,0 +1,239 @@ +package com.piacere.iec.backend.service.criteria; + +import java.io.Serializable; +import java.util.Objects; + +import tech.jhipster.service.Criteria; +import tech.jhipster.service.filter.Filter; +import tech.jhipster.service.filter.InstantFilter; +import tech.jhipster.service.filter.LongFilter; +import tech.jhipster.service.filter.StringFilter; + +/** + * Criteria class for the {@link com.piacere.iec.backend.domain.Image} entity. This class is used + * in {@link com.piacere.iec.backend.web.rest.ImageResource} to receive all the possible filtering options from + * the Http GET request parameters. + * For example the following could be a valid request: + * {@code /images?id.greaterThan=5&attr1.contains=something&attr2.specified=false} + * As Spring is unable to properly convert the types, unless specific {@link Filter} class are used, we need to use + * fix type specific filters. + */ +public class ImageCriteria implements Serializable, Criteria { + + private static final long serialVersionUID = 1L; + + private LongFilter id; + + private StringFilter imageType; + + private StringFilter imageName; + + private StringFilter imageUrl; + + private StringFilter imageDescription; + + private StringFilter imageProvider; + + private InstantFilter createdDate; + + private InstantFilter lastModifiedDate; + + private InstantFilter deletedDate; + + public ImageCriteria() {} + + public ImageCriteria(ImageCriteria other) { + this.id = other.id == null ? null : other.id.copy(); + this.imageType = other.imageType == null ? null : other.imageType.copy(); + this.imageName = other.imageName == null ? null : other.imageName.copy(); + this.imageUrl = other.imageUrl == null ? null : other.imageUrl.copy(); + this.imageDescription = other.imageDescription == null ? null : other.imageDescription.copy(); + this.imageProvider = other.imageProvider == null ? null : other.imageProvider.copy(); + this.createdDate = other.createdDate == null ? null : other.createdDate.copy(); + this.lastModifiedDate = other.lastModifiedDate == null ? null : other.lastModifiedDate.copy(); + this.deletedDate = other.deletedDate == null ? null : other.deletedDate.copy(); + } + + @Override + public ImageCriteria copy() { + return new ImageCriteria(this); + } + + public LongFilter getId() { + return id; + } + + public LongFilter id() { + if (id == null) { + id = new LongFilter(); + } + return id; + } + + public void setId(LongFilter id) { + this.id = id; + } + + public StringFilter getImageType() { + return imageType; + } + + public StringFilter imageType() { + if (imageType == null) { + imageType = new StringFilter(); + } + return imageType; + } + + public void setImageType(StringFilter imageType) { + this.imageType = imageType; + } + + public StringFilter getImageName() { + return imageName; + } + + public StringFilter imageName() { + if (imageName == null) { + imageName = new StringFilter(); + } + return imageName; + } + + public void setImageName(StringFilter imageName) { + this.imageName = imageName; + } + + public StringFilter getImageUrl() { + return imageUrl; + } + + public StringFilter imageUrl() { + if (imageUrl == null) { + imageUrl = new StringFilter(); + } + return imageUrl; + } + + public void setImageUrl(StringFilter imageUrl) { + this.imageUrl = imageUrl; + } + + public StringFilter getImageDescription() { + return imageDescription; + } + + public StringFilter imageDescription() { + if (imageDescription == null) { + imageDescription = new StringFilter(); + } + return imageDescription; + } + + public void setImageDescription(StringFilter imageDescription) { + this.imageDescription = imageDescription; + } + + public StringFilter getImageProvider() { + return imageProvider; + } + + public StringFilter imageProvider() { + if (imageProvider == null) { + imageProvider = new StringFilter(); + } + return imageProvider; + } + + public void setImageProvider(StringFilter imageProvider) { + this.imageProvider = imageProvider; + } + + public InstantFilter getCreatedDate() { + return createdDate; + } + + public InstantFilter createdDate() { + if (createdDate == null) { + createdDate = new InstantFilter(); + } + return createdDate; + } + + public void setCreatedDate(InstantFilter createdDate) { + this.createdDate = createdDate; + } + + public InstantFilter getLastModifiedDate() { + return lastModifiedDate; + } + + public InstantFilter lastModifiedDate() { + if (lastModifiedDate == null) { + lastModifiedDate = new InstantFilter(); + } + return lastModifiedDate; + } + + public void setLastModifiedDate(InstantFilter lastModifiedDate) { + this.lastModifiedDate = lastModifiedDate; + } + + public InstantFilter getDeletedDate() { + return deletedDate; + } + + public InstantFilter deletedDate() { + if (deletedDate == null) { + deletedDate = new InstantFilter(); + } + return deletedDate; + } + + public void setDeletedDate(InstantFilter deletedDate) { + this.deletedDate = deletedDate; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final ImageCriteria that = (ImageCriteria) o; + return ( + Objects.equals(id, that.id) && + Objects.equals(imageType, that.imageType) && + Objects.equals(imageName, that.imageName) && + Objects.equals(imageUrl, that.imageUrl) && + Objects.equals(imageDescription, that.imageDescription) && + Objects.equals(imageProvider, that.imageProvider) && + Objects.equals(createdDate, that.createdDate) && + Objects.equals(lastModifiedDate, that.lastModifiedDate) && + Objects.equals(deletedDate, that.deletedDate) + ); + } + + @Override + public int hashCode() { + return Objects.hash(id, imageType, imageName, imageUrl, imageDescription, imageProvider, createdDate, lastModifiedDate, deletedDate); + } + + // prettier-ignore + @Override + public String toString() { + return "ImageCriteria{" + + (id != null ? "id=" + id + ", " : "") + + (imageType != null ? "imageType=" + imageType + ", " : "") + + (imageName != null ? "imageName=" + imageName + ", " : "") + + (imageUrl != null ? "imageUrl=" + imageUrl + ", " : "") + + (imageDescription != null ? "imageDescription=" + imageDescription + ", " : "") + + (imageProvider != null ? "imageProvider=" + imageProvider + ", " : "") + + (createdDate != null ? "createdDate=" + createdDate + ", " : "") + + (lastModifiedDate != null ? "lastModifiedDate=" + lastModifiedDate + ", " : "") + + (deletedDate != null ? "deletedDate=" + deletedDate + ", " : "") + + "}"; + } +} diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/service/dto/ExistingResourceDTO.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/dto/ExistingResourceDTO.java new file mode 100644 index 0000000..bc59b50 --- /dev/null +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/dto/ExistingResourceDTO.java @@ -0,0 +1,177 @@ +package com.piacere.iec.backend.service.dto; + +import java.io.Serializable; +import java.time.Instant; +import java.util.Objects; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +/** + * A DTO for the {@link com.piacere.iec.backend.domain.ExistingResourceDTO} entity. + */ +public class ExistingResourceDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + private Long id; + + @NotNull + @Size(max = 70) + private String dataName; + + @NotNull + @Size(max = 70) + private String dataType; + + @NotNull + @Size(max = 70) + private String name; + + @NotNull + @Size(max = 70) + private String datacenterId; + + @NotNull + @Size(max = 70) + private String user; + + @NotNull + @Size(max = 70) + private String provider; + + @NotNull + @JsonIgnore + private Instant createdDate; + + @JsonIgnore + private Instant lastModifiedDate; + + @JsonIgnore + private Instant deletedDate; + + public ExistingResourceDTO() { + super(); + } + + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getDataName() { + return dataName; + } + + public void setDataName(String dataName) { + this.dataName = dataName; + } + + public String getDataType() { + return dataType; + } + + public void setDataType(String dataType) { + this.dataType = dataType; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDatacenterId() { + return datacenterId; + } + + public void setDatacenterId(String datacenterId) { + this.datacenterId = datacenterId; + } + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public String getProvider() { + return provider; + } + + public void setProvider(String provider) { + this.provider = provider; + } + + public Instant getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(Instant createdDate) { + this.createdDate = createdDate; + } + + public Instant getLastModifiedDate() { + return lastModifiedDate; + } + + public void setLastModifiedDate(Instant lastModifiedDate) { + this.lastModifiedDate = lastModifiedDate; + } + + public Instant getDeletedDate() { + return deletedDate; + } + + public void setDeletedDate(Instant deletedDate) { + this.deletedDate = deletedDate; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ExistingResourceDTO)) { + return false; + } + + ExistingResourceDTO existingResourceDTO = (ExistingResourceDTO) o; + if (this.id == null) { + return false; + } + return Objects.equals(this.id, existingResourceDTO.id); + } + + @Override + public int hashCode() { + return Objects.hash(this.id); + } + + // prettier-ignore + @Override + public String toString() { + return "ExistingResourceDTO{" + + "id=" + getId() + + ", dataName='" + getDataName() + "'" + + ", dataType='" + getDataType() + "'" + + ", name='" + getName() + "'" + + ", datacenterId='" + getDatacenterId() + "'" + + ", user='" + getUser() + "'" + + ", provider='" + getProvider() + "'" + + ", createdDate='" + getCreatedDate() + "'" + + ", lastModifiedDate='" + getLastModifiedDate() + "'" + + ", deletedDate='" + getDeletedDate() + "'" + + "}"; + } +} diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/service/dto/ImageDTO.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/dto/ImageDTO.java new file mode 100644 index 0000000..84b77d4 --- /dev/null +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/dto/ImageDTO.java @@ -0,0 +1,160 @@ +package com.piacere.iec.backend.service.dto; + +import java.io.Serializable; +import java.time.Instant; +import java.util.Objects; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +/** + * A DTO for the {@link com.piacere.iec.backend.domain.ImageDTO} entity. + */ +public class ImageDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + private Long id; + + @NotNull + @Size(max = 10) + private String imageType; + + @Size(max = 70) + private String imageName; + + @Size(max = 255) + private String imageUrl; + + private String imageDescription; + + @NotNull + @Size(max = 70) + private String imageProvider; + + @NotNull + @JsonIgnore + private Instant createdDate; + + @JsonIgnore + private Instant lastModifiedDate; + + @JsonIgnore + private Instant deletedDate; + + public ImageDTO() { + super(); + } + + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getImageType() { + return imageType; + } + + public void setImageType(String imageType) { + this.imageType = imageType; + } + + public String getImageName() { + return imageName; + } + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public String getImageUrl() { + return imageUrl; + } + + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } + + public String getImageDescription() { + return imageDescription; + } + + public void setImageDescription(String imageDescription) { + this.imageDescription = imageDescription; + } + + public String getImageProvider() { + return imageProvider; + } + + public void setImageProvider(String imageProvider) { + this.imageProvider = imageProvider; + } + + public Instant getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(Instant createdDate) { + this.createdDate = createdDate; + } + + public Instant getLastModifiedDate() { + return lastModifiedDate; + } + + public void setLastModifiedDate(Instant lastModifiedDate) { + this.lastModifiedDate = lastModifiedDate; + } + + public Instant getDeletedDate() { + return deletedDate; + } + + public void setDeletedDate(Instant deletedDate) { + this.deletedDate = deletedDate; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ImageDTO)) { + return false; + } + + ImageDTO imageDTO = (ImageDTO) o; + if (this.id == null) { + return false; + } + return Objects.equals(this.id, imageDTO.id); + } + + @Override + public int hashCode() { + return Objects.hash(this.id); + } + + // prettier-ignore + @Override + public String toString() { + return "imageDTO{" + + "id=" + getId() + + ", imageType='" + getImageType() + "'" + + ", imageName='" + getImageName() + "'" + + ", imageUrl='" + getImageUrl() + "'" + + ", imageDescription='" + getImageDescription() + "'" + + ", imageProvider='" + getImageProvider() + "'" + + ", createdDate='" + getCreatedDate() + "'" + + ", lastModifiedDate='" + getLastModifiedDate() + "'" + + ", deletedDate='" + getDeletedDate() + "'" + + "}"; + } +} diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/service/dto/ServiceAttributeValueDTO.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/dto/ServiceAttributeValueDTO.java index de9dd5f..95afeeb 100644 --- a/git/iec-backend/src/main/java/com/piacere/iec/backend/service/dto/ServiceAttributeValueDTO.java +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/dto/ServiceAttributeValueDTO.java @@ -12,7 +12,9 @@ import javax.validation.constraints.Size; */ public class ServiceAttributeValueDTO implements Serializable { - private Long id; + private static final long serialVersionUID = 1L; + + private Long id; @Size(max = 50) private String serviceAttributeValue; diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/service/impl/ExistingResourceServiceImpl.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/impl/ExistingResourceServiceImpl.java new file mode 100644 index 0000000..33e4e22 --- /dev/null +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/impl/ExistingResourceServiceImpl.java @@ -0,0 +1,80 @@ +package com.piacere.iec.backend.service.impl; + +import java.util.Optional; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.piacere.iec.backend.domain.ExistingResource; +import com.piacere.iec.backend.repository.ExistingResourceRepository; +import com.piacere.iec.backend.service.ExistingResourceService; +import com.piacere.iec.backend.service.dto.ExistingResourceDTO; +import com.piacere.iec.backend.service.mapper.ExistingResourceMapper; + +/** + * Service Implementation for managing {@link ExistingResource}. + */ +@Service +@Transactional +public class ExistingResourceServiceImpl implements ExistingResourceService { + + private final Logger log = LoggerFactory.getLogger(ExistingResourceServiceImpl.class); + + private final ExistingResourceRepository existingResourceRepository; + private final ExistingResourceMapper existingResourceMapper; + + public ExistingResourceServiceImpl( + ExistingResourceRepository existingResourceRepository, + ExistingResourceMapper existingResourceMapper) { + this.existingResourceRepository = existingResourceRepository; + this.existingResourceMapper = existingResourceMapper; + } + + @Override + public ExistingResourceDTO save(ExistingResourceDTO existingResourceDTO) { + log.debug("Request to save ExistingResource : {}", existingResourceDTO); + ExistingResource existingResource = existingResourceMapper.toEntity(existingResourceDTO); + existingResource = existingResourceRepository.save(existingResource); + return existingResourceMapper.toDto(existingResource); + } + + @Override + public Optional<ExistingResourceDTO> partialUpdate(ExistingResourceDTO existingResourceDTO) { + log.debug("Request to partially update ExistingResource : {}", existingResourceDTO); + + return existingResourceRepository + .findById(existingResourceDTO.getId()) + .map( + existingExistingResource -> { + existingResourceMapper.partialUpdate(existingExistingResource, existingResourceDTO); + return existingExistingResource; + } + ) + .map(existingResourceRepository::save) + .map(existingResourceMapper::toDto); + } + + @Override + @Transactional(readOnly = true) + public Page<ExistingResourceDTO> findAll(Pageable pageable) { + log.debug("Request to get all ExistingResources"); + return existingResourceRepository.findAll(pageable).map(existingResourceMapper::toDto); + } + + @Override + @Transactional(readOnly = true) + public Optional<ExistingResourceDTO> findOne(Long id) { + log.debug("Request to get ExistingResources : {}", id); + return existingResourceRepository.findById(id).map(existingResourceMapper::toDto); + } + + @Override + public void delete(Long id) { + log.debug("Request to delete ExistingResource : {}", id); + existingResourceRepository.deleteById(id); + } +} diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/service/impl/ImageServiceImpl.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/impl/ImageServiceImpl.java new file mode 100644 index 0000000..a9a1068 --- /dev/null +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/impl/ImageServiceImpl.java @@ -0,0 +1,80 @@ +package com.piacere.iec.backend.service.impl; + +import java.util.Optional; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.piacere.iec.backend.domain.Image; +import com.piacere.iec.backend.repository.ImageRepository; +import com.piacere.iec.backend.service.ImageService; +import com.piacere.iec.backend.service.dto.ImageDTO; +import com.piacere.iec.backend.service.mapper.ImageMapper; + +/** + * Service Implementation for managing {@link Image}. + */ +@Service +@Transactional +public class ImageServiceImpl implements ImageService { + + private final Logger log = LoggerFactory.getLogger(ImageServiceImpl.class); + + private final ImageRepository imageRepository; + private final ImageMapper imageMapper; + + public ImageServiceImpl( + ImageRepository imageRepository, + ImageMapper imageMapper) { + this.imageRepository = imageRepository; + this.imageMapper = imageMapper; + } + + @Override + public ImageDTO save(ImageDTO imageDTO) { + log.debug("Request to save Image : {}", imageDTO); + Image image = imageMapper.toEntity(imageDTO); + image = imageRepository.save(image); + return imageMapper.toDto(image); + } + + @Override + public Optional<ImageDTO> partialUpdate(ImageDTO imageDTO) { + log.debug("Request to partially update Image : {}", imageDTO); + + return imageRepository + .findById(imageDTO.getId()) + .map( + existingImage -> { + imageMapper.partialUpdate(existingImage, imageDTO); + return existingImage; + } + ) + .map(imageRepository::save) + .map(imageMapper::toDto); + } + + @Override + @Transactional(readOnly = true) + public Page<ImageDTO> findAll(Pageable pageable) { + log.debug("Request to get all Images"); + return imageRepository.findAll(pageable).map(imageMapper::toDto); + } + + @Override + @Transactional(readOnly = true) + public Optional<ImageDTO> findOne(Long id) { + log.debug("Request to get Images : {}", id); + return imageRepository.findById(id).map(imageMapper::toDto); + } + + @Override + public void delete(Long id) { + log.debug("Request to delete Image : {}", id); + imageRepository.deleteById(id); + } +} diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/service/mapper/ExistingResourceMapper.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/mapper/ExistingResourceMapper.java new file mode 100644 index 0000000..2315214 --- /dev/null +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/mapper/ExistingResourceMapper.java @@ -0,0 +1,18 @@ +package com.piacere.iec.backend.service.mapper; + +import com.piacere.iec.backend.domain.*; +import com.piacere.iec.backend.service.dto.ExistingResourceDTO; +import org.mapstruct.*; + +/** + * Mapper for the entity {@link ExistingResource} and its DTO {@link ExistingResourceDTO}. + */ +@Mapper(componentModel = "spring", uses = { RootServiceMapper.class }) +public interface ExistingResourceMapper extends EntityMapper<ExistingResourceDTO, ExistingResource> { + ExistingResourceDTO toDto(ExistingResource s); + + @Named("id") + @BeanMapping(ignoreByDefault = true) + @Mapping(target = "id", source = "id") + ExistingResourceDTO toDtoId(ExistingResource existingResource); +} diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/service/mapper/ImageMapper.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/mapper/ImageMapper.java new file mode 100644 index 0000000..adc364c --- /dev/null +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/service/mapper/ImageMapper.java @@ -0,0 +1,22 @@ +package com.piacere.iec.backend.service.mapper; + +import org.mapstruct.BeanMapping; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; + +import com.piacere.iec.backend.domain.Image; +import com.piacere.iec.backend.service.dto.ImageDTO; + +/** + * Mapper for the entity {@link Image} and its DTO {@link ImageDTO}. + */ +@Mapper(componentModel = "spring", uses = { RootServiceMapper.class }) +public interface ImageMapper extends EntityMapper<ImageDTO, Image> { + ImageDTO toDto(Image s); + + @Named("id") + @BeanMapping(ignoreByDefault = true) + @Mapping(target = "id", source = "id") + ImageDTO toDtoId(Image image); +} diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/util/CollectionUtil.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/util/CollectionUtil.java new file mode 100644 index 0000000..d36fce8 --- /dev/null +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/util/CollectionUtil.java @@ -0,0 +1,64 @@ +package com.piacere.iec.backend.util; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + + +/** + * Utilities to manage collections. + * @author Tecnalia + * @version 1.0 + */ +public final class CollectionUtil { + + /** + * Checks if an array is null or empty. + * @param sourceArray The source array. + * @return boolean + */ + public static boolean isNullOrEmpty(final Object[] sourceArray) { + return sourceArray == null || sourceArray.length == 0; + } + + + /** + * Checks if a List is null or empty. + * @param sourceList The source list. + * @return boolean + */ + public static boolean isNullOrEmpty(final List<?> sourceList) { + return sourceList == null || sourceList.isEmpty(); + } + + + /** + * Checks if a Map is null or empty. + * @param sourceMap The source map. + * @return boolean + */ + public static boolean isNullOrEmpty(final Map<?, ?> sourceMap) { + return sourceMap == null || sourceMap.isEmpty(); + } + + + /** + * Checks if a Set is null or empty. + * @param sourceSet The source set. + * @return boolean + */ + public static boolean isNullOrEmpty(final Set<?> sourceSet) { + return sourceSet == null || sourceSet.isEmpty(); + } + + + /** + * Checks if a Collection is null or empty. + * @param sourceSet The source set. + * @return boolean + */ + public static boolean isNullOrEmpty(final Collection<?> sourceCollection) { + return sourceCollection == null || sourceCollection.isEmpty(); + } +} \ No newline at end of file diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/web/rest/ExistingResourceResource.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/web/rest/ExistingResourceResource.java new file mode 100644 index 0000000..40f5084 --- /dev/null +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/web/rest/ExistingResourceResource.java @@ -0,0 +1,180 @@ +package com.piacere.iec.backend.web.rest; + +import java.net.URI; +import java.net.URISyntaxException; +import java.time.Instant; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import javax.validation.constraints.NotNull; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import com.piacere.iec.backend.repository.ExistingResourceRepository; +import com.piacere.iec.backend.service.ExistingResourceQueryService; +import com.piacere.iec.backend.service.ExistingResourceService; +import com.piacere.iec.backend.service.criteria.ExistingResourceCriteria; +import com.piacere.iec.backend.service.dto.ExistingResourceDTO; +import com.piacere.iec.backend.web.rest.errors.BadRequestAlertException; + +import tech.jhipster.web.util.HeaderUtil; +import tech.jhipster.web.util.PaginationUtil; +import tech.jhipster.web.util.ResponseUtil; + +/** + * REST controller for managing {@link com.piacere.iec.backend.domain.ExistingResource}. + */ +@RestController +@RequestMapping("/api") +public class ExistingResourceResource { + + private final Logger log = LoggerFactory.getLogger(ExistingResourceResource.class); + + private static final String ENTITY_NAME = "existingResource"; + + @Value("${jhipster.clientApp.name}") + private String applicationName; + + private final ExistingResourceService existingResourceService; + + private final ExistingResourceRepository existingResourceRepository; + + private final ExistingResourceQueryService existingResourceQueryService; + + public ExistingResourceResource( + ExistingResourceService existingResourceService, + ExistingResourceRepository existingResourceRepository, + ExistingResourceQueryService existingResourceQueryService + ) { + this.existingResourceService = existingResourceService; + this.existingResourceRepository = existingResourceRepository; + this.existingResourceQueryService = existingResourceQueryService; + } + + /** + * {@code POST /existing-resources} : Create a new existingResource. + * + * @param existingResourceDTO the existingResourceDTO to create. + * @return the {@link ResponseEntity} with status {@code 201 (Created)} and with body the new existingResourceDTO, or with status {@code 400 (Bad Request)} if the existingResource has already an ID. + * @throws URISyntaxException if the Location URI syntax is incorrect. + */ + @PostMapping("/existing-resources") + public ResponseEntity<ExistingResourceDTO> createExistingResource(@RequestBody ExistingResourceDTO existingResourceDTO) throws URISyntaxException { + log.debug("REST request to save ExistingResource : {}", existingResourceDTO); + existingResourceDTO.setId(null); + existingResourceDTO.setCreatedDate(Instant.now()); + ExistingResourceDTO result = existingResourceService.save(existingResourceDTO); + return ResponseEntity + .created(new URI("/api/existing-resources/" + result.getId())) + .headers(HeaderUtil.createEntityCreationAlert(applicationName, false, ENTITY_NAME, result.getId().toString())) + .body(result); + } + + /** + * {@code PUT /existing-resources/:id} : Updates an existing existingResource. + * + * @param id the id of the existingResourceDTO to save. + * @param existingResourceDTO the existingResourceDTO to update. + * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the updated existingResourceDTO, + * or with status {@code 400 (Bad Request)} if the existingResourceDTO is not valid, + * or with status {@code 500 (Internal Server Error)} if the existingResourceDTO couldn't be updated. + * @throws URISyntaxException if the Location URI syntax is incorrect. + */ + @PutMapping(value = "/existing-resources/{id}") + public ResponseEntity<ExistingResourceDTO> updateExistingResource( + @PathVariable(value = "id", required = false) final Long id, + @NotNull @RequestBody ExistingResourceDTO existingResourceDTO + ) throws URISyntaxException { + log.debug("REST request to update ExistingResource : {}, {}", id, existingResourceDTO); + if (existingResourceDTO.getId() == null) { + throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull"); + } + if (!Objects.equals(id, existingResourceDTO.getId())) { + throw new BadRequestAlertException("Invalid ID", ENTITY_NAME, "idinvalid"); + } + + if (!existingResourceRepository.existsById(id)) { + throw new BadRequestAlertException("Entity not found", ENTITY_NAME, "idnotfound"); + } + + existingResourceDTO.setLastModifiedDate(Instant.now()); + Optional<ExistingResourceDTO> result = existingResourceService.partialUpdate(existingResourceDTO); + + return ResponseUtil.wrapOrNotFound( + result, + HeaderUtil.createEntityUpdateAlert(applicationName, false, ENTITY_NAME, existingResourceDTO.getId().toString()) + ); + } + + /** + * {@code GET /existing-resources} : get all the existingResources. + * + * @param pageable the pagination information. + * @param criteria the criteria which the requested entities should match. + * @return the {@link ResponseEntity} with status {@code 200 (OK)} and the list of existingResources in body. + */ + @GetMapping("/existing-resources") + public ResponseEntity<List<ExistingResourceDTO>> getAllExistingResources(ExistingResourceCriteria criteria, Pageable pageable) { + log.debug("REST request to get ExistingResources by criteria: {}", criteria); + Page<ExistingResourceDTO> page = existingResourceQueryService.findByCriteria(criteria, pageable); + HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(ServletUriComponentsBuilder.fromCurrentRequest(), page); + return ResponseEntity.ok().headers(headers).body(page.getContent()); + } + + /** + * {@code GET /existing-resources/count} : count all the existingResources. + * + * @param criteria the criteria which the requested entities should match. + * @return the {@link ResponseEntity} with status {@code 200 (OK)} and the count in body. + */ + @GetMapping("/existing-resources/count") + public ResponseEntity<Long> countExistingResources(ExistingResourceCriteria criteria) { + log.debug("REST request to count ExistingResources by criteria: {}", criteria); + return ResponseEntity.ok().body(existingResourceQueryService.countByCriteria(criteria)); + } + + /** + * {@code GET /existing-resources/:id} : get the "id" existingResource. + * + * @param id the id of the existingResourceDTO to retrieve. + * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the existingResourceDTO, or with status {@code 404 (Not Found)}. + */ + @GetMapping("/existing-resources/{id}") + public ResponseEntity<ExistingResourceDTO> getExistingResource(@PathVariable Long id) { + log.debug("REST request to get existingResource : {}", id); + Optional<ExistingResourceDTO> existingResourceDTO = existingResourceService.findOne(id); + return ResponseUtil.wrapOrNotFound(existingResourceDTO); + } + + /** + * {@code DELETE /existing-resources/:id} : delete the "id" existingResource. + * + * @param id the id of the existingResources to delete. + * @return the {@link ResponseEntity} with status {@code 204 (NO_CONTENT)}. + */ + @DeleteMapping("/existing-resources/{id}") + public ResponseEntity<Void> deleteExistingResource(@PathVariable Long id) { + log.debug("REST request to delete ExistingResource : {}", id); + existingResourceService.delete(id); + return ResponseEntity + .noContent() + .headers(HeaderUtil.createEntityDeletionAlert(applicationName, false, ENTITY_NAME, id.toString())) + .build(); + } +} diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/web/rest/ImageResource.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/web/rest/ImageResource.java new file mode 100644 index 0000000..75c5335 --- /dev/null +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/web/rest/ImageResource.java @@ -0,0 +1,183 @@ +package com.piacere.iec.backend.web.rest; + +import java.net.URI; +import java.net.URISyntaxException; +import java.time.Instant; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import javax.validation.constraints.NotNull; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import com.piacere.iec.backend.repository.ImageRepository; +import com.piacere.iec.backend.service.ImageQueryService; +import com.piacere.iec.backend.service.ImageService; +import com.piacere.iec.backend.service.criteria.ImageCriteria; +import com.piacere.iec.backend.service.dto.ImageDTO; +import com.piacere.iec.backend.web.rest.errors.BadRequestAlertException; + +import tech.jhipster.web.util.HeaderUtil; +import tech.jhipster.web.util.PaginationUtil; +import tech.jhipster.web.util.ResponseUtil; + +/** + * REST controller for managing {@link com.piacere.iec.backend.domain.Image}. + */ +@RestController +@RequestMapping("/api") +public class ImageResource { + + private final Logger log = LoggerFactory.getLogger(ImageResource.class); + + private static final String ENTITY_NAME = "image"; + + @Value("${jhipster.clientApp.name}") + private String applicationName; + + private final ImageService imageService; + + private final ImageRepository imageRepository; + + private final ImageQueryService imageQueryService; + + public ImageResource( + ImageService imageService, + ImageRepository imageRepository, + ImageQueryService imageQueryService + ) { + this.imageService = imageService; + this.imageRepository = imageRepository; + this.imageQueryService = imageQueryService; + } + + /** + * {@code POST /images} : Create a new image. + * + * @param imageDTO the imageDTO to create. + * @return the {@link ResponseEntity} with status {@code 201 (Created)} and with body the new imageDTO, or with status {@code 400 (Bad Request)} if the image has already an ID. + * @throws URISyntaxException if the Location URI syntax is incorrect. + */ + @PostMapping("/images") + public ResponseEntity<ImageDTO> createImage(@RequestBody ImageDTO imageDTO) throws URISyntaxException { + log.debug("REST request to save Image : {}", imageDTO); + imageDTO.setId(null); + imageDTO.setCreatedDate(Instant.now()); + ImageDTO result = imageService.save(imageDTO); + return ResponseEntity + .created(new URI("/api/images/" + result.getId())) + .headers(HeaderUtil.createEntityCreationAlert(applicationName, false, ENTITY_NAME, result.getId().toString())) + .body(result); + } + + /** + * {@code PUT /images/:id} : Updates an existing image. + * + * @param id the id of the imageDTO to save. + * @param imageDTO the imageDTO to update. + * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the updated imageDTO, + * or with status {@code 400 (Bad Request)} if the imageDTO is not valid, + * or with status {@code 500 (Internal Server Error)} if the imageDTO couldn't be updated. + * @throws URISyntaxException if the Location URI syntax is incorrect. + */ + @PutMapping(value = "/images/{id}") + public ResponseEntity<ImageDTO> updateImage( + @PathVariable(value = "id", required = false) final Long id, + @NotNull @RequestBody ImageDTO imageDTO + ) throws URISyntaxException { + log.debug("REST request to update ImageDTO : {}, {}", id, imageDTO); + /* + if (imageDTO.getId() == null) { + throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull"); + } + if (!Objects.equals(id, imageDTO.getId())) { + throw new BadRequestAlertException("Invalid ID", ENTITY_NAME, "idinvalid"); + } + */ + + if (!imageRepository.existsById(id)) { + throw new BadRequestAlertException("Entity not found", ENTITY_NAME, "idnotfound"); + } + + imageDTO.setId(id); + imageDTO.setLastModifiedDate(Instant.now()); + Optional<ImageDTO> result = imageService.partialUpdate(imageDTO); + + return ResponseUtil.wrapOrNotFound( + result, + HeaderUtil.createEntityUpdateAlert(applicationName, false, ENTITY_NAME, imageDTO.getId().toString()) + ); + } + + /** + * {@code GET /images} : get all the images. + * + * @param pageable the pagination information. + * @param criteria the criteria which the requested entities should match. + * @return the {@link ResponseEntity} with status {@code 200 (OK)} and the list of images in body. + */ + @GetMapping("/images") + public ResponseEntity<List<ImageDTO>> getAllImages(ImageCriteria criteria, Pageable pageable) { + log.debug("REST request to get Images by criteria: {}", criteria); + Page<ImageDTO> page = imageQueryService.findByCriteria(criteria, pageable); + HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(ServletUriComponentsBuilder.fromCurrentRequest(), page); + return ResponseEntity.ok().headers(headers).body(page.getContent()); + } + + /** + * {@code GET /images/count} : count all the images. + * + * @param criteria the criteria which the requested entities should match. + * @return the {@link ResponseEntity} with status {@code 200 (OK)} and the count in body. + */ + @GetMapping("/images/count") + public ResponseEntity<Long> countImages(ImageCriteria criteria) { + log.debug("REST request to count Images by criteria: {}", criteria); + return ResponseEntity.ok().body(imageQueryService.countByCriteria(criteria)); + } + + /** + * {@code GET /images/:id} : get the "id" image. + * + * @param id the id of the imageDTO to retrieve. + * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the imageDTO, or with status {@code 404 (Not Found)}. + */ + @GetMapping("/images/{id}") + public ResponseEntity<ImageDTO> getImage(@PathVariable Long id) { + log.debug("REST request to get image : {}", id); + Optional<ImageDTO> imageDTO = imageService.findOne(id); + return ResponseUtil.wrapOrNotFound(imageDTO); + } + + /** + * {@code DELETE /images/:id} : delete the "id" image. + * + * @param id the id of the images to delete. + * @return the {@link ResponseEntity} with status {@code 204 (NO_CONTENT)}. + */ + @DeleteMapping("/images/{id}") + public ResponseEntity<Void> deleteImage(@PathVariable Long id) { + log.debug("REST request to delete Image : {}", id); + imageService.delete(id); + return ResponseEntity + .noContent() + .headers(HeaderUtil.createEntityDeletionAlert(applicationName, false, ENTITY_NAME, id.toString())) + .build(); + } +} diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/web/rest/InstanceResource.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/web/rest/InstanceResource.java index 9b5fe8c..bb5d4d8 100644 --- a/git/iec-backend/src/main/java/com/piacere/iec/backend/web/rest/InstanceResource.java +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/web/rest/InstanceResource.java @@ -136,7 +136,7 @@ public class InstanceResource { * or with status {@code 500 (Internal Server Error)} if the instanceDTO couldn't be updated. * @throws URISyntaxException if the Location URI syntax is incorrect. */ - @PatchMapping(value = "/instances/{id}", consumes = "application/merge-patch+json") + @PatchMapping(value = "/instances/{id}", consumes = "application/json") public ResponseEntity<InstanceDTO> partialUpdateInstance( @PathVariable(value = "id", required = false) final Long id, @NotNull @RequestBody InstanceDTO instanceDTO diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/web/rest/RootServiceResource.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/web/rest/RootServiceResource.java index 42e15a2..466da1e 100644 --- a/git/iec-backend/src/main/java/com/piacere/iec/backend/web/rest/RootServiceResource.java +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/web/rest/RootServiceResource.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.Set; import javax.validation.Valid; import javax.validation.constraints.NotNull; @@ -31,11 +32,15 @@ import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import com.piacere.iec.backend.domain.vo.ServiceDevOpsInfoVO; import com.piacere.iec.backend.domain.vo.ServiceDevOpsQueryInfoVO; import com.piacere.iec.backend.repository.RootServiceRepository; +import com.piacere.iec.backend.service.DefinitionQueryService; import com.piacere.iec.backend.service.RootServiceQueryService; import com.piacere.iec.backend.service.RootServiceService; import com.piacere.iec.backend.service.criteria.RootServiceCriteria; +import com.piacere.iec.backend.service.dto.DefinitionDTO; import com.piacere.iec.backend.service.dto.RootServiceCatalogueDTO; import com.piacere.iec.backend.service.dto.RootServiceDTO; +import com.piacere.iec.backend.service.dto.ServiceAttributeValueCatalogueDTO; +import com.piacere.iec.backend.util.CollectionUtil; import com.piacere.iec.backend.web.rest.errors.BadRequestAlertException; import tech.jhipster.web.util.HeaderUtil; @@ -61,15 +66,19 @@ public class RootServiceResource { private final RootServiceRepository rootServiceRepository; private final RootServiceQueryService rootServiceQueryService; + + private final DefinitionQueryService definitionQueryService; public RootServiceResource( RootServiceService rootServiceService, RootServiceRepository rootServiceRepository, - RootServiceQueryService rootServiceQueryService + RootServiceQueryService rootServiceQueryService, + DefinitionQueryService definitionQueryService ) { this.rootServiceService = rootServiceService; this.rootServiceRepository = rootServiceRepository; this.rootServiceQueryService = rootServiceQueryService; + this.definitionQueryService = definitionQueryService; } /** @@ -82,9 +91,7 @@ public class RootServiceResource { @PostMapping("/root-services") public ResponseEntity<RootServiceDTO> createRootService(@Valid @RequestBody RootServiceDTO rootServiceDTO) throws URISyntaxException { log.debug("REST request to save RootService : {}", rootServiceDTO); - if (rootServiceDTO.getId() != null) { - throw new BadRequestAlertException("A new rootService cannot already have an ID", ENTITY_NAME, "idexists"); - } + rootServiceDTO.setId(null); RootServiceDTO result = rootServiceService.save(rootServiceDTO); return ResponseEntity .created(new URI("/api/root-services/" + result.getId())) @@ -137,7 +144,7 @@ public class RootServiceResource { * or with status {@code 500 (Internal Server Error)} if the rootServiceDTO couldn't be updated. * @throws URISyntaxException if the Location URI syntax is incorrect. */ - @PatchMapping(value = "/root-services/{id}", consumes = "application/merge-patch+json") + @PatchMapping(value = "/root-services/{id}", consumes = "application/json") public ResponseEntity<RootServiceDTO> partialUpdateRootService( @PathVariable(value = "id", required = false) final Long id, @NotNull @RequestBody RootServiceDTO rootServiceDTO @@ -262,8 +269,26 @@ public class RootServiceResource { @GetMapping("/root-services/catalogue") public ResponseEntity<List<RootServiceCatalogueDTO>> getAllRootServicesCatalogue(RootServiceCriteria criteria) { log.debug("REST request to get RootServices by criteria: {}", criteria); - List<RootServiceCatalogueDTO> list = rootServiceQueryService.findByCatalogueCriteria(criteria); + final List<DefinitionDTO> definitions = definitionQueryService.findByCriteria(null); + final List<RootServiceCatalogueDTO> services = rootServiceQueryService.findByCatalogueCriteria(criteria); + if (!CollectionUtil.isNullOrEmpty(services) && !CollectionUtil.isNullOrEmpty(definitions)) { + // Replace the "code"::Definition in ServiceAttributeValue using "value"::Definition + for (RootServiceCatalogueDTO service : services) { + final Set<ServiceAttributeValueCatalogueDTO> attributeValues = service.getServiceAttributeValues(); + if (!CollectionUtil.isNullOrEmpty(attributeValues)) { + for (ServiceAttributeValueCatalogueDTO value : attributeValues) { + for (DefinitionDTO definition : definitions) { + if (value.getServiceAttributeValue().equals(definition.getCode())) { + value.setServiceAttributeValue(definition.getValue()); + break; + } + } + } + } + } + } + //HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(ServletUriComponentsBuilder.fromCurrentRequest(), page); - return ResponseEntity.ok().body(list); + return ResponseEntity.ok().body(services); } } diff --git a/git/iec-backend/src/main/java/com/piacere/iec/backend/web/rest/ServiceClassResource.java b/git/iec-backend/src/main/java/com/piacere/iec/backend/web/rest/ServiceClassResource.java index 16cf07d..bf40ba2 100644 --- a/git/iec-backend/src/main/java/com/piacere/iec/backend/web/rest/ServiceClassResource.java +++ b/git/iec-backend/src/main/java/com/piacere/iec/backend/web/rest/ServiceClassResource.java @@ -16,7 +16,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; -import com.piacere.iec.backend.repository.ServiceClassRepository; import com.piacere.iec.backend.service.ServiceClassQueryService; import com.piacere.iec.backend.service.ServiceClassService; import com.piacere.iec.backend.service.criteria.ServiceClassCriteria; @@ -34,118 +33,21 @@ public class ServiceClassResource { private final Logger log = LoggerFactory.getLogger(ServiceClassResource.class); - private static final String ENTITY_NAME = "serviceClass"; - @Value("${jhipster.clientApp.name}") private String applicationName; private final ServiceClassService serviceClassService; - private final ServiceClassRepository serviceClassRepository; - private final ServiceClassQueryService serviceClassQueryService; public ServiceClassResource( ServiceClassService serviceClassService, - ServiceClassRepository serviceClassRepository, ServiceClassQueryService serviceClassQueryService ) { this.serviceClassService = serviceClassService; - this.serviceClassRepository = serviceClassRepository; this.serviceClassQueryService = serviceClassQueryService; } -// /** -// * {@code POST /service-classes} : Create a new serviceClass. -// * -// * @param serviceClassDTO the serviceClassDTO to create. -// * @return the {@link ResponseEntity} with status {@code 201 (Created)} and with body the new serviceClassDTO, or with status {@code 400 (Bad Request)} if the serviceClass has already an ID. -// * @throws URISyntaxException if the Location URI syntax is incorrect. -// */ -// @PostMapping("/service-classes") -// public ResponseEntity<ServiceClassDTO> createServiceClass(@Valid @RequestBody ServiceClassDTO serviceClassDTO) -// throws URISyntaxException { -// log.debug("REST request to save ServiceClass : {}", serviceClassDTO); -// if (serviceClassDTO.getId() != null) { -// throw new BadRequestAlertException("A new serviceClass cannot already have an ID", ENTITY_NAME, "idexists"); -// } -// ServiceClassDTO result = serviceClassService.save(serviceClassDTO); -// return ResponseEntity -// .created(new URI("/api/service-classes/" + result.getId())) -// .headers(HeaderUtil.createEntityCreationAlert(applicationName, false, ENTITY_NAME, result.getId().toString())) -// .body(result); -// } - -// /** -// * {@code PUT /service-classes/:id} : Updates an existing serviceClass. -// * -// * @param id the id of the serviceClassDTO to save. -// * @param serviceClassDTO the serviceClassDTO to update. -// * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the updated serviceClassDTO, -// * or with status {@code 400 (Bad Request)} if the serviceClassDTO is not valid, -// * or with status {@code 500 (Internal Server Error)} if the serviceClassDTO couldn't be updated. -// * @throws URISyntaxException if the Location URI syntax is incorrect. -// */ -// @PutMapping("/service-classes/{id}") -// public ResponseEntity<ServiceClassDTO> updateServiceClass( -// @PathVariable(value = "id", required = false) final Long id, -// @Valid @RequestBody ServiceClassDTO serviceClassDTO -// ) throws URISyntaxException { -// log.debug("REST request to update ServiceClass : {}, {}", id, serviceClassDTO); -// if (serviceClassDTO.getId() == null) { -// throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull"); -// } -// if (!Objects.equals(id, serviceClassDTO.getId())) { -// throw new BadRequestAlertException("Invalid ID", ENTITY_NAME, "idinvalid"); -// } -// -// if (!serviceClassRepository.existsById(id)) { -// throw new BadRequestAlertException("Entity not found", ENTITY_NAME, "idnotfound"); -// } -// -// ServiceClassDTO result = serviceClassService.save(serviceClassDTO); -// return ResponseEntity -// .ok() -// .headers(HeaderUtil.createEntityUpdateAlert(applicationName, false, ENTITY_NAME, serviceClassDTO.getId().toString())) -// .body(result); -// } - -// /** -// * {@code PATCH /service-classes/:id} : Partial updates given fields of an existing serviceClass, field will ignore if it is null -// * -// * @param id the id of the serviceClassDTO to save. -// * @param serviceClassDTO the serviceClassDTO to update. -// * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the updated serviceClassDTO, -// * or with status {@code 400 (Bad Request)} if the serviceClassDTO is not valid, -// * or with status {@code 404 (Not Found)} if the serviceClassDTO is not found, -// * or with status {@code 500 (Internal Server Error)} if the serviceClassDTO couldn't be updated. -// * @throws URISyntaxException if the Location URI syntax is incorrect. -// */ -// @PatchMapping(value = "/service-classes/{id}", consumes = "application/merge-patch+json") -// public ResponseEntity<ServiceClassDTO> partialUpdateServiceClass( -// @PathVariable(value = "id", required = false) final Long id, -// @NotNull @RequestBody ServiceClassDTO serviceClassDTO -// ) throws URISyntaxException { -// log.debug("REST request to partial update ServiceClass partially : {}, {}", id, serviceClassDTO); -// if (serviceClassDTO.getId() == null) { -// throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull"); -// } -// if (!Objects.equals(id, serviceClassDTO.getId())) { -// throw new BadRequestAlertException("Invalid ID", ENTITY_NAME, "idinvalid"); -// } -// -// if (!serviceClassRepository.existsById(id)) { -// throw new BadRequestAlertException("Entity not found", ENTITY_NAME, "idnotfound"); -// } -// -// Optional<ServiceClassDTO> result = serviceClassService.partialUpdate(serviceClassDTO); -// -// return ResponseUtil.wrapOrNotFound( -// result, -// HeaderUtil.createEntityUpdateAlert(applicationName, false, ENTITY_NAME, serviceClassDTO.getId().toString()) -// ); -// } - /** * {@code GET /service-classes} : get all the serviceClasses. * @@ -185,20 +87,4 @@ public class ServiceClassResource { Optional<ServiceClassDTO> serviceClassDTO = serviceClassService.findOne(id); return ResponseUtil.wrapOrNotFound(serviceClassDTO); } - -// /** -// * {@code DELETE /service-classes/:id} : delete the "id" serviceClass. -// * -// * @param id the id of the serviceClassDTO to delete. -// * @return the {@link ResponseEntity} with status {@code 204 (NO_CONTENT)}. -// */ -// @DeleteMapping("/service-classes/{id}") -// public ResponseEntity<Void> deleteServiceClass(@PathVariable Long id) { -// log.debug("REST request to delete ServiceClass : {}", id); -// serviceClassService.delete(id); -// return ResponseEntity -// .noContent() -// .headers(HeaderUtil.createEntityDeletionAlert(applicationName, false, ENTITY_NAME, id.toString())) -// .build(); -// } } diff --git a/git/iec-backend/src/main/resources/config/application.yml b/git/iec-backend/src/main/resources/config/application.yml index 1ba9561..5a90af2 100644 --- a/git/iec-backend/src/main/resources/config/application.yml +++ b/git/iec-backend/src/main/resources/config/application.yml @@ -206,7 +206,7 @@ jhipster: mail: from: iecBackend@localhost api-docs: - default-include-pattern: ${server.servlet.context-path:}(/api/root-services/catalogue|/api/instances/toredown/.*|/api/instances/saveInfo|/api/instance-incidences/saveInfo) + default-include-pattern: ${server.servlet.context-path:}(/api/root-services/catalogue|/api/instances/.*)|(/api/existing-resources|/api/existing-resources/.*)|(/api/service-classes|/api/service-classes/.*)|(/api/images|/api/images/.*) management-include-pattern: ${server.servlet.context-path:}/management/.* title: Infrastructural Elements Catalogue API description: Infrastructural Elements Catalogue API documentation diff --git a/git/iec-backend/src/main/resources/config/liquibase/changelog/20230215090119_added_entity_ExistingResource.xml b/git/iec-backend/src/main/resources/config/liquibase/changelog/20230215090119_added_entity_ExistingResource.xml new file mode 100644 index 0000000..f91fa84 --- /dev/null +++ b/git/iec-backend/src/main/resources/config/liquibase/changelog/20230215090119_added_entity_ExistingResource.xml @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="utf-8"?> +<databaseChangeLog + xmlns="http://www.liquibase.org/xml/ns/dbchangelog" + xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd + http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd"> + + <!-- + Added the entity ExistingResource. + --> + <changeSet id="20230215090119-1" author="jhipster"> + <createTable tableName="existing_resource"> + <column name="id" type="bigint" autoIncrement="true"> + <constraints primaryKey="true" nullable="false"/> + </column> + <column name="data_name" type="varchar(70)"> + <constraints nullable="false" /> + </column> + <column name="data_type" type="varchar(70)"> + <constraints nullable="false" /> + </column> + <column name="name" type="varchar(70)"> + <constraints nullable="false" /> + </column> + <column name="datacenter_id" type="varchar(70)"> + <constraints nullable="false" /> + </column> + <column name="user" type="varchar(70)"> + <constraints nullable="false" /> + </column> + <column name="provider" type="varchar(70)"> + <constraints nullable="false" /> + </column> + <column name="created_date" type="${datetimeType}"> + <constraints nullable="false" /> + </column> + <column name="last_modified_date" type="${datetimeType}"> + <constraints nullable="true" /> + </column> + <column name="deleted_date" type="${datetimeType}"> + <constraints nullable="true" /> + </column> + <!-- jhipster-needle-liquibase-add-column - JHipster will add columns here --> + </createTable> + <dropDefaultValue tableName="existing_resource" columnName="created_date" columnDataType="${datetimeType}"/> + <dropDefaultValue tableName="existing_resource" columnName="last_modified_date" columnDataType="${datetimeType}"/> + <dropDefaultValue tableName="existing_resource" columnName="deleted_date" columnDataType="${datetimeType}"/> + </changeSet> + + <!-- jhipster-needle-liquibase-add-changeset - JHipster will add changesets here --> + + <!-- + Load sample data generated with Faker.js + - This data can be easily edited using a CSV editor (or even MS Excel) and + is located in the 'src/main/resources/config/liquibase/fake-data' directory + - By default this data is applied when running with the JHipster 'dev' profile. + This can be customized by adding or removing 'faker' in the 'spring.liquibase.contexts' + Spring Boot configuration key. + --> + <!-- <changeSet id="20210706090119-1-data" author="jhipster" context="faker"> + <loadData + file="config/liquibase/fake-data/root_service.csv" + separator=";" + tableName="root_service"> + <column name="id" type="numeric"/> + <column name="service_name" type="string"/> + <column name="first_contract" type="blob"/> + <column name="first_contract_content_type" type="string"/> + <column name="second_contract" type="blob"/> + <column name="second_contract_content_type" type="string"/> + <column name="third_contract" type="blob"/> + <column name="third_contract_content_type" type="string"/> + <column name="created_date" type="${datetimeType}"/> + <column name="last_modified_date" type="${datetimeType}"/> + <column name="deleted_date" type="${datetimeType}"/> + + </loadData> + </changeSet> --> +</databaseChangeLog> diff --git a/git/iec-backend/src/main/resources/config/liquibase/changelog/20230403121800_added_entity_Image.xml b/git/iec-backend/src/main/resources/config/liquibase/changelog/20230403121800_added_entity_Image.xml new file mode 100644 index 0000000..352e503 --- /dev/null +++ b/git/iec-backend/src/main/resources/config/liquibase/changelog/20230403121800_added_entity_Image.xml @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="utf-8"?> +<databaseChangeLog + xmlns="http://www.liquibase.org/xml/ns/dbchangelog" + xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd + http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd"> + + <!-- + Added the entity Image. + --> + <changeSet id="20230403121800-1" author="jhipster"> + <createTable tableName="image"> + <column name="id" type="bigint" autoIncrement="true"> + <constraints primaryKey="true" nullable="false"/> + </column> + <column name="image_type" type="varchar(10)"> + <constraints nullable="false" /> + </column> + <column name="image_name" type="varchar(100)"> + <constraints nullable="true" /> + </column> + <column name="imageUrl" type="varchar(255)"> + <constraints nullable="true" /> + </column> + <column name="image_description" type="text"> + <constraints nullable="true" /> + </column> + <column name="image_provider" type="varchar(70)"> + <constraints nullable="false" /> + </column> + <column name="created_date" type="${datetimeType}"> + <constraints nullable="false" /> + </column> + <column name="last_modified_date" type="${datetimeType}"> + <constraints nullable="true" /> + </column> + <column name="deleted_date" type="${datetimeType}"> + <constraints nullable="true" /> + </column> + <!-- jhipster-needle-liquibase-add-column - JHipster will add columns here --> + </createTable> + <dropDefaultValue tableName="image" columnName="created_date" columnDataType="${datetimeType}"/> + <dropDefaultValue tableName="image" columnName="last_modified_date" columnDataType="${datetimeType}"/> + <dropDefaultValue tableName="image" columnName="deleted_date" columnDataType="${datetimeType}"/> + </changeSet> + + <!-- jhipster-needle-liquibase-add-changeset - JHipster will add changesets here --> + + <!-- + Load sample data generated with Faker.js + - This data can be easily edited using a CSV editor (or even MS Excel) and + is located in the 'src/main/resources/config/liquibase/fake-data' directory + - By default this data is applied when running with the JHipster 'dev' profile. + This can be customized by adding or removing 'faker' in the 'spring.liquibase.contexts' + Spring Boot configuration key. + --> + <!-- <changeSet id="20210706090119-1-data" author="jhipster" context="faker"> + <loadData + file="config/liquibase/fake-data/root_service.csv" + separator=";" + tableName="root_service"> + <column name="id" type="numeric"/> + <column name="service_name" type="string"/> + <column name="first_contract" type="blob"/> + <column name="first_contract_content_type" type="string"/> + <column name="second_contract" type="blob"/> + <column name="second_contract_content_type" type="string"/> + <column name="third_contract" type="blob"/> + <column name="third_contract_content_type" type="string"/> + <column name="created_date" type="${datetimeType}"/> + <column name="last_modified_date" type="${datetimeType}"/> + <column name="deleted_date" type="${datetimeType}"/> + + </loadData> + </changeSet> --> +</databaseChangeLog> diff --git a/git/iec-backend/src/main/resources/config/liquibase/master.xml b/git/iec-backend/src/main/resources/config/liquibase/master.xml index 35b42cf..c6bf7aa 100644 --- a/git/iec-backend/src/main/resources/config/liquibase/master.xml +++ b/git/iec-backend/src/main/resources/config/liquibase/master.xml @@ -31,6 +31,9 @@ <include file="config/liquibase/changelog/20210706090130_added_entity_constraints_Instance.xml" relativeToChangelogFile="false"/> <include file="config/liquibase/changelog/20210706090131_added_entity_constraints_InstanceIncidence.xml" relativeToChangelogFile="false"/> <include file="config/liquibase/changelog/20210706090132_added_entity_constraints_ServiceAttributeType.xml" relativeToChangelogFile="false"/> + + <include file="config/liquibase/changelog/20230215090119_added_entity_ExistingResource.xml" relativeToChangelogFile="false"/> + <include file="config/liquibase/changelog/20230403121800_added_entity_Image.xml" relativeToChangelogFile="false"/> <!-- 20210706090119_added_entity_constraints_RootService.xml 20210706090120_added_entity_constraints_ServiceClassAttribute.xml diff --git a/git/iec-frontend/iec-frontend.png b/git/iec-frontend/iec-frontend.png index 2136351438c6fbd2f3dbd72654848fe80295720a..9ed7e777e9d94ddc08bb83415825ab36747806e9 100644 GIT binary patch literal 65147 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�nl@a=`5Md70ZzrXYM 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 b5ES@PuY2tB(oeZ<(jXn4u6{1-oD!M<%cDtn literal 65205 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 W<MiIJ|MAkyAik%opUXO@geCya`sA<x diff --git a/git/iec-frontend/src/main/webapp/app/app.constants.ts b/git/iec-frontend/src/main/webapp/app/app.constants.ts index 88dae20..3a02474 100644 --- a/git/iec-frontend/src/main/webapp/app/app.constants.ts +++ b/git/iec-frontend/src/main/webapp/app/app.constants.ts @@ -6,3 +6,6 @@ export const VERSION = process.env.VERSION; export const DEBUG_INFO_ENABLED = Boolean(process.env.DEBUG_INFO_ENABLED); export const SERVER_API_URL = process.env.SERVER_API_URL ?? ''; export const BUILD_TIMESTAMP = process.env.BUILD_TIMESTAMP; + +export const IMAGE_DOCKER = 'Docker'; +export const IMAGE_VM = 'VM'; diff --git a/git/iec-frontend/src/main/webapp/app/entities/entity-routing.module.ts b/git/iec-frontend/src/main/webapp/app/entities/entity-routing.module.ts index 21637ba..7a7bae5 100644 --- a/git/iec-frontend/src/main/webapp/app/entities/entity-routing.module.ts +++ b/git/iec-frontend/src/main/webapp/app/entities/entity-routing.module.ts @@ -18,6 +18,16 @@ import { RouterModule } from '@angular/router'; path: 'instance', data: { pageTitle: 'iecFrontendApp.iecBackendInstance.home.title' }, loadChildren: () => import('./iecBackend/instance/instance.module').then(m => m.IecBackendInstanceModule), + }, + { + path: 'image', + data: { pageTitle: 'iecFrontendApp.iecBackendImage.home.title' }, + loadChildren: () => import('./iecBackend/image/image.module').then(m => m.IecBackendImageModule), + }, + { + path: 'existing-resource', + data: { pageTitle: 'iecFrontendApp.iecBackendExistingResource.home.title' }, + loadChildren: () => import('./iecBackend/existing-resource/existing-resource.module').then(m => m.IecBackendExistingResourceModule), } /* jhipster-needle-add-entity-route - JHipster will add entity modules routes here */ ]), diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/delete/existing-resource-delete-dialog.component.html b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/delete/existing-resource-delete-dialog.component.html new file mode 100644 index 0000000..34b108e --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/delete/existing-resource-delete-dialog.component.html @@ -0,0 +1,29 @@ +<form *ngIf="existingResource" name="deleteForm" (ngSubmit)="confirmDelete(existingResource.id!)"> + <div class="modal-header"> + <h4 class="modal-title" data-cy="existingResourceDeleteDialogHeading" jhiTranslate="entity.delete.title">Confirm delete operation</h4> + + <button type="button" class="close" data-dismiss="modal" aria-hidden="true" (click)="cancel()">×</button> + </div> + + <div class="modal-body"> + <jhi-alert-error></jhi-alert-error> + + <p + id="jhi-delete-existingResource-heading" + jhiTranslate="iecFrontendApp.iecBackendExistingResource.delete.question" + [translateValues]="{ id: existingResource.id }" + > + Are you sure you want to delete this Existing Resource? + </p> + </div> + + <div class="modal-footer"> + <button type="button" class="btn btn-secondary" data-dismiss="modal" (click)="cancel()"> + <fa-icon icon="ban"></fa-icon> <span jhiTranslate="entity.action.cancel">Cancel</span> + </button> + + <button id="jhi-confirm-delete-existingResource" data-cy="entityConfirmDeleteButton" type="submit" class="btn btn-danger"> + <fa-icon icon="times"></fa-icon> <span jhiTranslate="entity.action.delete">Delete</span> + </button> + </div> +</form> diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/delete/existing-resource-delete-dialog.component.spec.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/delete/existing-resource-delete-dialog.component.spec.ts new file mode 100644 index 0000000..4a2b1bd --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/delete/existing-resource-delete-dialog.component.spec.ts @@ -0,0 +1,64 @@ +jest.mock('@ng-bootstrap/ng-bootstrap'); + +import { ComponentFixture, TestBed, inject, fakeAsync, tick } from '@angular/core/testing'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { of } from 'rxjs'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; + +import { ExistingResourceService } from '../service/existing-resource.service'; + +import { ExistingResourceDeleteDialogComponent } from './existing-resource-delete-dialog.component'; + +describe('Component Tests', () => { + describe('ExistingResource Management Delete Component', () => { + let comp: ExistingResourceDeleteDialogComponent; + let fixture: ComponentFixture<ExistingResourceDeleteDialogComponent>; + let service: ExistingResourceService; + let mockActiveModal: NgbActiveModal; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + declarations: [ExistingResourceDeleteDialogComponent], + providers: [NgbActiveModal], + }) + .overrideTemplate(ExistingResourceDeleteDialogComponent, '') + .compileComponents(); + fixture = TestBed.createComponent(ExistingResourceDeleteDialogComponent); + comp = fixture.componentInstance; + service = TestBed.inject(ExistingResourceService); + mockActiveModal = TestBed.inject(NgbActiveModal); + }); + + describe('confirmDelete', () => { + it('Should call delete service on confirmDelete', inject( + [], + fakeAsync(() => { + // GIVEN + spyOn(service, 'delete').and.returnValue(of({})); + + // WHEN + comp.confirmDelete(123); + tick(); + + // THEN + expect(service.delete).toHaveBeenCalledWith(123); + expect(mockActiveModal.close).toHaveBeenCalledWith('deleted'); + }) + )); + + it('Should not call delete service on clear', () => { + // GIVEN + spyOn(service, 'delete'); + + // WHEN + comp.cancel(); + + // THEN + expect(service.delete).not.toHaveBeenCalled(); + expect(mockActiveModal.close).not.toHaveBeenCalled(); + expect(mockActiveModal.dismiss).toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/delete/existing-resource-delete-dialog.component.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/delete/existing-resource-delete-dialog.component.ts new file mode 100644 index 0000000..1f61199 --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/delete/existing-resource-delete-dialog.component.ts @@ -0,0 +1,24 @@ +import { Component } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; + +import { IExistingResource } from '../existing-resource.model'; +import { ExistingResourceService } from '../service/existing-resource.service'; + +@Component({ + templateUrl: './existing-resource-delete-dialog.component.html', +}) +export class ExistingResourceDeleteDialogComponent { + existingResource?: IExistingResource; + + constructor(protected existingResourceService: ExistingResourceService, public activeModal: NgbActiveModal) {} + + cancel(): void { + this.activeModal.dismiss(); + } + + confirmDelete(id: number): void { + this.existingResourceService.delete(id).subscribe(() => { + this.activeModal.close('deleted'); + }); + } +} diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/detail/existing-resource-detail.component.html b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/detail/existing-resource-detail.component.html new file mode 100644 index 0000000..0b69a3f --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/detail/existing-resource-detail.component.html @@ -0,0 +1,29 @@ +<div class="row justify-content-center"> + <div class="col-6"> + <div class="card"> + <h5 class="card-header text-white bg-primary p-4 font-weight-bold">{{existingResource?.dataName}}</h5> + <div class="card-body"> + <span class="text-primary font-weight-bold" jhiTranslate="iecFrontendApp.iecBackendExistingResource.dataType">Data type</span> + <span> </span> + <span>{{ existingResource?.dataType }}</span><br> + <span class="text-primary font-weight-bold" jhiTranslate="iecFrontendApp.iecBackendExistingResource.name">Name</span> + <span> </span> + <span>{{ existingResource?.name }}</span><br> + <span class="text-primary font-weight-bold" jhiTranslate="iecFrontendApp.iecBackendExistingResource.datacenterId">Datacenter Id</span> + <span> </span> + <span>{{ existingResource?.datacenterId }}</span><br> + <span class="text-primary font-weight-bold" jhiTranslate="iecFrontendApp.iecBackendExistingResource.user">User</span> + <span> </span> + <span>{{ existingResource?.user }}</span><br> + <span class="text-primary font-weight-bold" jhiTranslate="iecFrontendApp.iecBackendExistingResource.provider">Provider</span> + <span> </span> + <span>{{ existingResource?.provider }}</span> + </div> + <div class="card-footer"> + <button type="submit" (click)="previousState()" class="btn btn-info float-right" data-cy="entityDetailsBackButton"> + <fa-icon icon="arrow-left"></fa-icon> <span jhiTranslate="entity.action.back">Back</span> + </button> + </div> + </div> + </div> +</div> \ No newline at end of file diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/detail/existing-resource-detail.component.spec.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/detail/existing-resource-detail.component.spec.ts new file mode 100644 index 0000000..fd4b917 --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/detail/existing-resource-detail.component.spec.ts @@ -0,0 +1,38 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ActivatedRoute } from '@angular/router'; +import { of } from 'rxjs'; + +import { ExistingResourceDetailComponent } from './existing-resource-detail.component'; + +describe('Component Tests', () => { + describe('Existing Resource Management Detail Component', () => { + let comp: ExistingResourceDetailComponent; + let fixture: ComponentFixture<ExistingResourceDetailComponent>; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ExistingResourceDetailComponent], + providers: [ + { + provide: ActivatedRoute, + useValue: { data: of({ image: { id: 123 } }) }, + }, + ], + }) + .overrideTemplate(ExistingResourceDetailComponent, '') + .compileComponents(); + fixture = TestBed.createComponent(ExistingResourceDetailComponent); + comp = fixture.componentInstance; + }); + + describe('OnInit', () => { + it('Should load existing resource on init', () => { + // WHEN + comp.ngOnInit(); + + // THEN + expect(comp.existingResource).toEqual(jasmine.objectContaining({ id: 123 })); + }); + }); + }); +}); diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/detail/existing-resource-detail.component.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/detail/existing-resource-detail.component.ts new file mode 100644 index 0000000..c26fb68 --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/detail/existing-resource-detail.component.ts @@ -0,0 +1,24 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +import { IExistingResource } from '../existing-resource.model'; + +@Component({ + selector: 'jhi-existing-resource-detail', + templateUrl: './existing-resource-detail.component.html', +}) +export class ExistingResourceDetailComponent implements OnInit { + existingResource: IExistingResource | null = null; + + constructor(protected activatedRoute: ActivatedRoute) {} + + ngOnInit(): void { + this.activatedRoute.data.subscribe(({ existingResource }) => { + this.existingResource = existingResource; + }); + } + + previousState(): void { + window.history.back(); + } +} diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/existing-resource.model.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/existing-resource.model.ts new file mode 100644 index 0000000..496cb0e --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/existing-resource.model.ts @@ -0,0 +1,33 @@ +import * as dayjs from 'dayjs'; + +export interface IExistingResource { + id?: number; + dataName?: string; + dataType?: string; + name?: string; + datacenterId?: string; + user?: string; + provider?: string; + createdDate?: dayjs.Dayjs; + lastModifiedDate?: dayjs.Dayjs | null; + deletedDate?: dayjs.Dayjs | null; +} + +export class ExistingResource implements IExistingResource { + constructor( + public id?: number, + public dataName?: string, + public dataType?: string, + public name?: string, + public datacenterId?: string, + public user?: string, + public provider?: string, + public createdDate?: dayjs.Dayjs, + public lastModifiedDate?: dayjs.Dayjs | null, + public deletedDate?: dayjs.Dayjs | null, + ) {} +} + +export function getExistingResourceIdentifier(existingResource: IExistingResource): number | undefined { + return existingResource.id; +} diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/existing-resource.module.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/existing-resource.module.ts new file mode 100644 index 0000000..89fc61c --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/existing-resource.module.ts @@ -0,0 +1,15 @@ +import { NgModule } from '@angular/core'; + +import { SharedModule } from 'app/shared/shared.module'; +import { ExistingResourceComponent } from './list/existing-resource.component'; +import { ExistingResourceDetailComponent } from './detail/existing-resource-detail.component'; +import { ExistingResourceUpdateComponent } from './update/existing-resource-update.component'; +import { ExistingResourceDeleteDialogComponent } from './delete/existing-resource-delete-dialog.component'; +import { ExistingResourceRoutingModule } from './route/existing-resource-routing.module'; + +@NgModule({ + imports: [SharedModule, ExistingResourceRoutingModule], + declarations: [ExistingResourceComponent, ExistingResourceDetailComponent, ExistingResourceUpdateComponent, ExistingResourceDeleteDialogComponent], + entryComponents: [ExistingResourceDeleteDialogComponent] +}) +export class IecBackendExistingResourceModule {} diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/list/existing-resource.component.html b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/list/existing-resource.component.html new file mode 100644 index 0000000..5252493 --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/list/existing-resource.component.html @@ -0,0 +1,119 @@ +<div> + <nav class="navbar navbar-dark bg-primary"> + <span class="navbar-brand mb-0 h1" jhiTranslate="iecFrontendApp.iecBackendExistingResource.home.title">Existing Resources</span> + </nav> + + <h2 id="page-heading" data-cy="ExistingResourceHeading"> + <div class="d-flex justify-content-end mt-2"> + <button class="btn btn-info mr-2" (click)="loadPage()" [disabled]="isLoading"> + <fa-icon icon="sync" [spin]="isLoading"></fa-icon> + <span jhiTranslate="iecFrontendApp.iecBackendExistingResource.home.refreshListLabel">Refresh List</span> + </button> + + <button + id="jh-create-entity" + data-cy="entityCreateButton" + class="btn btn-primary jh-create-entity create-root-service" + [routerLink]="['/existing-resource/new']" + > + <fa-icon icon="plus"></fa-icon> + <span jhiTranslate="iecFrontendApp.iecBackendExistingResource.home.createLabel"> Create a new Existing Resource</span> + </button> + </div> + </h2> + + <jhi-alert-error></jhi-alert-error> + + <jhi-alert></jhi-alert> + + <div class="alert alert-warning" id="no-result" *ngIf="existingResources?.length === 0"> + <span jhiTranslate="iecFrontendApp.iecBackendExistingResource.home.notFound">No Existing Resources found</span> + </div> + + <div class="table-responsive" id="entities" *ngIf="existingResources && existingResources.length > 0"> + <table class="table table-striped" aria-describedby="page-heading"> + <thead> + <tr jhiSort [(predicate)]="predicate" [(ascending)]="ascending" [callback]="loadPage.bind(this)"> + <th scope="col" jhiSortBy="dataName"> + <span jhiTranslate="iecFrontendApp.iecBackendExistingResource.dataName">Data name</span> + <fa-icon icon="sort"></fa-icon> + </th> + <th scope="col" jhiSortBy="dataType"> + <span jhiTranslate="iecFrontendApp.iecBackendExistingResource.dataType">Data type</span> + <fa-icon icon="sort"></fa-icon> + </th> + <th scope="col" jhiSortBy="name"> + <span jhiTranslate="iecFrontendApp.iecBackendExistingResource.name">Name</span> + <fa-icon icon="sort"></fa-icon> + </th> + <th scope="col" jhiSortBy="datacenterId"> + <span jhiTranslate="iecFrontendApp.iecBackendExistingResource.datacenterId">Datacenter Id</span> + <fa-icon icon="sort"></fa-icon> + </th> + <th scope="col" jhiSortBy="user"> + <span jhiTranslate="iecFrontendApp.iecBackendExistingResource.user">User</span> + <fa-icon icon="sort"></fa-icon> + </th> + <th scope="col" jhiSortBy="provider"> + <span jhiTranslate="iecFrontendApp.iecBackendExistingResource.provider">Provider</span> + <fa-icon icon="sort"></fa-icon> + </th> + <th scope="col"> + <span jhiTranslate="iecFrontendApp.iecBackendExistingResource.status">Status</span> + </th> + <th scope="col"></th> + </tr> + </thead> + <tbody> + <tr *ngFor="let existingResource of existingResources; trackBy: trackId" data-cy="entityTable"> + <td>{{ existingResource.dataName }}</td> + <td>{{ existingResource.dataType }}</td> + <td>{{ existingResource.name }}</td> + <td>{{ existingResource.datacenterId }}</td> + <td>{{ existingResource.user }}</td> + <td>{{ existingResource.provider }}</td> + <td> + <span class="badge badge-success" jhiTranslate="iecFrontendApp.iecBackendExistingResource.active" *ngIf="existingResource.deletedDate == null">Active</span> + <span class="badge badge-danger" jhiTranslate="iecFrontendApp.iecBackendExistingResource.inactive" *ngIf="existingResource.deletedDate != null">Inactive</span> + </td> + <td class="text-right"> + <div class="btn-group"> + <button + type="submit" + [routerLink]="['/existing-resource', existingResource.id, 'view']" + class="btn btn-info btn-sm" + data-cy="entityDetailsButton" + > + <fa-icon icon="eye"></fa-icon> + <span class="d-none d-md-inline" jhiTranslate="entity.action.view">View</span> + </button> + + <button type="submit" (click)="delete(existingResource)" class="btn btn-danger btn-sm" data-cy="entityDeleteButton"> + <fa-icon icon="times"></fa-icon> + <span class="d-none d-md-inline" jhiTranslate="entity.action.delete">Delete</span> + </button> + </div> + </td> + </tr> + </tbody> + </table> + </div> + + <div *ngIf="existingResources && existingResources.length > 0"> + <div class="row justify-content-center"> + <jhi-item-count [params]="{ page: page, totalItems: totalItems, itemsPerPage: itemsPerPage }"></jhi-item-count> + </div> + + <div class="row justify-content-center"> + <ngb-pagination + [collectionSize]="totalItems" + [(page)]="ngbPaginationPage" + [pageSize]="itemsPerPage" + [maxSize]="5" + [rotate]="true" + [boundaryLinks]="true" + (pageChange)="loadPage($event)" + ></ngb-pagination> + </div> + </div> +</div> diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/list/existing-resource.component.spec.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/list/existing-resource.component.spec.ts new file mode 100644 index 0000000..19921ad --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/list/existing-resource.component.spec.ts @@ -0,0 +1,100 @@ +jest.mock('@angular/router'); + +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { HttpHeaders, HttpResponse } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { ActivatedRoute, Router } from '@angular/router'; +import { of } from 'rxjs'; + +import { ExistingResourceService } from '../service/existing-resource.service'; + +import { ExistingResourceComponent } from './existing-resource.component'; + +describe('Component Tests', () => { + describe('ExistingResource Management Component', () => { + let comp: ExistingResourceComponent; + let fixture: ComponentFixture<ExistingResourceComponent>; + let service: ExistingResourceService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + declarations: [ExistingResourceComponent], + providers: [ + Router, + { + provide: ActivatedRoute, + useValue: { + data: of({ + defaultSort: 'id,asc', + }), + queryParamMap: of( + jest.requireActual('@angular/router').convertToParamMap({ + page: '1', + size: '1', + sort: 'id,desc', + }) + ), + }, + }, + ], + }) + .overrideTemplate(ExistingResourceComponent, '') + .compileComponents(); + + fixture = TestBed.createComponent(ExistingResourceComponent); + comp = fixture.componentInstance; + service = TestBed.inject(ExistingResourceService); + + const headers = new HttpHeaders().append('link', 'link;link'); + spyOn(service, 'query').and.returnValue( + of( + new HttpResponse({ + body: [{ id: 123 }], + headers, + }) + ) + ); + }); + + it('Should call load all on init', () => { + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.query).toHaveBeenCalled(); + expect(comp.existingResources?.[0]).toEqual(jasmine.objectContaining({ id: 123 })); + }); + + it('should load a page', () => { + // WHEN + comp.loadPage(1); + + // THEN + expect(service.query).toHaveBeenCalled(); + expect(comp.existingResources?.[0]).toEqual(jasmine.objectContaining({ id: 123 })); + }); + + it('should calculate the sort attribute for an id', () => { + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.query).toHaveBeenCalledWith(expect.objectContaining({ sort: ['id,desc'] })); + }); + + it('should calculate the sort attribute for a non-id attribute', () => { + // INIT + comp.ngOnInit(); + + // GIVEN + comp.predicate = 'name'; + + // WHEN + comp.loadPage(1); + + // THEN + expect(service.query).toHaveBeenLastCalledWith(expect.objectContaining({ sort: ['name,desc', 'id'] })); + }); + }); +}); diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/list/existing-resource.component.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/list/existing-resource.component.ts new file mode 100644 index 0000000..f3a38b6 --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/list/existing-resource.component.ts @@ -0,0 +1,117 @@ +import { Component, OnInit } from '@angular/core'; +import { HttpHeaders, HttpResponse } from '@angular/common/http'; +import { ActivatedRoute, Router } from '@angular/router'; +import { combineLatest } from 'rxjs'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; + +import { IExistingResource } from '../existing-resource.model'; + +import { ITEMS_PER_PAGE } from 'app/config/pagination.constants'; +import { ExistingResourceService } from '../service/existing-resource.service'; +import { ExistingResourceDeleteDialogComponent } from '../delete/existing-resource-delete-dialog.component'; + +@Component({ + selector: 'jhi-existing-resource', + templateUrl: './existing-resource.component.html', +}) +export class ExistingResourceComponent implements OnInit { + existingResources?: IExistingResource[]; + isLoading = false; + totalItems = 0; + itemsPerPage = ITEMS_PER_PAGE; + page?: number; + predicate!: string; + ascending!: boolean; + ngbPaginationPage = 1; + + constructor( + protected existingResourceService: ExistingResourceService, + protected activatedRoute: ActivatedRoute, + protected router: Router, + protected modalService: NgbModal + ) {} + + loadPage(page?: number, dontNavigate?: boolean): void { + this.isLoading = true; + const pageToLoad: number = page ?? this.page ?? 1; + + this.existingResourceService + .query({ + page: pageToLoad - 1, + size: this.itemsPerPage, + sort: this.sort(), + }) + .subscribe( + (res: HttpResponse<IExistingResource[]>) => { + this.isLoading = false; + this.onSuccess(res.body, res.headers, pageToLoad, !dontNavigate); + }, + () => { + this.isLoading = false; + this.onError(); + } + ); + } + + ngOnInit(): void { + this.handleNavigation(); + } + + trackId(index: number, item: IExistingResource): number { + return item.id!; + } + + delete(existingResource: IExistingResource): void { + const modalRef = this.modalService.open(ExistingResourceDeleteDialogComponent, { size: 'lg', backdrop: 'static' }); + modalRef.componentInstance.existingResource = existingResource; + // unsubscribe not needed because closed completes on modal close + modalRef.closed.subscribe(reason => { + if (reason === 'deleted') { + this.loadPage(); + } + }); + } + + protected sort(): string[] { + const result = [this.predicate + ',' + (this.ascending ? 'asc' : 'desc')]; + if (this.predicate !== 'id') { + result.push('id'); + } + return result; + } + + protected handleNavigation(): void { + combineLatest([this.activatedRoute.data, this.activatedRoute.queryParamMap]).subscribe(([data, params]) => { + const page = params.get('page'); + const pageNumber = page !== null ? +page : 1; + const sort = (params.get('sort') ?? data['defaultSort']).split(','); + const predicate = sort[0]; + const ascending = sort[1] === 'asc'; + if (pageNumber !== this.page || predicate !== this.predicate || ascending !== this.ascending) { + this.predicate = predicate; + this.ascending = ascending; + this.loadPage(pageNumber, true); + } + }); + } + + protected onSuccess(data: IExistingResource[] | null, headers: HttpHeaders, page: number, navigate: boolean): void { + this.totalItems = Number(headers.get('X-Total-Count')); + this.page = page; + if (navigate) { + this.router.navigate(['/existing-resource'], { + queryParams: { + page: this.page, + size: this.itemsPerPage, + sort: this.predicate + ',' + (this.ascending ? 'asc' : 'desc'), + }, + }); + } + this.existingResources = data ?? []; + this.ngbPaginationPage = this.page; + } + + protected onError(): void { + this.ngbPaginationPage = this.page ?? 1; + } +} diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/route/existing-resource-routing-resolve.service.spec.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/route/existing-resource-routing-resolve.service.spec.ts new file mode 100644 index 0000000..24bb547 --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/route/existing-resource-routing-resolve.service.spec.ts @@ -0,0 +1,82 @@ +jest.mock('@angular/router'); + +import { TestBed } from '@angular/core/testing'; +import { HttpResponse } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { of } from 'rxjs'; + +import { IExistingResource, ExistingResource } from '../existing-resource.model'; +import { ExistingResourceService } from '../service/existing-resource.service'; + +import { ExistingResourceRoutingResolveService } from './existing-resource-routing-resolve.service'; + +describe('Service Tests', () => { + describe('Existing Resource routing resolve service', () => { + let mockRouter: Router; + let mockActivatedRouteSnapshot: ActivatedRouteSnapshot; + let routingResolveService: ExistingResourceRoutingResolveService; + let service: ExistingResourceService; + let resultExistingResource: IExistingResource | undefined; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [Router, ActivatedRouteSnapshot], + }); + mockRouter = TestBed.inject(Router); + mockActivatedRouteSnapshot = TestBed.inject(ActivatedRouteSnapshot); + routingResolveService = TestBed.inject(ExistingResourceRoutingResolveService); + service = TestBed.inject(ExistingResourceService); + resultExistingResource = undefined; + }); + + describe('resolve', () => { + it('should return IExistingResource returned by find', () => { + // GIVEN + service.find = jest.fn(id => of(new HttpResponse({ body: { id } }))); + mockActivatedRouteSnapshot.params = { id: 123 }; + + // WHEN + routingResolveService.resolve(mockActivatedRouteSnapshot).subscribe(result => { + resultExistingResource = result; + }); + + // THEN + expect(service.find).toBeCalledWith(123); + expect(resultExistingResource).toEqual({ id: 123 }); + }); + + it('should return new IExistingResource if id is not provided', () => { + // GIVEN + service.find = jest.fn(); + mockActivatedRouteSnapshot.params = {}; + + // WHEN + routingResolveService.resolve(mockActivatedRouteSnapshot).subscribe(result => { + resultExistingResource = result; + }); + + // THEN + expect(service.find).not.toBeCalled(); + expect(resultExistingResource).toEqual(new Image()); + }); + + it('should route to 404 page if data not found in server', () => { + // GIVEN + spyOn(service, 'find').and.returnValue(of(new HttpResponse({ body: null }))); + mockActivatedRouteSnapshot.params = { id: 123 }; + + // WHEN + routingResolveService.resolve(mockActivatedRouteSnapshot).subscribe(result => { + resultExistingResource = result; + }); + + // THEN + expect(service.find).toBeCalledWith(123); + expect(resultExistingResource).toEqual(undefined); + expect(mockRouter.navigate).toHaveBeenCalledWith(['404']); + }); + }); + }); +}); diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/route/existing-resource-routing-resolve.service.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/route/existing-resource-routing-resolve.service.ts new file mode 100644 index 0000000..71213cb --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/route/existing-resource-routing-resolve.service.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@angular/core'; +import { HttpResponse } from '@angular/common/http'; +import { Resolve, ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Observable, of, EMPTY } from 'rxjs'; +import { mergeMap } from 'rxjs/operators'; + +import { IExistingResource, ExistingResource } from '../existing-resource.model'; +import { ExistingResourceService } from '../service/existing-resource.service'; + +@Injectable({ providedIn: 'root' }) +export class ExistingResourceRoutingResolveService implements Resolve<IExistingResource> { + constructor(protected service: ExistingResourceService, protected router: Router) {} + + resolve(route: ActivatedRouteSnapshot): Observable<IExistingResource> | Observable<never> { + const id = route.params['id']; + if (id) { + return this.service.find(id).pipe( + mergeMap((existingResource: HttpResponse<ExistingResource>) => { + if (existingResource.body) { + return of(existingResource.body); + } else { + this.router.navigate(['404']); + return EMPTY; + } + }) + ); + } + return of(new ExistingResource()); + } +} diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/route/existing-resource-routing.module.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/route/existing-resource-routing.module.ts new file mode 100644 index 0000000..27b81ce --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/route/existing-resource-routing.module.ts @@ -0,0 +1,41 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { UserRouteAccessService } from 'app/core/auth/user-route-access.service'; +import { ExistingResourceComponent } from '../list/existing-resource.component'; +import { ExistingResourceDetailComponent } from '../detail/existing-resource-detail.component'; +import { ExistingResourceUpdateComponent } from '../update/existing-resource-update.component'; +import { ExistingResourceRoutingResolveService } from './existing-resource-routing-resolve.service'; + +const existingResourceRoute: Routes = [ + { + path: '', + component: ExistingResourceComponent, + data: { + defaultSort: 'id,asc', + }, + canActivate: [UserRouteAccessService], + }, + { + path: ':id/view', + component: ExistingResourceDetailComponent, + resolve: { + existingResource: ExistingResourceRoutingResolveService, + }, + canActivate: [UserRouteAccessService], + }, + { + path: 'new', + component: ExistingResourceUpdateComponent, + resolve: { + existingResource: ExistingResourceRoutingResolveService, + }, + canActivate: [UserRouteAccessService], + } +]; + +@NgModule({ + imports: [RouterModule.forChild(existingResourceRoute)], + exports: [RouterModule], +}) +export class ExistingResourceRoutingModule {} diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/service/existing-resource.service.spec.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/service/existing-resource.service.spec.ts new file mode 100644 index 0000000..dadbfca --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/service/existing-resource.service.spec.ts @@ -0,0 +1,203 @@ +import { TestBed } from '@angular/core/testing'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; +import * as dayjs from 'dayjs'; + +import { DATE_TIME_FORMAT } from 'app/config/input.constants'; +import { IExistingResource, ExistingResource } from '../existing-resource.model'; + +import { ExistingResourceService } from './existing-resource.service'; + +describe('Existing Resource Tests', () => { + describe('Existing Resource Service', () => { + let service: ExistingResourceService; + let httpMock: HttpTestingController; + let elemDefault: IExistingResource; + let expectedResult: IExistingResource | IExistingResource[] | boolean | null; + let currentDate: dayjs.Dayjs; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + }); + expectedResult = null; + service = TestBed.inject(ExistingResourceService); + httpMock = TestBed.inject(HttpTestingController); + currentDate = dayjs(); + + elemDefault = { + id: 0, + dataName: 'AAAAAAA', + createdDate: currentDate, + lastModifiedDate: currentDate, + deletedDate: currentDate, + }; + }); + + describe('Existing Resource methods', () => { + it('should find an element', () => { + const returnedFromService = Object.assign( + { + createdDate: currentDate.format(DATE_TIME_FORMAT), + lastModifiedDate: currentDate.format(DATE_TIME_FORMAT), + deletedDate: currentDate.format(DATE_TIME_FORMAT), + }, + elemDefault + ); + + service.find(123).subscribe(resp => (expectedResult = resp.body)); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush(returnedFromService); + expect(expectedResult).toMatchObject(elemDefault); + }); + + it('should create an Existing Resource', () => { + const returnedFromService = Object.assign( + { + id: 0, + createdDate: currentDate.format(DATE_TIME_FORMAT), + lastModifiedDate: currentDate.format(DATE_TIME_FORMAT), + deletedDate: currentDate.format(DATE_TIME_FORMAT), + }, + elemDefault + ); + + const expected = Object.assign( + { + createdDate: currentDate, + lastModifiedDate: currentDate, + deletedDate: currentDate, + }, + returnedFromService + ); + + service.create(new ExistingResource()).subscribe(resp => (expectedResult = resp.body)); + + const req = httpMock.expectOne({ method: 'POST' }); + req.flush(returnedFromService); + expect(expectedResult).toMatchObject(expected); + }); + + it('should update an Existing Resource', () => { + const returnedFromService = Object.assign( + { + id: 1, + dataName: 'BBBBBB', + createdDate: currentDate.format(DATE_TIME_FORMAT), + lastModifiedDate: currentDate.format(DATE_TIME_FORMAT), + deletedDate: currentDate.format(DATE_TIME_FORMAT), + }, + elemDefault + ); + + const expected = Object.assign( + { + createdDate: currentDate, + lastModifiedDate: currentDate, + deletedDate: currentDate, + }, + returnedFromService + ); + + service.update(expected).subscribe(resp => (expectedResult = resp.body)); + + const req = httpMock.expectOne({ method: 'PUT' }); + req.flush(returnedFromService); + expect(expectedResult).toMatchObject(expected); + }); + + it('should return a list of Existing Resources', () => { + const returnedFromService = Object.assign( + { + id: 1, + dataName: 'BBBBBB', + createdDate: currentDate.format(DATE_TIME_FORMAT), + lastModifiedDate: currentDate.format(DATE_TIME_FORMAT), + deletedDate: currentDate.format(DATE_TIME_FORMAT), + }, + elemDefault + ); + + const expected = Object.assign( + { + createdDate: currentDate, + lastModifiedDate: currentDate, + deletedDate: currentDate, + }, + returnedFromService + ); + + service.query().subscribe(resp => (expectedResult = resp.body)); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush([returnedFromService]); + httpMock.verify(); + expect(expectedResult).toContainEqual(expected); + }); + + it('should delete an Existing Resource', () => { + service.delete(123).subscribe(resp => (expectedResult = resp.ok)); + + const req = httpMock.expectOne({ method: 'DELETE' }); + req.flush({ status: 200 }); + expect(expectedResult); + }); + + describe('addExistingResourceToCollectionIfMissing', () => { + it('should add an Existing Resource to an empty array', () => { + const image: IExistingResource = { id: 123 }; + expectedResult = service.addExistingResourceToCollectionIfMissing([], image); + expect(expectedResult).toHaveLength(1); + expect(expectedResult).toContain(image); + }); + + it('should not add an Existing Resource to an array that contains it', () => { + const existingResource: IExistingResource = { id: 123 }; + const existingResourceCollection: IExistingResource[] = [ + { + ...existingResource, + }, + { id: 456 }, + ]; + expectedResult = service.addExistingResourceToCollectionIfMissing(existingResourceCollection, existingResource); + expect(expectedResult).toHaveLength(2); + }); + + it("should add an Existing Resource to an array that doesn't contain it", () => { + const existingResource: IExistingResource = { id: 123 }; + const existingResourceCollection: IExistingResource[] = [{ id: 456 }]; + expectedResult = service.addExistingResourceToCollectionIfMissing(existingResourceCollection, existingResource); + expect(expectedResult).toHaveLength(2); + expect(expectedResult).toContain(existingResource); + }); + + it('should add only unique Existing Resource to an array', () => { + const existingResourceArray: IExistingResource[] = [{ id: 123 }, { id: 456 }, { id: 27673 }]; + const existingResourceCollection: IExistingResource[] = [{ id: 123 }]; + expectedResult = service.addExistingResourceToCollectionIfMissing(existingResourceCollection, ...existingResourceArray); + expect(expectedResult).toHaveLength(3); + }); + + it('should accept varargs', () => { + const existingResource: IExistingResource = { id: 123 }; + const existingResource2: IExistingResource = { id: 456 }; + expectedResult = service.addExistingResourceToCollectionIfMissing([], existingResource, existingResource2); + expect(expectedResult).toHaveLength(2); + expect(expectedResult).toContain(existingResource); + expect(expectedResult).toContain(existingResource2); + }); + + it('should accept null and undefined values', () => { + const existingResource: IExistingResource = { id: 123 }; + expectedResult = service.addExistingResourceToCollectionIfMissing([], null, existingResource, undefined); + expect(expectedResult).toHaveLength(1); + expect(expectedResult).toContain(existingResource); + }); + }); + }); + + afterEach(() => { + httpMock.verify(); + }); + }); +}); diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/service/existing-resource.service.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/service/existing-resource.service.ts new file mode 100644 index 0000000..cfeb9c2 --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/service/existing-resource.service.ts @@ -0,0 +1,101 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpResponse } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import * as dayjs from 'dayjs'; + +import { isPresent } from 'app/core/util/operators'; +import { ApplicationConfigService } from 'app/core/config/application-config.service'; +import { createRequestOption } from 'app/core/request/request-util'; +import { IExistingResource, getExistingResourceIdentifier } from '../existing-resource.model'; + +export type EntityResponseType = HttpResponse<IExistingResource>; +export type EntityArrayResponseType = HttpResponse<IExistingResource[]>; + +@Injectable({ providedIn: 'root' }) +export class ExistingResourceService { + public resourceUrl = this.applicationConfigService.getEndpointFor('api/existing-resources', 'iecbackend'); + + constructor(protected http: HttpClient, private applicationConfigService: ApplicationConfigService) {} + + create(existingResource: IExistingResource): Observable<EntityResponseType> { + const copy = this.convertDateFromClient(existingResource); + return this.http + .post<IExistingResource>(this.resourceUrl, copy, { observe: 'response' }) + .pipe(map((res: EntityResponseType) => this.convertDateFromServer(res))); + } + + update(existingResource: IExistingResource): Observable<EntityResponseType> { + const copy = this.convertDateFromClient(existingResource); + return this.http + .put<IExistingResource>(`${this.resourceUrl}/${getExistingResourceIdentifier(existingResource) as number}`, copy, { observe: 'response' }) + .pipe(map((res: EntityResponseType) => this.convertDateFromServer(res))); + } + + find(id: number): Observable<EntityResponseType> { + return this.http + .get<IExistingResource>(`${this.resourceUrl}/${id}`, { observe: 'response' }) + .pipe(map((res: EntityResponseType) => this.convertDateFromServer(res))); + } + + query(req?: any): Observable<EntityArrayResponseType> { + const options = createRequestOption(req); + return this.http + .get<IExistingResource[]>(this.resourceUrl, { params: options, observe: 'response' }) + .pipe(map((res: EntityArrayResponseType) => this.convertDateArrayFromServer(res))); + } + + delete(id: number): Observable<HttpResponse<{}>> { + return this.http.delete(`${this.resourceUrl}/${id}`, { observe: 'response' }); + } + + addExistingResourceToCollectionIfMissing( + existingResourceCollection: IExistingResource[], + ...existingResourcesToCheck: (IExistingResource | null | undefined)[] + ): IExistingResource[] { + const existingResources: IExistingResource[] = existingResourcesToCheck.filter(isPresent); + if (existingResources.length > 0) { + const existingResourceCollectionIdentifiers = existingResourceCollection.map( + existingResourceItem => getExistingResourceIdentifier(existingResourceItem)! + ); + const existingResourcesToAdd = existingResources.filter(existingResourceItem => { + const existingResourceIdentifier = getExistingResourceIdentifier(existingResourceItem); + if (existingResourceIdentifier == null || existingResourceCollectionIdentifiers.includes(existingResourceIdentifier)) { + return false; + } + existingResourceCollectionIdentifiers.push(existingResourceIdentifier); + return true; + }); + return [...existingResourcesToAdd, ...existingResourceCollection]; + } + return existingResourceCollection; + } + + protected convertDateFromClient(existingResource: IExistingResource): IExistingResource { + return Object.assign({}, existingResource, { + createdDate: existingResource.createdDate?.isValid() ? existingResource.createdDate.toJSON() : undefined, + lastModifiedDate: existingResource.lastModifiedDate?.isValid() ? existingResource.lastModifiedDate.toJSON() : undefined, + deletedDate: existingResource.deletedDate?.isValid() ? existingResource.deletedDate.toJSON() : undefined, + }); + } + + protected convertDateFromServer(res: EntityResponseType): EntityResponseType { + if (res.body) { + res.body.createdDate = res.body.createdDate ? dayjs(res.body.createdDate) : undefined; + res.body.lastModifiedDate = res.body.lastModifiedDate ? dayjs(res.body.lastModifiedDate) : undefined; + res.body.deletedDate = res.body.deletedDate ? dayjs(res.body.deletedDate) : undefined; + } + return res; + } + + protected convertDateArrayFromServer(res: EntityArrayResponseType): EntityArrayResponseType { + if (res.body) { + res.body.forEach((existingResource: IExistingResource) => { + existingResource.createdDate = existingResource.createdDate ? dayjs(existingResource.createdDate) : undefined; + existingResource.lastModifiedDate = existingResource.lastModifiedDate ? dayjs(existingResource.lastModifiedDate) : undefined; + existingResource.deletedDate = existingResource.deletedDate ? dayjs(existingResource.deletedDate) : undefined; + }); + } + return res; + } +} diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/update/existing-resource-update.component.html b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/update/existing-resource-update.component.html new file mode 100644 index 0000000..967d1ec --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/update/existing-resource-update.component.html @@ -0,0 +1,113 @@ +<div class="row justify-content-center"> + <div class="col-8"> + <form name="editForm" role="form" novalidate (ngSubmit)="save()" [formGroup]="editForm"> + <h2 id="jhi-instance-heading" data-cy="ExistingResourceCreateUpdateHeading" jhiTranslate="iecFrontendApp.iecBackendExistingResource.home.createOrEditLabel"> + Create or edit an Existing Resource + </h2> + + <div> + <jhi-alert-error></jhi-alert-error> + + <div class="form-group" [hidden]="true"> + <label class="form-control-label" jhiTranslate="global.field.id" for="field_id">ID</label> + <input type="number" class="form-control" name="id" id="field_id" data-cy="id" formControlName="id" [readonly]="true" /> + </div> + + <div class="form-group"> + <label class="form-control-label" jhiTranslate="iecFrontendApp.iecBackendExistingResource.dataName" for="field_dataName">Data name</label> + <input type="text" class="form-control" name="dataName" id="field_dataName" data-cy="dataName" formControlName="dataName" /> + <div *ngIf="editForm.get('dataName')!.invalid && (editForm.get('dataName')!.dirty || editForm.get('dataName')!.touched)"> + <small class="form-text text-danger" *ngIf="editForm.get('dataName')?.errors?.required" jhiTranslate="entity.validation.required"> + This field is required. + </small> + <small class="form-text text-danger" *ngIf="editForm.get('dataName')?.errors?.maxlength" jhiTranslate="entity.validation.maxlength" [translateValues]="{ max: 70 }"> + This field cannot be longer than 70 characters. + </small> + </div> + </div> + + <div class="form-group"> + <label class="form-control-label" jhiTranslate="iecFrontendApp.iecBackendExistingResource.dataType" for="field_dataType">Data type</label> + <input type="text" class="form-control" name="dataType" id="field_dataType" data-cy="dataType" formControlName="dataType" /> + <div *ngIf="editForm.get('dataType')!.invalid && (editForm.get('dataType')!.dirty || editForm.get('dataType')!.touched)"> + <small class="form-text text-danger" *ngIf="editForm.get('dataType')?.errors?.required" jhiTranslate="entity.validation.required"> + This field is required. + </small> + <small class="form-text text-danger" *ngIf="editForm.get('dataType')?.errors?.maxlength" jhiTranslate="entity.validation.maxlength" [translateValues]="{ max: 70 }"> + This field cannot be longer than 70 characters. + </small> + </div> + </div> + + <div class="form-group"> + <label class="form-control-label" jhiTranslate="iecFrontendApp.iecBackendExistingResource.name" for="field_name">Name</label> + <input type="text" class="form-control" name="name" id="field_name" data-cy="name" formControlName="name" /> + <div *ngIf="editForm.get('name')!.invalid && (editForm.get('name')!.dirty || editForm.get('name')!.touched)"> + <small class="form-text text-danger" *ngIf="editForm.get('name')?.errors?.required" jhiTranslate="entity.validation.required"> + This field is required. + </small> + <small class="form-text text-danger" *ngIf="editForm.get('name')?.errors?.maxlength" jhiTranslate="entity.validation.maxlength" [translateValues]="{ max: 70 }"> + This field cannot be longer than 70 characters. + </small> + </div> + </div> + + <div class="form-group"> + <label class="form-control-label" jhiTranslate="iecFrontendApp.iecBackendExistingResource.datacenterId" for="field_datacenterId">Datacenter id</label> + <input type="text" class="form-control" name="datacenterId" id="field_datacenterId" data-cy="datacenterId" formControlName="datacenterId" /> + <div *ngIf="editForm.get('datacenterId')!.invalid && (editForm.get('datacenterId')!.dirty || editForm.get('datacenterId')!.touched)"> + <small class="form-text text-danger" *ngIf="editForm.get('datacenterId')?.errors?.required" jhiTranslate="entity.validation.required"> + This field is required. + </small> + <small class="form-text text-danger" *ngIf="editForm.get('datacenterId')?.errors?.maxlength" jhiTranslate="entity.validation.maxlength" [translateValues]="{ max: 70 }"> + This field cannot be longer than 70 characters. + </small> + </div> + </div> + + <div class="form-group"> + <label class="form-control-label" jhiTranslate="iecFrontendApp.iecBackendExistingResource.user" for="field_user">User</label> + <input type="text" class="form-control" name="user" id="field_user" data-cy="user" formControlName="user" /> + <div *ngIf="editForm.get('user')!.invalid && (editForm.get('user')!.dirty || editForm.get('user')!.touched)"> + <small class="form-text text-danger" *ngIf="editForm.get('user')?.errors?.required" jhiTranslate="entity.validation.required"> + This field is required. + </small> + <small class="form-text text-danger" *ngIf="editForm.get('user')?.errors?.maxlength" jhiTranslate="entity.validation.maxlength" [translateValues]="{ max: 70 }"> + This field cannot be longer than 70 characters. + </small> + </div> + </div> + + <div class="form-group"> + <label class="form-control-label" jhiTranslate="iecFrontendApp.iecBackendExistingResource.provider" for="field_provider">Provider</label> + <input type="text" class="form-control" name="provider" id="field_provider" data-cy="provider" formControlName="provider" /> + <div *ngIf="editForm.get('provider')!.invalid && (editForm.get('provider')!.dirty || editForm.get('provider')!.touched)"> + <small class="form-text text-danger" *ngIf="editForm.get('provider')?.errors?.required" jhiTranslate="entity.validation.required"> + This field is required. + </small> + <small class="form-text text-danger" *ngIf="editForm.get('provider')?.errors?.maxlength" jhiTranslate="entity.validation.maxlength" [translateValues]="{ max: 70 }"> + This field cannot be longer than 70 characters. + </small> + </div> + </div> + <input type="hidden" id="field_createdDate" data-cy="createdDate" name="createdDate" formControlName="createdDate"/> + <input type="hidden" id="field_lastModifiedDate" data-cy="lastModifiedDate" name="lastModifiedDate" formControlName="lastModifiedDate"/> + <input type="hidden" id="field_deletedDate" data-cy="deletedDate" name="deletedDate" formControlName="deletedDate"/> + </div> + + <div class="form-group"> + {{editForm.invalid}} + </div> + + <div> + <button type="button" id="cancel-save" class="btn btn-secondary" (click)="previousState()"> + <fa-icon icon="ban"></fa-icon> <span jhiTranslate="entity.action.cancel">Cancel</span> + </button> + + <button type="submit" id="save-entity" data-cy="entityCreateSaveButton" [disabled]="editForm.invalid || isSaving" class="btn btn-primary"> + <fa-icon icon="save"></fa-icon> <span jhiTranslate="entity.action.save">Save</span> + </button> + </div> + </form> + </div> +</div> diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/update/existing-resource-update.component.spec.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/update/existing-resource-update.component.spec.ts new file mode 100644 index 0000000..1167a90 --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/update/existing-resource-update.component.spec.ts @@ -0,0 +1,120 @@ +jest.mock('@angular/router'); + +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { HttpResponse } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { FormBuilder } from '@angular/forms'; +import { ActivatedRoute } from '@angular/router'; +import { of, Subject } from 'rxjs'; + +import { ExistingResourceService } from '../service/existing-resource.service'; +import { IExistingResource, ExistingResource } from '../existing-resource.model'; + +import { ExistingResourceUpdateComponent } from './existing-resource-update.component'; + +describe('Component Tests', () => { + describe('Existing Resource Management Update Component', () => { + let comp: ExistingResourceUpdateComponent; + let fixture: ComponentFixture<ExistingResourceUpdateComponent>; + let activatedRoute: ActivatedRoute; + let existingResourceService: ExistingResourceService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + declarations: [ExistingResourceUpdateComponent], + providers: [FormBuilder, ActivatedRoute], + }) + .overrideTemplate(ExistingResourceUpdateComponent, '') + .compileComponents(); + + fixture = TestBed.createComponent(ExistingResourceUpdateComponent); + activatedRoute = TestBed.inject(ActivatedRoute); + existingResourceService = TestBed.inject(ExistingResourceService); + + comp = fixture.componentInstance; + }); + + describe('ngOnInit', () => { + it('Should call RootService query and add missing value', () => { + const existingResource: IExistingResource = { id: 456 }; + + activatedRoute.data = of({ existingResource }); + comp.ngOnInit(); + }); + + it('Should update editForm', () => { + const existingResource: IExistingResource = { id: 456 }; + + activatedRoute.data = of({ existingResource }); + comp.ngOnInit(); + + expect(comp.editForm.value).toEqual(expect.objectContaining(existingResource)); + }); + }); + + describe('save', () => { + it('Should call update service on save for existing entity', () => { + // GIVEN + const saveSubject = new Subject(); + const existingResource = { id: 123 }; + spyOn(existingResourceService, 'update').and.returnValue(saveSubject); + spyOn(comp, 'previousState'); + activatedRoute.data = of({ existingResource }); + comp.ngOnInit(); + + // WHEN + comp.save(); + expect(comp.isSaving).toEqual(true); + saveSubject.next(new HttpResponse({ body: existingResource })); + saveSubject.complete(); + + // THEN + expect(comp.previousState).toHaveBeenCalled(); + expect(existingResourceService.update).toHaveBeenCalledWith(existingResource); + expect(comp.isSaving).toEqual(false); + }); + + it('Should call create service on save for new entity', () => { + // GIVEN + const saveSubject = new Subject(); + const existingResource = new ExistingResource(); + spyOn(existingResourceService, 'create').and.returnValue(saveSubject); + spyOn(comp, 'previousState'); + activatedRoute.data = of({ existingResource }); + comp.ngOnInit(); + + // WHEN + comp.save(); + expect(comp.isSaving).toEqual(true); + saveSubject.next(new HttpResponse({ body: existingResource })); + saveSubject.complete(); + + // THEN + expect(existingResourceService.create).toHaveBeenCalledWith(existingResource); + expect(comp.isSaving).toEqual(false); + expect(comp.previousState).toHaveBeenCalled(); + }); + + it('Should set isSaving to false on error', () => { + // GIVEN + const saveSubject = new Subject(); + const existingResource = { id: 123 }; + spyOn(existingResourceService, 'update').and.returnValue(saveSubject); + spyOn(comp, 'previousState'); + activatedRoute.data = of({ existingResource }); + comp.ngOnInit(); + + // WHEN + comp.save(); + expect(comp.isSaving).toEqual(true); + saveSubject.error('This is an error!'); + + // THEN + expect(existingResourceService.update).toHaveBeenCalledWith(existingResource); + expect(comp.isSaving).toEqual(false); + expect(comp.previousState).not.toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/update/existing-resource-update.component.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/update/existing-resource-update.component.ts new file mode 100644 index 0000000..de19591 --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/existing-resource/update/existing-resource-update.component.ts @@ -0,0 +1,121 @@ +import { Component, OnInit } from '@angular/core'; +import { HttpResponse } from '@angular/common/http'; +import { FormBuilder, Validators } from '@angular/forms'; +import { ActivatedRoute } from '@angular/router'; +import { Observable } from 'rxjs'; +import { finalize } from 'rxjs/operators'; + +import * as dayjs from 'dayjs'; +import { DATE_TIME_FORMAT } from 'app/config/input.constants'; + +import { IExistingResource, ExistingResource } from '../existing-resource.model'; +import { ExistingResourceService } from '../service/existing-resource.service'; + +@Component({ + selector: 'jhi-existing-resource-update', + templateUrl: './existing-resource-update.component.html', +}) +export class ExistingResourceUpdateComponent implements OnInit { + isSaving = false; + + editForm = this.fb.group({ + id: [], + dataName: [null, [Validators.required, Validators.maxLength(70)]], + dataType: [null, [Validators.required, Validators.maxLength(70)]], + name: [null, [Validators.required, Validators.maxLength(70)]], + datacenterId: [null, [Validators.required, Validators.maxLength(70)]], + user: [null, [Validators.required, Validators.maxLength(70)]], + provider: [null, [Validators.required, Validators.maxLength(70)]], + createdDate: [null, [Validators.required]], + lastModifiedDate: [], + deletedDate: [] + }); + + constructor( + protected existingResourceService: ExistingResourceService, + protected activatedRoute: ActivatedRoute, + protected fb: FormBuilder + ) {} + + ngOnInit(): void { + this.activatedRoute.data.subscribe(({ existingResource }) => { + const today = dayjs(); + if (existingResource.id === undefined) { + existingResource.createdDate = today; + } else { + existingResource.lastModifiedDate = today; + } + this.updateForm(existingResource); + }); + } + + previousState(): void { + window.history.back(); + } + + save(): void { + this.isSaving = true; + const existingResource = this.createFromForm(); + if (existingResource.id !== undefined) { + this.subscribeToSaveResponse(this.existingResourceService.update(existingResource)); + } else { + this.subscribeToSaveResponse(this.existingResourceService.create(existingResource)); + } + } + + protected subscribeToSaveResponse(result: Observable<HttpResponse<IExistingResource>>): void { + result.pipe(finalize(() => this.onSaveFinalize())).subscribe( + () => this.onSaveSuccess(), + () => this.onSaveError() + ); + } + + protected onSaveSuccess(): void { + this.previousState(); + } + + protected onSaveError(): void { + // Api for inheritance. + } + + protected onSaveFinalize(): void { + this.isSaving = false; + } + + protected updateForm(existingResource: IExistingResource): void { + this.editForm.patchValue({ + id: existingResource!.id, + dataName: existingResource.dataName, + dataType: existingResource.dataType, + name: existingResource.name, + datacenterId: existingResource.datacenterId, + user: existingResource.user, + provider: existingResource.provider, + createdDate: existingResource.createdDate ? existingResource.createdDate.format(DATE_TIME_FORMAT) : null, + lastModifiedDate: existingResource.lastModifiedDate ? existingResource.lastModifiedDate.format(DATE_TIME_FORMAT) : null, + deletedDate: existingResource.deletedDate ? existingResource.deletedDate.format(DATE_TIME_FORMAT) : null + }); + } + + protected createFromForm(): IExistingResource { + return { + ...new ExistingResource(), + id: this.editForm.get(['id'])!.value, + dataName: this.editForm.get(['dataName'])!.value, + dataType: this.editForm.get(['dataType'])!.value, + name: this.editForm.get(['name'])!.value, + datacenterId: this.editForm.get(['datacenterId'])!.value, + user: this.editForm.get(['user'])!.value, + provider: this.editForm.get(['provider'])!.value, + createdDate: this.editForm.get(['createdDate'])!.value + ? dayjs(this.editForm.get(['createdDate'])!.value, DATE_TIME_FORMAT) + : undefined, + lastModifiedDate: this.editForm.get(['lastModifiedDate'])!.value + ? dayjs(this.editForm.get(['lastModifiedDate'])!.value, DATE_TIME_FORMAT) + : undefined, + deletedDate: this.editForm.get(['deletedDate'])!.value + ? dayjs(this.editForm.get(['deletedDate'])!.value, DATE_TIME_FORMAT) + : undefined + }; + } +} diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/detail/image-detail.component.html b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/detail/image-detail.component.html new file mode 100644 index 0000000..f6118f2 --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/detail/image-detail.component.html @@ -0,0 +1,24 @@ +<div class="row justify-content-center"> + <div class="col-6"> + <div class="card"> + <h5 class="card-header text-white bg-primary p-4 font-weight-bold" *ngIf="image?.imageType == imageVM">{{image?.imageName}}</h5> + <h5 class="card-header text-white bg-primary p-4 font-weight-bold" *ngIf="image?.imageType == imageDocker">{{image?.imageUrl}}</h5> + <div class="card-body"> + <span class="text-primary font-weight-bold" jhiTranslate="iecFrontendApp.iecBackendImage.imageType">Type</span> + <span> </span> + <span>{{ image?.imageType }}</span><br> + <span class="text-primary font-weight-bold" jhiTranslate="iecFrontendApp.iecBackendImage.imageDescription">Description</span> + <span> </span> + <span>{{ image?.imageDescription }}</span><br> + <span class="text-primary font-weight-bold" jhiTranslate="iecFrontendApp.iecBackendImage.imageProvider">Provider</span> + <span> </span> + <span>{{ image?.imageProvider }}</span> + </div> + <div class="card-footer"> + <button type="submit" (click)="previousState()" class="btn btn-info float-right" data-cy="entityDetailsBackButton"> + <fa-icon icon="arrow-left"></fa-icon> <span jhiTranslate="entity.action.back">Back</span> + </button> + </div> + </div> + </div> +</div> \ No newline at end of file diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/detail/image-detail.component.spec.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/detail/image-detail.component.spec.ts new file mode 100644 index 0000000..1def98e --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/detail/image-detail.component.spec.ts @@ -0,0 +1,38 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ActivatedRoute } from '@angular/router'; +import { of } from 'rxjs'; + +import { ImageDetailComponent } from './image-detail.component'; + +describe('Component Tests', () => { + describe('Image Management Detail Component', () => { + let comp: ImageDetailComponent; + let fixture: ComponentFixture<ImageDetailComponent>; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ImageDetailComponent], + providers: [ + { + provide: ActivatedRoute, + useValue: { data: of({ image: { id: 123 } }) }, + }, + ], + }) + .overrideTemplate(ImageDetailComponent, '') + .compileComponents(); + fixture = TestBed.createComponent(ImageDetailComponent); + comp = fixture.componentInstance; + }); + + describe('OnInit', () => { + it('Should load image on init', () => { + // WHEN + comp.ngOnInit(); + + // THEN + expect(comp.image).toEqual(jasmine.objectContaining({ id: 123 })); + }); + }); + }); +}); diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/detail/image-detail.component.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/detail/image-detail.component.ts new file mode 100644 index 0000000..3e0ca8b --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/detail/image-detail.component.ts @@ -0,0 +1,31 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +import { IImage } from '../image.model'; + +import { IMAGE_DOCKER, IMAGE_VM } from '../../../../app.constants'; + +@Component({ + selector: 'jhi-image-detail', + templateUrl: './image-detail.component.html', +}) +export class ImageDetailComponent implements OnInit { + image: IImage | null = null; + imageDocker: string; + imageVM: string; + + constructor(protected activatedRoute: ActivatedRoute) { + this.imageDocker = IMAGE_DOCKER; + this.imageVM = IMAGE_VM; + } + + ngOnInit(): void { + this.activatedRoute.data.subscribe(({ image }) => { + this.image = image; + }); + } + + previousState(): void { + window.history.back(); + } +} diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/image.model.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/image.model.ts new file mode 100644 index 0000000..765fcba --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/image.model.ts @@ -0,0 +1,31 @@ +import * as dayjs from 'dayjs'; + +export interface IImage { + id?: number; + imageType?: string; + imageName?: string; + imageUrl?: string; + imageDescription?: string; + imageProvider?: string; + createdDate?: dayjs.Dayjs; + lastModifiedDate?: dayjs.Dayjs | null; + deletedDate?: dayjs.Dayjs | null; +} + +export class Image implements IImage { + constructor( + public id?: number, + public imageType?: string, + public imageName?: string, + public imageUrl?: string, + public imageDescription?: string, + public imageProvider?: string, + public createdDate?: dayjs.Dayjs, + public lastModifiedDate?: dayjs.Dayjs | null, + public deletedDate?: dayjs.Dayjs | null, + ) {} +} + +export function getImageIdentifier(image: IImage): number | undefined { + return image.id; +} diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/image.module.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/image.module.ts new file mode 100644 index 0000000..1759a8c --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/image.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core'; + +import { SharedModule } from 'app/shared/shared.module'; +import { ImageComponent } from './list/image.component'; +import { ImageDetailComponent } from './detail/image-detail.component'; +import { ImageRoutingModule } from './route/image-routing.module'; + +@NgModule({ + imports: [SharedModule, ImageRoutingModule], + declarations: [ImageComponent, ImageDetailComponent], +}) +export class IecBackendImageModule {} diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/list/image.component.html b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/list/image.component.html new file mode 100644 index 0000000..0bc437d --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/list/image.component.html @@ -0,0 +1,94 @@ +<div> + <nav class="navbar navbar-dark bg-primary"> + <span class="navbar-brand mb-0 h1" jhiTranslate="iecFrontendApp.iecBackendImage.home.title">Images</span> + </nav> + + <h2 id="page-heading" data-cy="ImageHeading"> + <div class="d-flex justify-content-end mt-2"> + <button class="btn btn-info mr-2" (click)="loadPage()" [disabled]="isLoading"> + <fa-icon icon="sync" [spin]="isLoading"></fa-icon> + <span jhiTranslate="iecFrontendApp.iecBackendImage.home.refreshListLabel">Refresh List</span> + </button> + </div> + </h2> + + <jhi-alert-error></jhi-alert-error> + + <jhi-alert></jhi-alert> + + <div class="alert alert-warning" id="no-result" *ngIf="images?.length === 0"> + <span jhiTranslate="iecFrontendApp.iecBackendImage.home.notFound">No Images found</span> + </div> + + <div class="table-responsive" id="entities" *ngIf="images && images.length > 0"> + <table class="table table-striped" aria-describedby="page-heading"> + <thead> + <tr jhiSort [(predicate)]="predicate" [(ascending)]="ascending" [callback]="loadPage.bind(this)"> + <th scope="col" jhiSortBy="imageType"> + <span jhiTranslate="iecFrontendApp.iecBackendImage.imageType">Type</span> + <fa-icon icon="sort"></fa-icon> + </th> + <th scope="col" jhiSortBy="imageName"> + <span jhiTranslate="iecFrontendApp.iecBackendImage.imageName">Name</span> + <fa-icon icon="sort"></fa-icon> + </th> + <th scope="col" jhiSortBy="imageUrl"> + <span jhiTranslate="iecFrontendApp.iecBackendImage.imageUrl">URL</span> + <fa-icon icon="sort"></fa-icon> + </th> + <th scope="col" jhiSortBy="imageProvider"> + <span jhiTranslate="iecFrontendApp.iecBackendImage.imageProvider">Provider</span> + <fa-icon icon="sort"></fa-icon> + </th> + <th scope="col"> + <span jhiTranslate="iecFrontendApp.iecBackendImage.status">Status</span> + </th> + <th scope="col"></th> + </tr> + </thead> + <tbody> + <tr *ngFor="let image of images; trackBy: trackId" data-cy="entityTable"> + <td>{{ image.imageType }}</td> + <td>{{ image.imageName }}</td> + <td>{{ image.imageUrl }}</td> + <td>{{ image.imageProvider }}</td> + <td> + <span class="badge badge-success" jhiTranslate="iecFrontendApp.iecBackendImage.active" *ngIf="image.deletedDate == null">Active</span> + <span class="badge badge-danger" jhiTranslate="iecFrontendApp.iecBackendImage.inactive" *ngIf="image.deletedDate != null">Inactive</span> + </td> + <td class="text-right"> + <div class="btn-group"> + <button + type="submit" + [routerLink]="['/image', image.id, 'view']" + class="btn btn-info btn-sm" + data-cy="entityDetailsButton" + > + <fa-icon icon="eye"></fa-icon> + <span class="d-none d-md-inline" jhiTranslate="entity.action.view">View</span> + </button> + </div> + </td> + </tr> + </tbody> + </table> + </div> + + <div *ngIf="images && images.length > 0"> + <div class="row justify-content-center"> + <jhi-item-count [params]="{ page: page, totalItems: totalItems, itemsPerPage: itemsPerPage }"></jhi-item-count> + </div> + + <div class="row justify-content-center"> + <ngb-pagination + [collectionSize]="totalItems" + [(page)]="ngbPaginationPage" + [pageSize]="itemsPerPage" + [maxSize]="5" + [rotate]="true" + [boundaryLinks]="true" + (pageChange)="loadPage($event)" + ></ngb-pagination> + </div> + </div> +</div> diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/list/image.component.spec.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/list/image.component.spec.ts new file mode 100644 index 0000000..6065edf --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/list/image.component.spec.ts @@ -0,0 +1,100 @@ +jest.mock('@angular/router'); + +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { HttpHeaders, HttpResponse } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { ActivatedRoute, Router } from '@angular/router'; +import { of } from 'rxjs'; + +import { ImageService } from '../service/image.service'; + +import { ImageComponent } from './image.component'; + +describe('Component Tests', () => { + describe('Image Management Component', () => { + let comp: ImageComponent; + let fixture: ComponentFixture<ImageComponent>; + let service: ImageService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + declarations: [ImageComponent], + providers: [ + Router, + { + provide: ActivatedRoute, + useValue: { + data: of({ + defaultSort: 'id,asc', + }), + queryParamMap: of( + jest.requireActual('@angular/router').convertToParamMap({ + page: '1', + size: '1', + sort: 'id,desc', + }) + ), + }, + }, + ], + }) + .overrideTemplate(ImageComponent, '') + .compileComponents(); + + fixture = TestBed.createComponent(ImageComponent); + comp = fixture.componentInstance; + service = TestBed.inject(ImageService); + + const headers = new HttpHeaders().append('link', 'link;link'); + spyOn(service, 'query').and.returnValue( + of( + new HttpResponse({ + body: [{ id: 123 }], + headers, + }) + ) + ); + }); + + it('Should call load all on init', () => { + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.query).toHaveBeenCalled(); + expect(comp.images?.[0]).toEqual(jasmine.objectContaining({ id: 123 })); + }); + + it('should load a page', () => { + // WHEN + comp.loadPage(1); + + // THEN + expect(service.query).toHaveBeenCalled(); + expect(comp.images?.[0]).toEqual(jasmine.objectContaining({ id: 123 })); + }); + + it('should calculate the sort attribute for an id', () => { + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.query).toHaveBeenCalledWith(expect.objectContaining({ sort: ['id,desc'] })); + }); + + it('should calculate the sort attribute for a non-id attribute', () => { + // INIT + comp.ngOnInit(); + + // GIVEN + comp.predicate = 'name'; + + // WHEN + comp.loadPage(1); + + // THEN + expect(service.query).toHaveBeenLastCalledWith(expect.objectContaining({ sort: ['name,desc', 'id'] })); + }); + }); +}); diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/list/image.component.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/list/image.component.ts new file mode 100644 index 0000000..34825e7 --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/list/image.component.ts @@ -0,0 +1,105 @@ +import { Component, OnInit } from '@angular/core'; +import { HttpHeaders, HttpResponse } from '@angular/common/http'; +import { ActivatedRoute, Router } from '@angular/router'; +import { combineLatest } from 'rxjs'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; + +import { IImage } from '../image.model'; + +import { ITEMS_PER_PAGE } from 'app/config/pagination.constants'; +import { ImageService } from '../service/image.service'; + +@Component({ + selector: 'jhi-image', + templateUrl: './image.component.html', +}) +export class ImageComponent implements OnInit { + images?: IImage[]; + isLoading = false; + totalItems = 0; + itemsPerPage = ITEMS_PER_PAGE; + page?: number; + predicate!: string; + ascending!: boolean; + ngbPaginationPage = 1; + + constructor( + protected imageService: ImageService, + protected activatedRoute: ActivatedRoute, + protected router: Router, + protected modalService: NgbModal + ) {} + + loadPage(page?: number, dontNavigate?: boolean): void { + this.isLoading = true; + const pageToLoad: number = page ?? this.page ?? 1; + + this.imageService + .query({ + page: pageToLoad - 1, + size: this.itemsPerPage, + sort: this.sort(), + }) + .subscribe( + (res: HttpResponse<IImage[]>) => { + this.isLoading = false; + this.onSuccess(res.body, res.headers, pageToLoad, !dontNavigate); + }, + () => { + this.isLoading = false; + this.onError(); + } + ); + } + + ngOnInit(): void { + this.handleNavigation(); + } + + trackId(index: number, item: IImage): number { + return item.id!; + } + + protected sort(): string[] { + const result = [this.predicate + ',' + (this.ascending ? 'asc' : 'desc')]; + if (this.predicate !== 'id') { + result.push('id'); + } + return result; + } + + protected handleNavigation(): void { + combineLatest([this.activatedRoute.data, this.activatedRoute.queryParamMap]).subscribe(([data, params]) => { + const page = params.get('page'); + const pageNumber = page !== null ? +page : 1; + const sort = (params.get('sort') ?? data['defaultSort']).split(','); + const predicate = sort[0]; + const ascending = sort[1] === 'asc'; + if (pageNumber !== this.page || predicate !== this.predicate || ascending !== this.ascending) { + this.predicate = predicate; + this.ascending = ascending; + this.loadPage(pageNumber, true); + } + }); + } + + protected onSuccess(data: IImage[] | null, headers: HttpHeaders, page: number, navigate: boolean): void { + this.totalItems = Number(headers.get('X-Total-Count')); + this.page = page; + if (navigate) { + this.router.navigate(['/image'], { + queryParams: { + page: this.page, + size: this.itemsPerPage, + sort: this.predicate + ',' + (this.ascending ? 'asc' : 'desc'), + }, + }); + } + this.images = data ?? []; + this.ngbPaginationPage = this.page; + } + + protected onError(): void { + this.ngbPaginationPage = this.page ?? 1; + } +} diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/route/image-routing-resolve.service.spec.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/route/image-routing-resolve.service.spec.ts new file mode 100644 index 0000000..b645149 --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/route/image-routing-resolve.service.spec.ts @@ -0,0 +1,82 @@ +jest.mock('@angular/router'); + +import { TestBed } from '@angular/core/testing'; +import { HttpResponse } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { of } from 'rxjs'; + +import { IImage, Image } from '../image.model'; +import { ImageService } from '../service/image.service'; + +import { ImageRoutingResolveService } from './image-routing-resolve.service'; + +describe('Service Tests', () => { + describe('Image routing resolve service', () => { + let mockRouter: Router; + let mockActivatedRouteSnapshot: ActivatedRouteSnapshot; + let routingResolveService: ImageRoutingResolveService; + let service: ImageService; + let resultImage: IImage | undefined; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [Router, ActivatedRouteSnapshot], + }); + mockRouter = TestBed.inject(Router); + mockActivatedRouteSnapshot = TestBed.inject(ActivatedRouteSnapshot); + routingResolveService = TestBed.inject(ImageRoutingResolveService); + service = TestBed.inject(ImageService); + resultImage = undefined; + }); + + describe('resolve', () => { + it('should return IImage returned by find', () => { + // GIVEN + service.find = jest.fn(id => of(new HttpResponse({ body: { id } }))); + mockActivatedRouteSnapshot.params = { id: 123 }; + + // WHEN + routingResolveService.resolve(mockActivatedRouteSnapshot).subscribe(result => { + resultImage = result; + }); + + // THEN + expect(service.find).toBeCalledWith(123); + expect(resultImage).toEqual({ id: 123 }); + }); + + it('should return new IImage if id is not provided', () => { + // GIVEN + service.find = jest.fn(); + mockActivatedRouteSnapshot.params = {}; + + // WHEN + routingResolveService.resolve(mockActivatedRouteSnapshot).subscribe(result => { + resultImage = result; + }); + + // THEN + expect(service.find).not.toBeCalled(); + expect(resultImage).toEqual(new Image()); + }); + + it('should route to 404 page if data not found in server', () => { + // GIVEN + spyOn(service, 'find').and.returnValue(of(new HttpResponse({ body: null }))); + mockActivatedRouteSnapshot.params = { id: 123 }; + + // WHEN + routingResolveService.resolve(mockActivatedRouteSnapshot).subscribe(result => { + resultImage = result; + }); + + // THEN + expect(service.find).toBeCalledWith(123); + expect(resultImage).toEqual(undefined); + expect(mockRouter.navigate).toHaveBeenCalledWith(['404']); + }); + }); + }); +}); diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/route/image-routing-resolve.service.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/route/image-routing-resolve.service.ts new file mode 100644 index 0000000..02bceff --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/route/image-routing-resolve.service.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@angular/core'; +import { HttpResponse } from '@angular/common/http'; +import { Resolve, ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Observable, of, EMPTY } from 'rxjs'; +import { mergeMap } from 'rxjs/operators'; + +import { IImage, Image } from '../image.model'; +import { ImageService } from '../service/image.service'; + +@Injectable({ providedIn: 'root' }) +export class ImageRoutingResolveService implements Resolve<IImage> { + constructor(protected service: ImageService, protected router: Router) {} + + resolve(route: ActivatedRouteSnapshot): Observable<IImage> | Observable<never> { + const id = route.params['id']; + if (id) { + return this.service.find(id).pipe( + mergeMap((image: HttpResponse<Image>) => { + if (image.body) { + return of(image.body); + } else { + this.router.navigate(['404']); + return EMPTY; + } + }) + ); + } + return of(new Image()); + } +} diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/route/image-routing.module.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/route/image-routing.module.ts new file mode 100644 index 0000000..76fd509 --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/route/image-routing.module.ts @@ -0,0 +1,32 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { UserRouteAccessService } from 'app/core/auth/user-route-access.service'; +import { ImageComponent } from '../list/image.component'; +import { ImageDetailComponent } from '../detail/image-detail.component'; +import { ImageRoutingResolveService } from './image-routing-resolve.service'; + +const imageRoute: Routes = [ + { + path: '', + component: ImageComponent, + data: { + defaultSort: 'id,asc', + }, + canActivate: [UserRouteAccessService], + }, + { + path: ':id/view', + component: ImageDetailComponent, + resolve: { + image: ImageRoutingResolveService, + }, + canActivate: [UserRouteAccessService], + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(imageRoute)], + exports: [RouterModule], +}) +export class ImageRoutingModule {} diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/service/image.service.spec.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/service/image.service.spec.ts new file mode 100644 index 0000000..afb6a0f --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/service/image.service.spec.ts @@ -0,0 +1,203 @@ +import { TestBed } from '@angular/core/testing'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; +import * as dayjs from 'dayjs'; + +import { DATE_TIME_FORMAT } from 'app/config/input.constants'; +import { IImage, Image } from '../image.model'; + +import { ImageService } from './image.service'; + +describe('Image Tests', () => { + describe('Image Service', () => { + let service: ImageService; + let httpMock: HttpTestingController; + let elemDefault: IImage; + let expectedResult: IImage | IImage[] | boolean | null; + let currentDate: dayjs.Dayjs; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + }); + expectedResult = null; + service = TestBed.inject(ImageService); + httpMock = TestBed.inject(HttpTestingController); + currentDate = dayjs(); + + elemDefault = { + id: 0, + imageName: 'AAAAAAA', + createdDate: currentDate, + lastModifiedDate: currentDate, + deletedDate: currentDate, + }; + }); + + describe('Image methods', () => { + it('should find an element', () => { + const returnedFromService = Object.assign( + { + createdDate: currentDate.format(DATE_TIME_FORMAT), + lastModifiedDate: currentDate.format(DATE_TIME_FORMAT), + deletedDate: currentDate.format(DATE_TIME_FORMAT), + }, + elemDefault + ); + + service.find(123).subscribe(resp => (expectedResult = resp.body)); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush(returnedFromService); + expect(expectedResult).toMatchObject(elemDefault); + }); + + it('should create an Image', () => { + const returnedFromService = Object.assign( + { + id: 0, + createdDate: currentDate.format(DATE_TIME_FORMAT), + lastModifiedDate: currentDate.format(DATE_TIME_FORMAT), + deletedDate: currentDate.format(DATE_TIME_FORMAT), + }, + elemDefault + ); + + const expected = Object.assign( + { + createdDate: currentDate, + lastModifiedDate: currentDate, + deletedDate: currentDate, + }, + returnedFromService + ); + + service.create(new Image()).subscribe(resp => (expectedResult = resp.body)); + + const req = httpMock.expectOne({ method: 'POST' }); + req.flush(returnedFromService); + expect(expectedResult).toMatchObject(expected); + }); + + it('should update an Image', () => { + const returnedFromService = Object.assign( + { + id: 1, + imageName: 'BBBBBB', + createdDate: currentDate.format(DATE_TIME_FORMAT), + lastModifiedDate: currentDate.format(DATE_TIME_FORMAT), + deletedDate: currentDate.format(DATE_TIME_FORMAT), + }, + elemDefault + ); + + const expected = Object.assign( + { + createdDate: currentDate, + lastModifiedDate: currentDate, + deletedDate: currentDate, + }, + returnedFromService + ); + + service.update(expected).subscribe(resp => (expectedResult = resp.body)); + + const req = httpMock.expectOne({ method: 'PUT' }); + req.flush(returnedFromService); + expect(expectedResult).toMatchObject(expected); + }); + + it('should return a list of Images', () => { + const returnedFromService = Object.assign( + { + id: 1, + imageName: 'BBBBBB', + createdDate: currentDate.format(DATE_TIME_FORMAT), + lastModifiedDate: currentDate.format(DATE_TIME_FORMAT), + deletedDate: currentDate.format(DATE_TIME_FORMAT), + }, + elemDefault + ); + + const expected = Object.assign( + { + createdDate: currentDate, + lastModifiedDate: currentDate, + deletedDate: currentDate, + }, + returnedFromService + ); + + service.query().subscribe(resp => (expectedResult = resp.body)); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush([returnedFromService]); + httpMock.verify(); + expect(expectedResult).toContainEqual(expected); + }); + + it('should delete an Image', () => { + service.delete(123).subscribe(resp => (expectedResult = resp.ok)); + + const req = httpMock.expectOne({ method: 'DELETE' }); + req.flush({ status: 200 }); + expect(expectedResult); + }); + + describe('addImageToCollectionIfMissing', () => { + it('should add an Image to an empty array', () => { + const image: IImage = { id: 123 }; + expectedResult = service.addImageToCollectionIfMissing([], image); + expect(expectedResult).toHaveLength(1); + expect(expectedResult).toContain(image); + }); + + it('should not add an Image to an array that contains it', () => { + const image: IImage = { id: 123 }; + const imageCollection: IImage[] = [ + { + ...image, + }, + { id: 456 }, + ]; + expectedResult = service.addImageToCollectionIfMissing(imageCollection, image); + expect(expectedResult).toHaveLength(2); + }); + + it("should add an Image to an array that doesn't contain it", () => { + const image: IImage = { id: 123 }; + const imageCollection: IImage[] = [{ id: 456 }]; + expectedResult = service.addImageToCollectionIfMissing(imageCollection, image); + expect(expectedResult).toHaveLength(2); + expect(expectedResult).toContain(image); + }); + + it('should add only unique Image to an array', () => { + const imageArray: IImage[] = [{ id: 123 }, { id: 456 }, { id: 27673 }]; + const imageCollection: IImage[] = [{ id: 123 }]; + expectedResult = service.addImageToCollectionIfMissing(imageCollection, ...imageArray); + expect(expectedResult).toHaveLength(3); + }); + + it('should accept varargs', () => { + const image: IImage = { id: 123 }; + const image2: IImage = { id: 456 }; + expectedResult = service.addImageToCollectionIfMissing([], image, image2); + expect(expectedResult).toHaveLength(2); + expect(expectedResult).toContain(image); + expect(expectedResult).toContain(image2); + }); + + it('should accept null and undefined values', () => { + const image: IImage = { id: 123 }; + expectedResult = service.addImageToCollectionIfMissing([], null, image, undefined); + expect(expectedResult).toHaveLength(1); + expect(expectedResult).toContain(image); + }); + }); + }); + + afterEach(() => { + httpMock.verify(); + }); + }); +}); diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/service/image.service.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/service/image.service.ts new file mode 100644 index 0000000..e38b63e --- /dev/null +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/image/service/image.service.ts @@ -0,0 +1,83 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpResponse } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import * as dayjs from 'dayjs'; + +import { isPresent } from 'app/core/util/operators'; +import { ApplicationConfigService } from 'app/core/config/application-config.service'; +import { createRequestOption } from 'app/core/request/request-util'; +import { IImage, getImageIdentifier } from '../image.model'; + +export type EntityResponseType = HttpResponse<IImage>; +export type EntityArrayResponseType = HttpResponse<IImage[]>; + +@Injectable({ providedIn: 'root' }) +export class ImageService { + public resourceUrl = this.applicationConfigService.getEndpointFor('api/images', 'iecbackend'); + + constructor(protected http: HttpClient, private applicationConfigService: ApplicationConfigService) {} + + find(id: number): Observable<EntityResponseType> { + return this.http + .get<IImage>(`${this.resourceUrl}/${id}`, { observe: 'response' }) + .pipe(map((res: EntityResponseType) => this.convertDateFromServer(res))); + } + + query(req?: any): Observable<EntityArrayResponseType> { + const options = createRequestOption(req); + return this.http + .get<IImage[]>(this.resourceUrl, { params: options, observe: 'response' }) + .pipe(map((res: EntityArrayResponseType) => this.convertDateArrayFromServer(res))); + } + + addImageToCollectionIfMissing( + imageCollection: IImage[], + ...imagesToCheck: (IImage | null | undefined)[] + ): IImage[] { + const images: IImage[] = imagesToCheck.filter(isPresent); + if (images.length > 0) { + const imageCollectionIdentifiers = imageCollection.map( + imageItem => getImageIdentifier(imageItem)! + ); + const imagesToAdd = images.filter(imageItem => { + const imageIdentifier = getImageIdentifier(imageItem); + if (imageIdentifier == null || imageCollectionIdentifiers.includes(imageIdentifier)) { + return false; + } + imageCollectionIdentifiers.push(imageIdentifier); + return true; + }); + return [...imagesToAdd, ...imageCollection]; + } + return imageCollection; + } + + protected convertDateFromClient(image: IImage): IImage { + return Object.assign({}, image, { + createdDate: image.createdDate?.isValid() ? image.createdDate.toJSON() : undefined, + lastModifiedDate: image.lastModifiedDate?.isValid() ? image.lastModifiedDate.toJSON() : undefined, + deletedDate: image.deletedDate?.isValid() ? image.deletedDate.toJSON() : undefined, + }); + } + + protected convertDateFromServer(res: EntityResponseType): EntityResponseType { + if (res.body) { + res.body.createdDate = res.body.createdDate ? dayjs(res.body.createdDate) : undefined; + res.body.lastModifiedDate = res.body.lastModifiedDate ? dayjs(res.body.lastModifiedDate) : undefined; + res.body.deletedDate = res.body.deletedDate ? dayjs(res.body.deletedDate) : undefined; + } + return res; + } + + protected convertDateArrayFromServer(res: EntityArrayResponseType): EntityArrayResponseType { + if (res.body) { + res.body.forEach((image: IImage) => { + image.createdDate = image.createdDate ? dayjs(image.createdDate) : undefined; + image.lastModifiedDate = image.lastModifiedDate ? dayjs(image.lastModifiedDate) : undefined; + image.deletedDate = image.deletedDate ? dayjs(image.deletedDate) : undefined; + }); + } + return res; + } +} diff --git a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/root-service/detail/root-service-detail.component.ts b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/root-service/detail/root-service-detail.component.ts index ba069dd..9f51339 100644 --- a/git/iec-frontend/src/main/webapp/app/entities/iecBackend/root-service/detail/root-service-detail.component.ts +++ b/git/iec-frontend/src/main/webapp/app/entities/iecBackend/root-service/detail/root-service-detail.component.ts @@ -16,6 +16,17 @@ export class RootServiceDetailComponent implements OnInit { ngOnInit(): void { this.activatedRoute.data.subscribe(({ rootService }) => { this.rootService = rootService; + const VALUES = this.rootService!.serviceAttributeValues!; + for (let i = 0;i < VALUES!.length;i++) { + if (VALUES![i].serviceAttributeType!.definitions != null) { + for (let j = 0;j < VALUES![i].serviceAttributeType!.definitions!.length;j++) { + if (VALUES![i].serviceAttributeValue === VALUES![i].serviceAttributeType!.definitions![j].code) { + VALUES![i].serviceAttributeValue = VALUES![i].serviceAttributeType!.definitions![j].value; + break; + } + } + } + } }); } diff --git a/git/iec-frontend/src/main/webapp/app/layouts/navbar/navbar.component.html b/git/iec-frontend/src/main/webapp/app/layouts/navbar/navbar.component.html index eb69021..514a200 100644 --- a/git/iec-frontend/src/main/webapp/app/layouts/navbar/navbar.component.html +++ b/git/iec-frontend/src/main/webapp/app/layouts/navbar/navbar.component.html @@ -51,6 +51,22 @@ </span> </a> </li> + <li class="nav-item" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }"> + <a class="nav-link" routerLink="image" (click)="collapseNavbar()"> + <span> + <fa-icon icon="asterisk"></fa-icon> + <span jhiTranslate="global.menu.entities.iecBackendImages">Images</span> + </span> + </a> + </li> + <li class="nav-item" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }"> + <a class="nav-link" routerLink="existing-resource" (click)="collapseNavbar()"> + <span> + <fa-icon icon="asterisk"></fa-icon> + <span jhiTranslate="global.menu.entities.iecBackendExistingResources">Existing Resources</span> + </span> + </a> + </li> <!-- jhipster-needle-add-element-to-menu - JHipster will add new menu items here <li diff --git a/git/iec-frontend/src/main/webapp/i18n/en/global.json b/git/iec-frontend/src/main/webapp/i18n/en/global.json index afb9381..0c6db75 100644 --- a/git/iec-frontend/src/main/webapp/i18n/en/global.json +++ b/git/iec-frontend/src/main/webapp/i18n/en/global.json @@ -13,6 +13,8 @@ "iecBackendServiceAttributeType": "Service Attribute Type", "iecBackendServiceAttributeValue": "Service Attribute Value", "iecBackendInstance": "Instances", + "iecBackendImages": "Images", + "iecBackendExistingResources": "Existing Resources", "jhipster-needle-menu-add-entry": "JHipster will add additional entities here (do not translate!)" }, "account": { diff --git a/git/iec-frontend/src/main/webapp/i18n/en/iecBackendExistingResource.json b/git/iec-frontend/src/main/webapp/i18n/en/iecBackendExistingResource.json new file mode 100644 index 0000000..27d8232 --- /dev/null +++ b/git/iec-frontend/src/main/webapp/i18n/en/iecBackendExistingResource.json @@ -0,0 +1,39 @@ +{ + "iecFrontendApp": { + "iecBackendExistingResource": { + "home": { + "title": "Existing Resources", + "refreshListLabel": "Refresh list", + "createLabel": "Create a new Existing Resource", + "createOrEditLabel": "Create or edit an Existing Resource", + "notFound": "No Existing Resource found" + }, + "delete": { + "question": "Are you sure you want to delete Existing Resource {{ id }}?" + }, + "detail": { + "title": "Existing Resource" + }, + "id": "ID", + "dataName": "Data name", + "dataType": "Data type", + "name": "Name", + "datacenterId": "Datacenter Id", + "user": "User", + "provider": "Provider", + "createdDate": "Created Date", + "lastModifiedDate": "Last Modified Date", + "deletedDate": "Deleted Date", + "status": "Status", + "active": "Active", + "inactive": "Inactive" + } + }, + "iecBackendApp": { + "iecBackendExistingResource": { + "created": "A new Existing Resource is created with identifier {{ param }}", + "updated": "An Existing Resource is updated with identifier {{ param }}", + "deleted": "An Existing Resource is deleted with identifier {{ param }}" + } + } +} diff --git a/git/iec-frontend/src/main/webapp/i18n/en/iecBackendImage.json b/git/iec-frontend/src/main/webapp/i18n/en/iecBackendImage.json new file mode 100644 index 0000000..51f6d40 --- /dev/null +++ b/git/iec-frontend/src/main/webapp/i18n/en/iecBackendImage.json @@ -0,0 +1,38 @@ +{ + "iecFrontendApp": { + "iecBackendImage": { + "home": { + "title": "Images", + "refreshListLabel": "Refresh list", + "createLabel": "Create a new Image", + "createOrEditLabel": "Create or edit an Image", + "notFound": "No Image found" + }, + "delete": { + "question": "Are you sure you want to delete Image {{ id }}?" + }, + "detail": { + "title": "Image" + }, + "id": "ID", + "imageType": "Type", + "imageName": "Name", + "imageUrl": "URL", + "imageDescription": "Description", + "imageProvider": "Provider", + "createdDate": "Created Date", + "lastModifiedDate": "Last Modified Date", + "deletedDate": "Deleted Date", + "status": "Status", + "active": "Active", + "inactive": "Inactive" + } + }, + "iecBackendApp": { + "iecBackendImage": { + "created": "A new Image is created with identifier {{ param }}", + "updated": "An Image is updated with identifier {{ param }}", + "deleted": "An Image is deleted with identifier {{ param }}" + } + } +} diff --git a/git/iec-frontend/src/main/webapp/i18n/es/global.json b/git/iec-frontend/src/main/webapp/i18n/es/global.json index d6573d6..fa19e45 100644 --- a/git/iec-frontend/src/main/webapp/i18n/es/global.json +++ b/git/iec-frontend/src/main/webapp/i18n/es/global.json @@ -13,6 +13,8 @@ "iecBackendServiceAttributeType": "Service Attribute Type", "iecBackendServiceAttributeValue": "Service Attribute Value", "iecBackendInstance": "Instancias", + "iecBackendImages": "Imágenes", + "iecBackendExistingResources": "Recursos Existentes", "jhipster-needle-menu-add-entry": "JHipster will add additional entities here (do not translate!)" }, "account": { diff --git a/git/iec-frontend/src/main/webapp/i18n/es/iecBackendExistingResource.json b/git/iec-frontend/src/main/webapp/i18n/es/iecBackendExistingResource.json new file mode 100644 index 0000000..c57ba7e --- /dev/null +++ b/git/iec-frontend/src/main/webapp/i18n/es/iecBackendExistingResource.json @@ -0,0 +1,39 @@ +{ + "iecFrontendApp": { + "iecBackendExistingResource": { + "home": { + "title": "Recursos Existentes", + "refreshListLabel": "Refrescar lista", + "createLabel": "Crear nuevo Recurso Existente", + "createOrEditLabel": "Crear o editar Recurso Existente", + "notFound": "Ningun Recurso Existente encontrado" + }, + "delete": { + "question": "¿Seguro que quiere eliminar el Recurso Existente {{ id }}?" + }, + "detail": { + "title": "Recurso Existente" + }, + "id": "ID", + "dataName": "Nombre de dato", + "dataType": "Tipo de dato", + "name": "Nombre", + "datacenterId": "Id del Datacenter", + "user": "Usuario", + "provider": "Proveedor", + "createdDate": "Fecha de creación", + "lastModifiedDate": "Fecha última modificación", + "deletedDate": "Fecha eliminación", + "status": "Estado", + "active": "Activo", + "inactive": "Inactivo" + } + }, + "iecBackendApp": { + "iecBackendExistingResource": { + "created": "Un nuevo Recurso Existente ha sido creado con el identificador {{ param }}", + "updated": "Un Recurso Existente ha sido actualizado con el identificador {{ param }}", + "deleted": "Un Recurso Existente ha sido eliminado con el identificador {{ param }}" + } + } +} diff --git a/git/iec-frontend/src/main/webapp/i18n/es/iecBackendImage.json b/git/iec-frontend/src/main/webapp/i18n/es/iecBackendImage.json new file mode 100644 index 0000000..db3950d --- /dev/null +++ b/git/iec-frontend/src/main/webapp/i18n/es/iecBackendImage.json @@ -0,0 +1,38 @@ +{ + "iecFrontendApp": { + "iecBackendImage": { + "home": { + "title": "Imágenes", + "refreshListLabel": "Refrescar lista", + "createLabel": "Crear nueva Imagen", + "createOrEditLabel": "Crear o editar Imagen", + "notFound": "Ninguna Imagen encontrada" + }, + "delete": { + "question": "¿Seguro que quiere eliminar la Imagen {{ id }}?" + }, + "detail": { + "title": "Imagen" + }, + "id": "ID", + "imageType": "Tipo", + "imageName": "Nombre", + "imageUrl": "URL", + "imageDescription": "Descripción", + "imageProvider": "Proveedor", + "createdDate": "Fecha de creación", + "lastModifiedDate": "Fecha última modificación", + "deletedDate": "Fecha eliminación", + "status": "Estado", + "active": "Activa", + "inactive": "Inactiva" + } + }, + "iecBackendApp": { + "iecBackendImage": { + "created": "Una nueva Imagen ha sido creada con el identificador {{ param }}", + "updated": "Una Imagen ha sido actualizada con el identificador {{ param }}", + "deleted": "Una Imagen ha sido eliminada con el identificador {{ param }}" + } + } +} diff --git a/git/iec-mysql/startupscripts/02_createTables.sql b/git/iec-mysql/startupscripts/02_createTables.sql index 878af67..defbd80 100644 --- a/git/iec-mysql/startupscripts/02_createTables.sql +++ b/git/iec-mysql/startupscripts/02_createTables.sql @@ -170,8 +170,54 @@ CREATE TABLE `service_class_attribute` ( LOCK TABLES `service_class_attribute` WRITE; /*!40000 ALTER TABLE `service_class_attribute` DISABLE KEYS */; /*!40000 ALTER TABLE `service_class_attribute` ENABLE KEYS */; +UNLOCK TABLES; +DROP TABLE IF EXISTS `existing_resource`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `existing_resource` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `data_name` varchar(70) NOT NULL, + `data_type` varchar(70) NOT NULL, + `name` varchar(70) NOT NULL, + `datacenter_id` varchar(70) NOT NULL, + `user` varchar(70) NOT NULL, + `provider` varchar(70) NOT NULL, + `created_date` datetime(6) NOT NULL, + `last_modified_date` datetime(6), + `deleted_date` datetime(6), + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +LOCK TABLES `existing_resource` WRITE; +/*!40000 ALTER TABLE `existing_resource` DISABLE KEYS */; +/*!40000 ALTER TABLE `existing_resource` ENABLE KEYS */; UNLOCK TABLES; + +DROP TABLE IF EXISTS `image`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `image` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `image_type` varchar(10) NOT NULL, + `image_name` varchar(100), + `image_url` varchar(255), + `image_description` text, + `image_provider` varchar(70) NOT NULL, + `created_date` datetime(6) NOT NULL, + `last_modified_date` datetime(6), + `deleted_date` datetime(6), + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +LOCK TABLES `image` WRITE; +/*!40000 ALTER TABLE `image` DISABLE KEYS */; +/*!40000 ALTER TABLE `image` ENABLE KEYS */; +UNLOCK TABLES; + + ALTER TABLE `instance_incidence` ADD CONSTRAINT `fk_instance_incidence__instance_id` FOREIGN KEY (`instance_id`) REFERENCES `instance` (`id`); diff --git a/git/iec-mysql/startupscripts/03_initialData.sql b/git/iec-mysql/startupscripts/03_initialData.sql index 41938e4..f69df04 100644 --- a/git/iec-mysql/startupscripts/03_initialData.sql +++ b/git/iec-mysql/startupscripts/03_initialData.sql @@ -66,6 +66,19 @@ INSERT INTO iecbackend.root_service (service_name,first_contract,first_contract_ /*51*/('m1.medium',NULL,'',NULL,'',NULL,'3','2020-04-01 17:46:19','2020-04-01 17:46:19',NULL,3), /*52*/('m1.large',NULL,'',NULL,'',NULL,'3','2020-04-01 17:46:19','2020-04-01 17:46:19',NULL,3), /*53*/('m1.xlarge',NULL,'',NULL,'',NULL,'3','2020-04-01 17:46:19','2020-04-01 17:46:19',NULL,3); +INSERT INTO iecbackend.root_service (service_name,first_contract,first_contract_content_type,second_contract,second_contract_content_type,third_contract,third_contract_content_type,created_date,last_modified_date,deleted_date,service_class_id) VALUES +/*54*/('Nano',NULL,'',NULL,'',NULL,'3','2023-05-18 17:46:19','2023-05-18 17:46:19',NULL,3), +/*55*/('Micro',NULL,'',NULL,'',NULL,'3','2023-05-18 17:46:19','2023-05-18 17:46:19',NULL,3), +/*56*/('Small',NULL,'',NULL,'',NULL,'3','2023-05-18 17:46:19','2023-05-18 17:46:19',NULL,3), +/*57*/('Medium',NULL,'',NULL,'',NULL,'3','2023-05-18 17:46:19','2023-05-18 17:46:19',NULL,3), +/*58*/('Large',NULL,'',NULL,'',NULL,'3','2023-05-18 17:46:19','2023-05-18 17:46:19',NULL,3), +/*59*/('2Large',NULL,'',NULL,'',NULL,'3','2023-05-18 17:46:19','2023-05-18 17:46:19',NULL,3), +/*60*/('XLarge',NULL,'',NULL,'',NULL,'3','2023-05-18 17:46:19','2023-05-18 17:46:19',NULL,3), +/*61*/('X2Large',NULL,'',NULL,'',NULL,'3','2023-05-18 17:46:19','2023-05-18 17:46:19',NULL,3), +/*62*/('X3Large',NULL,'',NULL,'',NULL,'3','2023-05-18 17:46:19','2023-05-18 17:46:19',NULL,3), +/*64*/('X4Large',NULL,'',NULL,'',NULL,'3','2023-05-18 17:46:19','2023-05-18 17:46:19',NULL,3); +INSERT INTO iecbackend.root_service (service_name,first_contract,first_contract_content_type,second_contract,second_contract_content_type,third_contract,third_contract_content_type,created_date,last_modified_date,deleted_date,service_class_id) VALUES +/*64*/('ionos Example1',NULL,'',NULL,'',NULL,'3','2023-05-18 17:46:19','2023-05-18 17:46:19',NULL,3); -- -------------------------------------------------- -- Service attribute types: @@ -819,6 +832,7 @@ INSERT INTO iecbackend.service_attribute_value (service_attribute_value,unit_val ('100','millisecond','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,21,47), ('','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,24,47), ('186','euro','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,25,47), + ('00NA','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,1,48), ('USNA','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,2,48), ('AMAZ','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,3,48), @@ -836,7 +850,7 @@ INSERT INTO iecbackend.service_attribute_value (service_attribute_value,unit_val ('200','dollar','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,25,48); -- -------------------------------------------------- --- OpenStack flavours +-- OpenStack flavours (5) -- -------------------------------------------------- INSERT INTO iecbackend.service_attribute_value (service_attribute_value,unit_value,check_list_value,created_date,last_modified_date,deleted_date,service_attribute_type_id,root_service_id) VALUES ('00EU','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,1,49), @@ -913,6 +927,177 @@ INSERT INTO iecbackend.service_attribute_value (service_attribute_value,unit_val ('2','millisecond','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,21,53), ('','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,24,53), ('160','euro','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,25,53); + +-- -------------------------------------------------- +-- VMware templates +-- -------------------------------------------------- +INSERT INTO iecbackend.service_attribute_value (root_service_id, service_attribute_value,unit_value,check_list_value,created_date,last_modified_date,deleted_date,service_attribute_type_id) VALUES + (54, '00EU','','','2023-05-19 17:46:20','2023-05-19 17:46:20',NULL,1), + (54, 'SPEU','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,2), + (54, 'VSPH','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,3), + (54, '1','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,4), + (54, '1500','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,5), + (54, '0.5','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,6), + (54, '10','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,7), + (54, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,8), + (54, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,9), + (54, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,10), + (54, '98','percentage','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,20), + (54, '10','millisecond','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,21), + (54, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,24), + (54, '10','euro','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,25); +INSERT INTO iecbackend.service_attribute_value (root_service_id, service_attribute_value,unit_value,check_list_value,created_date,last_modified_date,deleted_date,service_attribute_type_id) VALUES + (55, '00EU','','','2023-05-19 17:46:20','2023-05-19 17:46:20',NULL,1), + (55, 'SPEU','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,2), + (55, 'VSPH','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,3), + (55, '1','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,4), + (55, '1500','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,5), + (55, '1','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,6), + (55, '20','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,7), + (55, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,8), + (55, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,9), + (55, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,10), + (55, '98','percentage','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,20), + (55, '10','millisecond','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,21), + (55, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,24), + (55, '20','euro','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,25); +INSERT INTO iecbackend.service_attribute_value (root_service_id, service_attribute_value,unit_value,check_list_value,created_date,last_modified_date,deleted_date,service_attribute_type_id) VALUES + (56, '00EU','','','2023-05-19 17:46:20','2023-05-19 17:46:20',NULL,1), + (56, 'SPEU','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,2), + (56, 'VSPH','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,3), + (56, '1','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,4), + (56, '1500','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,5), + (56, '2','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,6), + (56, '40','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,7), + (56, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,8), + (56, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,9), + (56, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,10), + (56, '98','percentage','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,20), + (56, '10','millisecond','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,21), + (56, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,24), + (56, '40','euro','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,25); +INSERT INTO iecbackend.service_attribute_value (root_service_id, service_attribute_value,unit_value,check_list_value,created_date,last_modified_date,deleted_date,service_attribute_type_id) VALUES + (57, '00EU','','','2023-05-19 17:46:20','2023-05-19 17:46:20',NULL,1), + (57, 'SPEU','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,2), + (57, 'VSPH','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,3), + (57, '2','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,4), + (57, '1500','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,5), + (57, '4','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,6), + (57, '40','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,7), + (57, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,8), + (57, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,9), + (57, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,10), + (57, '98','percentage','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,20), + (57, '10','millisecond','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,21), + (57, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,24), + (57, '80','euro','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,25); +INSERT INTO iecbackend.service_attribute_value (root_service_id, service_attribute_value,unit_value,check_list_value,created_date,last_modified_date,deleted_date,service_attribute_type_id) VALUES + (58, '00EU','','','2023-05-19 17:46:20','2023-05-19 17:46:20',NULL,1), + (58, 'SPEU','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,2), + (58, 'VSPH','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,3), + (58, '2','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,4), + (58, '1500','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,5), + (58, '8','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,6), + (58, '80','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,7), + (58, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,8), + (58, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,9), + (58, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,10), + (58, '98','percentage','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,20), + (58, '10','millisecond','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,21), + (58, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,24), + (58, '100','euro','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,25); +INSERT INTO iecbackend.service_attribute_value (root_service_id, service_attribute_value,unit_value,check_list_value,created_date,last_modified_date,deleted_date,service_attribute_type_id) VALUES + (59, '00EU','','','2023-05-19 17:46:20','2023-05-19 17:46:20',NULL,1), + (59, 'SPEU','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,2), + (59, 'VSPH','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,3), + (59, '4','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,4), + (59, '1500','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,5), + (59, '8','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,6), + (59, '80','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,7), + (59, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,8), + (59, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,9), + (59, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,10), + (59, '98','percentage','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,20), + (59, '10','millisecond','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,21), + (59, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,24), + (59, '150','euro','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,25); +INSERT INTO iecbackend.service_attribute_value (root_service_id, service_attribute_value,unit_value,check_list_value,created_date,last_modified_date,deleted_date,service_attribute_type_id) VALUES + (60, '00EU','','','2023-05-19 17:46:20','2023-05-19 17:46:20',NULL,1), + (60, 'SPEU','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,2), + (60, 'VSPH','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,3), + (60, '4','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,4), + (60, '1500','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,5), + (60, '16','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,6), + (60, '160','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,7), + (60, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,8), + (60, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,9), + (60, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,10), + (60, '98','percentage','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,20), + (60, '10','millisecond','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,21), + (60, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,24), + (60, '175','euro','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,25); +INSERT INTO iecbackend.service_attribute_value (root_service_id, service_attribute_value,unit_value,check_list_value,created_date,last_modified_date,deleted_date,service_attribute_type_id) VALUES + (61, '00EU','','','2023-05-19 17:46:20','2023-05-19 17:46:20',NULL,1), + (61, 'SPEU','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,2), + (61, 'VSPH','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,3), + (61, '8','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,4), + (61, '1500','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,5), + (61, '16','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,6), + (61, '160','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,7), + (61, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,8), + (61, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,9), + (61, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,10), + (61, '98','percentage','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,20), + (61, '10','millisecond','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,21), + (61, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,24), + (61, '200','euro','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,25); +INSERT INTO iecbackend.service_attribute_value (root_service_id, service_attribute_value,unit_value,check_list_value,created_date,last_modified_date,deleted_date,service_attribute_type_id) VALUES + (62, '00EU','','','2023-05-19 17:46:20','2023-05-19 17:46:20',NULL,1), + (62, 'SPEU','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,2), + (62, 'VSPH','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,3), + (62, '8','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,4), + (62, '1500','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,5), + (62, '32','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,6), + (62, '320','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,7), + (62, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,8), + (62, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,9), + (62, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,10), + (62, '98','percentage','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,20), + (62, '10','millisecond','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,21), + (62, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,24), + (62, '225','euro','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,25); +INSERT INTO iecbackend.service_attribute_value (root_service_id, service_attribute_value,unit_value,check_list_value,created_date,last_modified_date,deleted_date,service_attribute_type_id) VALUES + (63, '00EU','','','2023-05-19 17:46:20','2023-05-19 17:46:20',NULL,1), + (63, 'SPEU','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,2), + (63, 'VSPH','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,3), + (63, '8','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,4), + (63, '1500','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,5), + (63, '64','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,6), + (63, '320','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,7), + (63, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,8), + (63, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,9), + (63, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,10), + (63, '98','percentage','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,20), + (63, '10','millisecond','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,21), + (63, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,24), + (63, '250','euro','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,25); +INSERT INTO iecbackend.service_attribute_value (root_service_id, service_attribute_value,unit_value,check_list_value,created_date,last_modified_date,deleted_date,service_attribute_type_id) VALUES + (64, '00EU','','','2023-05-19 17:46:20','2023-05-19 17:46:20',NULL,1), + (64, 'SPEU','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,2), + (64, 'IONO','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,3), + (64, '1','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,4), + (64, '1500','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,5), + (64, '1','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,6), + (64, '5','GB','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,7), + (64, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,8), + (64, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,9), + (64, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,10), + (64, '98','percentage','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,20), + (64, '10','millisecond','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,21), + (64, '','','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,24), + (64, '10','euro','','2020-04-01 17:46:20','2020-04-01 17:46:20',NULL,25); + + -- -------------------------------------------------- -- Service class: -- 1: Database @@ -925,7 +1110,7 @@ INSERT INTO iecbackend.service_class (service_class_name,created_date,last_modif ('Virtual Machine','2020-04-01 19:46:19','2020-04-01 19:46:19',NULL); -- -------------------------------------------------- --- Service class attributes (service_class_id, attribute_type_id) +-- Service_class vs attributes (service_class_id, attribute_type_id) -- Db/St/Vm 11-22/16-23/1-10 -- -------------------------------------------------- INSERT INTO iecbackend.service_class_attribute (weight,is_mandatory,created_date,last_modified_date,deleted_date,service_class_id,service_attribute_type_id) VALUES @@ -962,6 +1147,10 @@ INSERT INTO iecbackend.service_class_attribute (weight,is_mandatory,created_date (14,0,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL,3,25); +-- -------------------------------------------------- +-- Definition (code,value,ismainattribute,ischeckoption,service_attribute_type_id,---) +-- 00AS, Asia, , , 1-24 , +-- -------------------------------------------------- INSERT INTO iecbackend.definition (code,value,ismainattribute,ischeckoption,service_attribute_type_id,created_date,last_modified_date,deleted_date) VALUES -- 1: Region -- 2: Zone @@ -992,12 +1181,16 @@ INSERT INTO iecbackend.definition (code,value,ismainattribute,ischeckoption,serv INSERT INTO iecbackend.definition (code,value,ismainattribute,ischeckoption,service_attribute_type_id,created_date,last_modified_date,deleted_date) VALUES -- 3: Provider - ('AIME','AIMES',1,0,3,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), - ('AMAZ','Amazon',1,0,3,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), - ('ARSY','Arsys',1,0,3,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), - ('AZUR','Azure',1,0,3,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), - ('GOOG','Google',1,0,3,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), - ('OPEN','OpenStack',1,0,3,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), + ('AIME','aimes',1,0,3,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), + ('AMAZ','aws',1,0,3,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), + ('ARSY','arsys',1,0,3,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), + ('AZUR','azure',1,0,3,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), + ('GOOG','google',1,0,3,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), + ('OPEN','openstack',1,0,3,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), + ('VSPH','vsphere',1,0,3,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), + ('CLSI','cloudsigma',1,0,3,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), + ('IONO ','ionoscloud',1,0,3,'2023-05-17 19:46:19','2023-05-17 19:46:19',NULL), + -- 8: Optimized ('GEPU','General purpose',1,0,8,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), ('COOP','Compute optimized',1,0,8,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), @@ -1005,9 +1198,18 @@ INSERT INTO iecbackend.definition (code,value,ismainattribute,ischeckoption,serv ('MEOP','Memory optimized',1,0,8,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), ('SGOP','Storage optimized',1,0,8,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), ('HPCO','High performance compute',1,0,8,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), - ('IPV4','IPv4',1,0,9,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), - ('00RE','Relational',1,0,11,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL); +-- 9: Public IP + ('IPV4','IPv4',1,0,9,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL); + +-- 10:Underpinning Technology + INSERT INTO iecbackend.definition (code,value,ismainattribute,ischeckoption,service_attribute_type_id,created_date,last_modified_date,deleted_date) VALUES +-- 11: Database Type + ('00RE','Relational',1,0,11,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), + ('00NR','Non-relational',1,0,11,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL); + +INSERT INTO iecbackend.definition (code,value,ismainattribute,ischeckoption,service_attribute_type_id,created_date,last_modified_date,deleted_date) VALUES +-- 12: Database Technology ('AURE','Amazon Aurora',1,0,12,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), ('ARRE','Amazon RDS',1,0,12,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), ('MARE','MariaDB',1,0,12,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), @@ -1015,22 +1217,41 @@ INSERT INTO iecbackend.definition (code,value,ismainattribute,ischeckoption,serv ('MYRE','MySQL',1,0,12,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), ('ORRE','Oracle',1,0,12,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), ('PORE','PostgreSQL',1,0,12,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), - ('00NR','Non-relational',1,0,11,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), ('AMNR','Amazon DynamoDB',1,0,12,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), ('CANR','Apache Cassandra',1,0,12,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL); INSERT INTO iecbackend.definition (code,value,ismainattribute,ischeckoption,service_attribute_type_id,created_date,last_modified_date,deleted_date) VALUES ('MONR','MongoDB',1,0,12,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), + +-- 13: Data Transfer IN +-- 14: Data Transfer OUT +-- 15: Database Storage Capacity + +-- 16: Storage Type ('BACK','Backup',1,0,16,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), ('GENE','General',1,0,16,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), + +-- 17: Storage Subtype ('FILE','Files',1,0,17,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), ('OBJT','Objects',1,0,17,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), ('QUEU','Queues',1,0,17,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), ('BLOK','Block',1,0,17,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), + +-- 18: Capacity + +-- 19: Data Redundancy ('GEOS','Geo-redundant storage (GRS)',1,0,19,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), ('LOCS','Locally redundant storage (LRS)',1,0,19,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), ('REAS','Read-access geo-redundant storage (RA-GRS)',1,0,19,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL); INSERT INTO iecbackend.definition (code,value,ismainattribute,ischeckoption,service_attribute_type_id,created_date,last_modified_date,deleted_date) VALUES ('ZONS','Zone-redundant storage (ZRS)',1,0,19,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), + +-- 20: Availability +-- STORAGE --- +-- 21: Response time: VM Performance +-- 22: Transaction Unit (DTU): DB Performance +-- 23: Request - Response time: Storage Performance + +-- 24: Legal ('LEG1','tier1',1,0,24,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), ('LEG2','tier2',1,0,24,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), ('LEG3','tier3',1,0,24,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), @@ -1038,10 +1259,11 @@ INSERT INTO iecbackend.definition (code,value,ismainattribute,ischeckoption,serv ('CRT2','BSI C5 (Germany)',0,1,24,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), ('CRT3','PCI - DSS',0,1,24,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), ('CRT4','EU - Wide Certification Scheme (TBD)',0,1,24,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), - ('CRT5','Other',0,1,24,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL), - ('CLSI','CloudSigma',1,0,3,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL); + ('CRT5','Other',0,1,24,'2020-04-01 19:46:19','2020-04-01 19:46:19',NULL); -INSERT INTO `instance` (`id`,`created_date`,`deleted_date`,`email`,`instance_ip_url`,`deployment_id`,`instance_name`,`last_modified_date`,`service_id`) VALUES +-- 25: Cost + +INSERT INTO instance (`id`,`created_date`,`deleted_date`,`email`,`instance_ip_url`,`deployment_id`,`instance_name`,`last_modified_date`,`service_id`) VALUES (1, '2021-07-05 00:00:00',NULL,'testmail@tecnalia.com','168.0.1.10','deployment01','instanceTest',NULL,1); INSERT INTO `instance_incidence` (`id`, `detail`, `real_metric_value`, `instance_id`, `created_date`, `last_modified_date`, `deleted_date`) VALUES @@ -1049,21 +1271,20 @@ INSERT INTO `instance_incidence` (`id`, `detail`, `real_metric_value`, `instance (2, 'NFR Violation', NULL, 1, '2020-04-01 19:46:19', '2020-04-01 19:46:19', NULL), (3, 'Error in Region', NULL, 1, '2020-04-01 19:46:19', '2020-04-01 19:46:19', NULL); /*, - (4, 'NFR Violation', NULL, 9, '2020-04-01 19:46:19', '2020-04-01 19:46:19', NULL), - (5, 'NFR Violation', NULL, 6, '2020-04-01 19:46:19', '2020-04-01 19:46:19', NULL), - (6, 'NFR Violation', NULL, 7, '2020-04-01 19:46:19', '2020-04-01 19:46:19', NULL), - (7, 'NFR Violation', NULL, 6, '2020-04-01 19:46:19', '2020-04-01 19:46:19', NULL), (8, 'NFR Violation', NULL, 6, '2020-04-01 19:46:19', '2020-04-01 19:46:19', NULL), - (9, 'NFR Violation', NULL, 12, '2020-04-01 19:46:19', '2020-04-01 19:46:19', NULL), - (10,'NFR Violation', NULL, 15, '2020-04-01 19:46:19', '2020-04-01 19:46:19', NULL), - (11, 'NFR Violation', NULL, 19, '2020-04-01 19:46:19', '2020-04-01 19:46:19', NULL), - (12, 'NFR Violation', NULL, 20, '2020-04-01 19:46:19', '2020-04-01 19:46:19', NULL), - (13, 'Error in Region', NULL, 8, '2020-04-01 19:46:19', '2020-04-01 19:46:19', NULL), - (14, 'Error in Region', NULL, 7, '2020-04-01 19:46:19', '2020-04-01 19:46:19', NULL), - (15, 'Error in Region', NULL, 6, '2020-04-01 19:46:19', '2020-04-01 19:46:19', NULL), - (16, 'Error in Region', NULL, 5, '2020-04-01 19:46:19', '2020-04-01 19:46:19', NULL), - (17, 'Error in Region', NULL, 4, '2020-04-01 19:46:19', '2020-04-01 19:46:19', NULL), (18, 'Error in Region', NULL, 3, '2020-04-01 19:46:19', '2020-04-01 19:46:19', NULL);*/ +INSERT INTO `existing_resource` (`data_name`, `data_type`, `name`, `datacenter_id`, `user`, `provider`, `created_date`, `last_modified_date`, `deleted_date`) VALUES +('vsphere_datacenter', 'dc', 'MB', '', 'User A', 'Provider A', '2023-02-16 11:46:19', '2023-02-16 11:46:19', NULL), +('vsphere_compute_cluster', 'compute_cluster', 'MB-PIAC-NIC-1', '${data.vsphere_datacenter.dc.id}', 'User X', 'Provider X', '2023-02-16 11:46:19', '2023-02-16 11:46:19', NULL), +('vsphere_datastore', 'datastore', 'VNX01-0200-NIC-TA-PIAC-DRO-VMW-P', '${data.vsphere_datacenter.dc.id}', 'User X', 'Provider Y', '2023-02-16 11:46:19', '2023-02-16 11:46:19', NULL), +('vsphere_resource_pool', 'pool', 'PIAC', '${data.vsphere_datacenter.dc.id}', 'User Y', 'Provider X', '2023-02-16 11:46:19', '2023-02-16 11:46:19', NULL), +('vsphere_virtual_machine', 'template', 'Centos7_PIAC', '${data.vsphere_datacenter.dc.id}', 'User Y', 'Provider Y', '2023-02-16 11:46:19', '2023-02-16 11:46:19', NULL), +('vsphere_network', 'network', 'DRO-MB-P-BG001-2098', '${data.vsphere_datacenter.dc.id}', 'User B', 'Provider B', '2023-02-16 11:46:19', '2023-02-16 11:46:19', NULL); + +INSERT INTO `image` (`image_type`, `image_name`, `image_url`, `image_description`, `image_provider`, `created_date`, `last_modified_date`, `deleted_date`) VALUES +('Docker', NULL, 'docker.hub.io/Ericsson/tia:1.0', NULL, 'Provider A', '2023-02-16 11:46:19', '2023-02-16 11:46:19', NULL), +('VM', 'Ubuntu_6.4.2', NULL, 'VM file for Ubuntu 6.4.2', 'Provider B', '2023-02-16 11:46:19', '2023-02-16 11:46:19', NULL); + SET FOREIGN_KEY_CHECKS=1; COMMIT; \ No newline at end of file diff --git a/git/jhipster-registry/.env b/git/jhipster-registry/.env new file mode 100644 index 0000000..46e9247 --- /dev/null +++ b/git/jhipster-registry/.env @@ -0,0 +1,7 @@ +ADMIN_USER=admin +ADMIN_PASSWORD=jhipsterPassword +HTTPS_PORT=443 +SERVER_HOST=piacere.digital.tecnalia.dev +COMPOSE_PROJECT_NAME=jhipster-production +JHIPSTER_REGISTRY_CONFIG_PATH= +COMPOSE_FILE=docker-compose.yaml:docker-compose-volumes.yaml:docker-compose-dev.yaml:docker-compose-traefik-network-external.yaml diff --git a/git/jhipster-registry/.env.gen b/git/jhipster-registry/.env.gen new file mode 100644 index 0000000..f5c6a82 --- /dev/null +++ b/git/jhipster-registry/.env.gen @@ -0,0 +1,44 @@ +# Reference documentation https://docs.docker.com/compose/environment-variables/ +# Focus default variables as production, to allow direct download and run in production +# Required external variables that must be defined externally are those that have no value + +#### Common image related #### +DOCKER_REGISTRY_CACHE_PREFIX=cache.euve.digital.tecnalia.dev:5000 +DOCKER_REGISTRY_CACHE_VERSION=latest + +#### Common Build related #### +# DOCKER_BUILDKIT and COMPOSE_DOCKER_CLI_BUILD do not have effect here, we leave them as documentation +DOCKER_BUILDKIT=1 +COMPOSE_DOCKER_CLI_BUILD=1 + +#### Common Production related #### +ADMIN_USER=admin +ADMIN_PASSWORD=jhipsterPassword +HTTPS_PORT=443 +# server host is configured during the sync based on _ENV_RELEASE_ and _ENV_DEPLOY +# SERVER_HOST= +_ENV_DEPLOY_SERVER_HOST=piacere.digital.tecnalia.dev +_ENV_LOCAL_SERVER_HOST=192.168.56.1.nip.io + +#### Platform Specific #### +TZ=Madrid + +#### Common docker-compose related #### +# https://docs.docker.com/compose/reference/envvars/#compose_file#compose_project_name +# these are docker-compose related environment variables +COMPOSE_PROJECT_NAME=jhipster-production +# _ENV_LOCAL_COMPOSE_FILE_BASE= # These are oriented for local vagrant usually it contains local traefik configuration, dev services, etc +# _ENV_RELEASE_COMPOSE_FILE_BASE= # These are oriented for tagging relevant images for upload to official release repositories +# _ENV_DEPLOY_COMPOSE_FILE_BASE= # These are oriented for final deployment it contains production traefik configuration, etc +# _ENV_TEST_COMPOSE_FILE_BASE= # These are oriented for testing +# COMPOSE_FILE_BASE= # (MANDATORY) These are those main services of the project, that will apply to all the scenarios + +COMPOSE_FILE_BASE=docker-compose.yaml:docker-compose-volumes.yaml + +COMPOSE_FILE= +# COMPOSE_FILE Is generated automatically + +COMPOSE_FILE_BASE_LOCAL=docker-compose-dev.yaml +COMPOSE_FILE_BASE_NETWORK=docker-compose-traefik-network-external.yaml + +JHIPSTER_REGISTRY_CONFIG_PATH= diff --git a/git/jhipster-registry/.env.local b/git/jhipster-registry/.env.local new file mode 100644 index 0000000..de41d03 --- /dev/null +++ b/git/jhipster-registry/.env.local @@ -0,0 +1,35 @@ +# Reference documentation https://docs.docker.com/compose/environment-variables/ +# Focus default variables as production, to allow direct download and run in production +# Required external variables that must be defined externally are those that have no value + +#### Common image related #### + +#### Common Build related #### +# DOCKER_BUILDKIT and COMPOSE_DOCKER_CLI_BUILD do not have effect here, we leave them as documentation + +#### Common Production related #### +ADMIN_USER=admin +ADMIN_PASSWORD=jhipsterPassword +HTTPS_PORT=443 +# server host is configured during the sync based on _ENV_RELEASE_ and _ENV_DEPLOY +# SERVER_HOST= +SERVER_HOST=192.168.56.1.nip.io + +#### Platform Specific #### + +#### Common docker-compose related #### +# https://docs.docker.com/compose/reference/envvars/#compose_file#compose_project_name +# these are docker-compose related environment variables +COMPOSE_PROJECT_NAME=jhipster-production +# _ENV_LOCAL_COMPOSE_FILE_BASE= # These are oriented for local vagrant usually it contains local traefik configuration, dev services, etc +# _ENV_RELEASE_COMPOSE_FILE_BASE= # These are oriented for tagging relevant images for upload to official release repositories +# _ENV_DEPLOY_COMPOSE_FILE_BASE= # These are oriented for final deployment it contains production traefik configuration, etc +# _ENV_TEST_COMPOSE_FILE_BASE= # These are oriented for testing +# COMPOSE_FILE_BASE= # (MANDATORY) These are those main services of the project, that will apply to all the scenarios + + +# COMPOSE_FILE Is generated automatically + + +JHIPSTER_REGISTRY_CONFIG_PATH= +COMPOSE_FILE=docker-compose.yaml:docker-compose-volumes.yaml:docker-compose-dev.yaml:docker-compose-traefik-network-external.yaml diff --git a/git/jhipster-registry/.gitmodules b/git/jhipster-registry/.gitmodules new file mode 100644 index 0000000..e69de29 diff --git a/git/jhipster-registry/README.md b/git/jhipster-registry/README.md new file mode 100644 index 0000000..6abb59c --- /dev/null +++ b/git/jhipster-registry/README.md @@ -0,0 +1,31 @@ +# development-services + +This docker-compose file generalizes some services that we use in tecnalia to monitor and debug containers in integration servers. +* traefik dashboard +* traefik api +* portainer +* keycloak to provide sso access to services + +In future +* monitoring with telegraf +* monitoring db and render with infuxdb and grafana (this requires resources) + +## Use +This docker compose is not planned to be used alone but as a resource in another docker compose projects by extending DOCKER_FILE variable. + +```bash +export DOCKER_FILE=[...];path/docker-compose-tecnalia-selfsigned.yaml;path/docker-compose-dev.yaml +``` + +## Resources +Besides the docker-composes we also provide some additional resources: +* traefik examples using the official or our customized traefik + +## How to access +the entrypoints for the services will be in subdomains, asuming a base domain such as 192.168.56.1.nip.io: +* https://traefik.192.168.56.1.nip.io:8443/ to access traefik dashboard +* https://traefik.192.168.56.1.nip.io:8443/api/http/routers to access traefik api +* https://portainer.192.168.56.1.nip.io:8443/ to access portainer +* https://auth.192.168.56.1.nip.io:8443/ to access keycloak +* ... + diff --git a/central-config/jhipster/application.yml b/git/jhipster-registry/data/jhipster-registry/central-config/jhipster-registry/application.yml old mode 100755 new mode 100644 similarity index 100% rename from central-config/jhipster/application.yml rename to git/jhipster-registry/data/jhipster-registry/central-config/jhipster-registry/application.yml diff --git a/central-config/jhipster/registry.yml b/git/jhipster-registry/data/jhipster-registry/central-config/jhipster-registry/jhipster-registry.yml old mode 100755 new mode 100644 similarity index 93% rename from central-config/jhipster/registry.yml rename to git/jhipster-registry/data/jhipster-registry/central-config/jhipster-registry/jhipster-registry.yml index 795640e..3ba07ce --- a/central-config/jhipster/registry.yml +++ b/git/jhipster-registry/data/jhipster-registry/central-config/jhipster-registry/jhipster-registry.yml @@ -6,4 +6,4 @@ jhipster: allowed-headers: "*" exposed-headers: "Authorization,Link,X-Total-Count" allow-credentials: "true" - max-age: 1800 + max-age: 1800 diff --git a/git/jhipster-registry/docker-compose-dev-expose.yaml b/git/jhipster-registry/docker-compose-dev-expose.yaml new file mode 100644 index 0000000..1f2a4a3 --- /dev/null +++ b/git/jhipster-registry/docker-compose-dev-expose.yaml @@ -0,0 +1,4 @@ +services: + portainer: + ports: + - 8086:8086 diff --git a/docker-compose-dev.yaml b/git/jhipster-registry/docker-compose-dev.yaml old mode 100755 new mode 100644 similarity index 71% rename from docker-compose-dev.yaml rename to git/jhipster-registry/docker-compose-dev.yaml index 80b771b..4a73f39 --- a/docker-compose-dev.yaml +++ b/git/jhipster-registry/docker-compose-dev.yaml @@ -1,14 +1,10 @@ -version: '3.8' - services: - traefik: - networks: - default: - aliases: - - jhipster-registry.${SERVER_HOST} jhipster-registry: + networks: + traefik_network: labels: - "traefik.enable=true" + - "traefik.docker.network=traefik_network" - "traefik.http.routers.jhipster-registry.entrypoints=websecure" - "traefik.http.routers.jhipster-registry.rule=Host(`jhipster-registry.${SERVER_HOST:?err}`)" diff --git a/git/jhipster-registry/docker-compose-heathcheck-kill.yaml b/git/jhipster-registry/docker-compose-heathcheck-kill.yaml new file mode 100644 index 0000000..3f35e2c --- /dev/null +++ b/git/jhipster-registry/docker-compose-heathcheck-kill.yaml @@ -0,0 +1,10 @@ +# for some reason after a reboot the jhipster frezees and requires to be reboot +# this is not an elegant way to manage the issue +services: + jhipster-registry: + healthcheck: + test: curl -f --retry 6 --max-time 5 --retry-delay 10 --retry-max-time 60 "http://sh-gateway:8080/management/health" || bash -c 'kill -s 15 -1 && (sleep 10; kill -s 9 -1)' + interval: 5m #5m + timeout: 2s #2m + retries: 1 + start_period: 45s #45s diff --git a/git/jhipster-registry/docker-compose-oidc.yaml b/git/jhipster-registry/docker-compose-oidc.yaml new file mode 100644 index 0000000..5a9bc7f --- /dev/null +++ b/git/jhipster-registry/docker-compose-oidc.yaml @@ -0,0 +1,8 @@ +services: + + jhipster-registry: + environment: + SPRING_PROFILES_ACTIVE: prod,oauth2 + SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_OIDC_ISSUER_URI: ${KEYCLOAK_URL}/auth/realms/jhipster + SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_ID: jhipster-registry + SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_SECRET: jhipster-registry diff --git a/git/jhipster-registry/docker-compose-tecnalia-ca.yaml b/git/jhipster-registry/docker-compose-tecnalia-ca.yaml new file mode 100644 index 0000000..7fe22c9 --- /dev/null +++ b/git/jhipster-registry/docker-compose-tecnalia-ca.yaml @@ -0,0 +1,7 @@ +services: + + jhipster-registry: + command: + - /bin/sh + - -c + - ( [ -f /ca.pem ] || ( curl -s ${EXTRA_CA_URL:?err} --output /ca.pem && openssl x509 -in /ca.pem -text && keytool -import -noprompt -trustcacerts -alias ca -file /ca.pem -cacerts -storepass changeit ) ) && echo \"The JHipster Registry will start in $${JHIPSTER_SLEEP}s...\" && sleep $${JHIPSTER_SLEEP} && java $${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar /jhipster-registry.jar diff --git a/git/jhipster-registry/docker-compose-traefik-aliases.yaml b/git/jhipster-registry/docker-compose-traefik-aliases.yaml new file mode 100644 index 0000000..d16c4b4 --- /dev/null +++ b/git/jhipster-registry/docker-compose-traefik-aliases.yaml @@ -0,0 +1,6 @@ +services: + traefik: + networks: + traefik_network: + aliases: + - jhipster-registry.${SERVER_HOST} diff --git a/git/jhipster-registry/docker-compose-traefik-network-external.yaml b/git/jhipster-registry/docker-compose-traefik-network-external.yaml new file mode 100644 index 0000000..95623b3 --- /dev/null +++ b/git/jhipster-registry/docker-compose-traefik-network-external.yaml @@ -0,0 +1,4 @@ +networks: + traefik_network: + name: traefik_network + external: true diff --git a/git/jhipster-registry/docker-compose-volumes.yaml b/git/jhipster-registry/docker-compose-volumes.yaml new file mode 100644 index 0000000..d804916 --- /dev/null +++ b/git/jhipster-registry/docker-compose-volumes.yaml @@ -0,0 +1,4 @@ +services: + jhipster-registry: + volumes: + - ./${JHIPSTER_REGISTRY_CONFIG_PATH}data/jhipster-registry/central-config/jhipster-registry:/central-config/jhipster-registry diff --git a/docker-compose-jhipster-registry.yaml b/git/jhipster-registry/docker-compose.yaml old mode 100755 new mode 100644 similarity index 75% rename from docker-compose-jhipster-registry.yaml rename to git/jhipster-registry/docker-compose.yaml index 7a61bd3..8ca99df --- a/docker-compose-jhipster-registry.yaml +++ b/git/jhipster-registry/docker-compose.yaml @@ -1,19 +1,20 @@ -version: '3.8' - services: - jhipster-registry: - image: jhipster/jhipster-registry:v6.7.1 + image: jhipster/jhipster-registry:v6.8.0 restart: always environment: SPRING_CLOUD_CONFIG_SERVER_COMPOSITE_0_TYPE: native # usually LOCATION use to point to file:./central-config, but, looking forward to the possibility to use a unique jhipster-registry for all the project we use the label feature that allow us to contain multiple configurations organized in folders iec, sh, iop SPRING_CLOUD_CONFIG_SERVER_COMPOSITE_0_SEARCH_LOCATIONS: file:./central-config/{label} # if we migrate to a single jhipster-registry for all project we will need create a new folder global to hold the jhipster-registry configuration and assing global as LABEL - SPRING_CLOUD_CONFIG_LABEL: jhipster - SPRING_CLOUD_CONFIG_NAME: registry + SPRING_CLOUD_CONFIG_LABEL: jhipster-registry + SPRING_CLOUD_CONFIG_NAME: jhipster-registry GLOBAL_PASSWORD: ${ADMIN_PASSWORD} JHIPSTER_CORS_ALLOWEDORIGINS: "https://jhipster-registry.${SERVER_HOST:?err}:${HTTPS_PORT}" - volumes: - - ./central-config/jhipster:/central-config/jhipster - - ./central-config/iec:/central-config/iec + networks: + jhipster_network: + +networks: + jhipster_network: + name: jhipster_network + external: false diff --git a/piacere-build/docker-compose.yaml b/piacere-build/docker-compose.yaml new file mode 100644 index 0000000..ddc1c0b --- /dev/null +++ b/piacere-build/docker-compose.yaml @@ -0,0 +1,34 @@ +services: + iec-mysql: + build: + context: ${IEC_BASE_PATH}git/iec-mysql + dockerfile: Dockerfile + cache_from: + - ${IMAGE_IEC_MYSQL_CACHE:?err} + args: + BUILDKIT_INLINE_CACHE: 1 # For multistage docker + + # https://github.com/jfrog/artifactory-user-plugins/tree/master/cleanup/cleanDockerImages + + iec-backend: + build: + context: ${IEC_BASE_PATH}git/iec-backend + dockerfile: Dockerfile + cache_from: + - ${IMAGE_IEC_BACKEND_CACHE:?err} + args: + BUILDKIT_INLINE_CACHE: 1 # For multistage docker + + # https://github.com/jfrog/artifactory-user-plugins/tree/master/cleanup/cleanDockerImages + + iec-frontend: + build: + context: ${IEC_BASE_PATH}git/iec-frontend + dockerfile: Dockerfile + cache_from: + - ${IMAGE_IEC_FRONTEND_CACHE:?err} + args: + BUILDKIT_INLINE_CACHE: 1 # For multistage docker + + # https://github.com/jfrog/artifactory-user-plugins/tree/master/cleanup/cleanDockerImages + diff --git a/release/docker-compose.yaml b/release/docker-compose.yaml new file mode 100644 index 0000000..3af1f85 --- /dev/null +++ b/release/docker-compose.yaml @@ -0,0 +1,9 @@ +services: + iec-mysql: + image: ${IMAGE_IEC_MYSQL:?err} + + iec-backend: + image: ${IMAGE_IEC_BACKEND:?err} + + iec-frontend: + image: ${IMAGE_IEC_FRONTEND:?err} -- GitLab