diff --git a/.forgejo/workflows/ci-settings.xml b/.forgejo/workflows/ci-settings.xml deleted file mode 100644 index c206c4b..0000000 --- a/.forgejo/workflows/ci-settings.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - nexus - * - http://repo.oguerreiro.com/repository/maven-public/ - - - - - - nexus - default - default#123! - - - maven-releases - default - default#123! - - - maven-snapshots - default - default#123! - - - diff --git a/.forgejo/workflows/release.yml b/.forgejo/workflows/release.yml index 7b8d83e..bf4c7d3 100644 --- a/.forgejo/workflows/release.yml +++ b/.forgejo/workflows/release.yml @@ -14,7 +14,7 @@ jobs: - name: Install system dependencies run: | apt-get update - apt-get install -y nodejs npm openjdk-17-jdk maven git jq + apt-get install -y nodejs npm openjdk-17-jdk maven git export JAVA_HOME=$(dirname $(dirname $(readlink -f $(which javac)))) echo "JAVA_HOME=$JAVA_HOME" >> $GITHUB_ENV @@ -22,7 +22,6 @@ jobs: run: | java -version mvn -v - mvn help:evaluate -Dexpression=settings.localRepository -q -DforceStdout node -v npm -v @@ -53,106 +52,6 @@ jobs: git commit -am "Release ${{ steps.version.outputs.release_version }}" git push - # Create the release notes (closed issues) - # Must be here, before the new tag, to get closed issued from the LAST TAG to NOW - - name: Generate release notes from closed issues - id: generate_notes - run: | - REPO_OWNER="root" - REPO_NAME="resilient" - TOKEN="${{ secrets.FORGEJO_TOKEN }}" - VERSION="${{ steps.version.outputs.release_version }}" - API_BASE="https://git.oguerreiro.com/api/v1" - - # Step 1. Get the latest tag - echo "Step 1 : Fetching latest release tag..." - LATEST_TAG=$(curl -H "Authorization: token $TOKEN" \ - "$API_BASE/repos/$REPO_OWNER/$REPO_NAME/tags" \ - | jq -r '.[0].name') - - if [[ -z "$LATEST_TAG" || "$LATEST_TAG" == "null" ]]; then - # Doesn't have tag. Its the first release - echo "No previous tags found. Assuming first release." - CLOSED_ISSUES="" - else - # Tag found - echo "Latest tag is: $LATEST_TAG" - - # Step 2: Get the tag ref object - echo "Step 2 : Fetch tag ref object from tag = $LATEST_TAG" - TAG_REF=$(curl -H "Authorization: token $TOKEN" \ - "$API_BASE/repos/$REPO_OWNER/$REPO_NAME/git/refs/tags/$LATEST_TAG") - echo "... TAG_REF is: $TAG_REF" - - # Extract the first .object.sha (if it's an array) or directly if it's an object - if echo "$TAG_REF" | jq -e 'type == "array"' >/dev/null; then - echo "... is an array" - TAG_OBJECT_SHA=$(echo "$TAG_REF" | jq -r '.[0].object.sha') - TAG_OBJECT_TYPE=$(echo "$TAG_REF" | jq -r '.[0].object.type') - else - echo "... is an object" - TAG_OBJECT_SHA=$(echo "$TAG_REF" | jq -r '.object.sha') - TAG_OBJECT_TYPE=$(echo "$TAG_REF" | jq -r '.object.type') - fi - - echo "... TAG SHA is (1): $TAG_OBJECT_SHA" - echo "... TAG TYPE is (1): $TAG_OBJECT_TYPE" - - # Resolve annotated tag to commit SHA - while [ "$TAG_OBJECT_TYPE" != "commit" ]; do - echo "..." - echo "... TAG OBJECT is not of type commit. Try : $API_BASE/repos/$REPO_OWNER/$REPO_NAME/git/$TAG_OBJECT_TYPE/$TAG_OBJECT_SHA" - TAG_OBJECT=$(curl -H "Authorization: token $TOKEN" \ - "$API_BASE/repos/$REPO_OWNER/$REPO_NAME/git/tags/$TAG_OBJECT_SHA") - - if echo "$TAG_OBJECT" | jq -e 'type == "array"' >/dev/null; then - echo "... ... is an array" - TAG_OBJECT_SHA=$(echo "$v" | jq -r '.[0].object.sha') - TAG_OBJECT_TYPE=$(echo "$TAG_OBJECT" | jq -r '.[0].object.type') - else - echo "... ... is an object" - TAG_OBJECT_SHA=$(echo "$TAG_OBJECT" | jq -r '.object.sha') - TAG_OBJECT_TYPE=$(echo "$TAG_OBJECT" | jq -r '.object.type') - fi - - echo "... TAG_OBJECT_SHA is (2): $TAG_OBJECT_SHA" - echo "... TAG_OBJECT_TYPE is (2): $TAG_OBJECT_TYPE" - done - - echo "... commit found with SHA $TAG_OBJECT_SHA" - COMMIT_SHA=$TAG_OBJECT_SHA - - # Step 3: Get the commit date - echo "Step 3 : Get the commit date from commit = $COMMIT_SHA" - COMMIT_DATE=$(curl -H "Authorization: token $TOKEN" \ - "$API_BASE/repos/$REPO_OWNER/$REPO_NAME/git/commits/$COMMIT_SHA" \ - | jq -r '.commit.committer.date') - echo "... Fetching closed issues since $COMMIT_DATE..." - - CLOSED_ISSUES_JSON=$(curl -H "Authorization: token $TOKEN" \ - "$API_BASE/repos/$REPO_OWNER/$REPO_NAME/issues?state=closed&since=$COMMIT_DATE") - - if [[ -z "$CLOSED_ISSUES_JSON" ]]; then - echo "Warning: No closed issues or invalid response." - CLOSED_ISSUES="" - else - CLOSED_ISSUES=$(echo "$CLOSED_ISSUES_JSON" | jq -r '.[] | "- [#\(.number)](\(.html_url)) \(.title)"') - fi - fi - - # Build release notes markdown - { - echo "## Release v$VERSION" - echo - if [[ -n "$CLOSED_ISSUES" ]]; then - echo "### Closed Issues" - echo "$CLOSED_ISSUES" - else - echo "No issues closed since last release." - fi - } > release-notes.md - cat release-notes.md - - name: Tag release run: | git tag -a v${{ steps.version.outputs.release_version }} -m "Release ${{ steps.version.outputs.release_version }}" @@ -162,42 +61,45 @@ jobs: # Install @Angular dependencies - name: Install frontend dependencies - if: false # DISABLED for testing. To check if backend build is also doing frontend. run: | cd src/main/webapp npm ci + # Setup node_modules cache, for better performance + - name: Cache node_modules + uses: actions/cache@v3 + with: + path: | + **/node_modules + key: node-modules-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + node-modules- + # Build the frontend - name: Build frontend - if: false # DISABLED for testing. To check if backend build is also doing frontend. run: | cd src/main/webapp npm run build - - # Build the backend (JAR). NOTE: the -Dmaven.download.parallel=false will force MAVEN to have a single connection for downloads, without this I can get "Connection reset" + + # Setup Maven cache, for better performance + - name: Cache Maven dependencies + uses: actions/cache@v3 + with: + path: ~/.m2/repository + key: maven-${{ runner.os }}-${{ hashFiles('**/pom.xml') }} + restore-keys: | + maven-${{ runner.os }}- + + # Build the backend (JAR) - name: Build backend (Spring Boot) run: | - echo "DEBUG Outputs ************************* " - echo "Container hostname: $(hostname)" - echo "Runner working dir: $PWD" - echo "Runner user: $(whoami)" - echo "Listing contents of ~/.m2/repository:" - ls -lhR ~/.m2/repository | head -n 100 || echo "No .m2/repository found" - echo "Disk usage:" - du -sh ~/.m2/repository || echo "No .m2 directory found" - echo " " - echo "BUILD Outputs ************************* " - mvn clean package -Pprod -DskipTests -Dmaven.download.parallel=false -Dmaven.repo.local=/root/.m2/repository -s .forgejo/workflows/ci-settings.xml - container: - image: maven:3.9-eclipse-temurin-17 - volumes: - - docker-forgejo_maven-cache:/root/.m2 - + mvn clean package -Pprod -DskipTests + # Log output - name: List output files run: | ls -lh target/*.jar || true - + # save artifacts - name: Upload backend JAR uses: actions/upload-artifact@v3 @@ -205,38 +107,6 @@ jobs: name: app-backend path: target/resilient*.jar - # Create the release - # NOTE: added system dependency install "jq" - - name: Create release and upload JAR - run: | - VERSION=${{ steps.version.outputs.release_version }} - API="https://git.oguerreiro.com/api/v1" - REPO="root/resilient" - - # Create release - RESPONSE=$(curl -X POST "$API/repos/$REPO/releases" \ - -H "Authorization: token ${{ secrets.FORGEJO_TOKEN }}" \ - -H "Content-Type: application/json" \ - -d "{ - \"tag_name\": \"v$VERSION\", - \"target_commitish\": \"master\", - \"name\": \"Release v$VERSION\", - \"body\": $(jq -Rs < release-notes.md) - }") - - RELEASE_ID=$(echo "$RESPONSE" | jq -r '.id') - echo "Created release ID: $RELEASE_ID" - - # Upload artifact - # NOTE: For safety, the artifact to upload is expected to be the EXACT $VERSION of this branch. If not, something is wrong. - JAR_FILE=$(ls target/resilient-$VERSION.jar | head -n 1) - echo "Attaching file : $JAR_FILE" - curl -X POST "$API/repos/$REPO/releases/$RELEASE_ID/assets?name=resilient-$VERSION.jar" \ - -H "Authorization: token ${{ secrets.FORGEJO_TOKEN }}" \ - -H "Content-Type: application/java-archive" \ - --data-binary @"$JAR_FILE" - - # ################################################################## # ## THIS IS A RELEASE - Change master version to next SNAPSHOT ## # ## #4. Checkout master ## diff --git a/pom.xml b/pom.xml index 57fcf51..b85f1fd 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.oguerreiro.resilient resilient - 1.0.8-SNAPSHOT + 1.0.2 jar Resilient Description for Resilient diff --git a/src/main/java/com/oguerreiro/resilient/config/SecurityConfiguration.java b/src/main/java/com/oguerreiro/resilient/config/SecurityConfiguration.java index eb2f037..ce677fb 100644 --- a/src/main/java/com/oguerreiro/resilient/config/SecurityConfiguration.java +++ b/src/main/java/com/oguerreiro/resilient/config/SecurityConfiguration.java @@ -219,7 +219,6 @@ public class SecurityConfiguration { .requestMatchers(mvc.pattern("/api/account/reset-password/init")).permitAll() .requestMatchers(mvc.pattern("/api/account/reset-password/finish")).permitAll() .requestMatchers(mvc.pattern("/api/account/saml2-endpoint")).permitAll() - .requestMatchers(mvc.pattern("/api/account/has-basic-auth")).permitAll() .requestMatchers(mvc.pattern("/api/home/page")).permitAll() .requestMatchers(mvc.pattern("/api/admin/**")).hasAuthority(AuthoritiesConstants.ADMIN) .requestMatchers(mvc.pattern("/api/**")).authenticated() diff --git a/src/main/java/com/oguerreiro/resilient/repository/OrganizationRepository.java b/src/main/java/com/oguerreiro/resilient/repository/OrganizationRepository.java index 5aef3a7..8ba65ab 100644 --- a/src/main/java/com/oguerreiro/resilient/repository/OrganizationRepository.java +++ b/src/main/java/com/oguerreiro/resilient/repository/OrganizationRepository.java @@ -5,7 +5,6 @@ import java.util.Optional; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @@ -39,13 +38,11 @@ public interface OrganizationRepository extends ResilientJpaRepository findOneByUser(User user); @Query("select organization from Organization organization where organization.outputInventory = true and organization.organizationType.nature = com.oguerreiro.resilient.domain.enumeration.OrganizationNature.ORGANIZATION order by (CASE WHEN organization.parent IS NULL THEN 0 ELSE 1 END), (CASE WHEN organization.sort IS NULL THEN 1 ELSE 0 END), organization.sort asc") List findAllOrganizationForOutput(); - @EntityGraph(attributePaths = "parent") Optional findOneByCode(String code); @Query(""" diff --git a/src/main/java/com/oguerreiro/resilient/security/basic/ResilientBasicProperties.java b/src/main/java/com/oguerreiro/resilient/security/basic/ResilientBasicProperties.java deleted file mode 100644 index d279cb7..0000000 --- a/src/main/java/com/oguerreiro/resilient/security/basic/ResilientBasicProperties.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.oguerreiro.resilient.security.basic; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.stereotype.Component; - -@Component -@ConfigurationProperties(prefix = "resilient.security.basic") -public class ResilientBasicProperties { - - private boolean enabled; - - // Root-level Getters/Setters - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - -} diff --git a/src/main/java/com/oguerreiro/resilient/security/saml2/Saml2AuthenticationHandler.java b/src/main/java/com/oguerreiro/resilient/security/saml2/Saml2AuthenticationHandler.java index 1da77e8..3d2b3db 100644 --- a/src/main/java/com/oguerreiro/resilient/security/saml2/Saml2AuthenticationHandler.java +++ b/src/main/java/com/oguerreiro/resilient/security/saml2/Saml2AuthenticationHandler.java @@ -82,7 +82,7 @@ public class Saml2AuthenticationHandler implements AuthenticationSuccessHandler, return; } - User user = userRepository.findOneWithAuthoritiesByLogin(username).orElse(null); + User user = userRepository.findOneByLogin(username).orElse(null); if (user != null) { // This user can login with SAML2 ? if (!user.getAllowSamlAuthentication()) { @@ -155,20 +155,26 @@ public class Saml2AuthenticationHandler implements AuthenticationSuccessHandler, } // Create a ResilientUserDetails and replace Principal - Organization parentOrganization = userOrganization.getParent(); ResilientUserDetails userdetails = new ResilientUserDetails(username, "MOCK-PWD", authorities, securityGroup, - userOrganization.getParent(), "pt-PT"); + userOrganization, "pt-PT"); Saml2Authentication newAuthentication = new Saml2Authentication(userdetails, samlXMLResponse, - userdetails.getAuthorities()); + authentication.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(newAuthentication); - // Send to success URL, if configured - String successUrl = resilientSaml2Properties.getSuccessUrl(); - if (successUrl != null && !successUrl.isBlank()) { - // This is mandatory in DEV environment. Optional in PROD because the app url is the same. - // Even so, I think its a good practice to define the success url - response.sendRedirect(successUrl); + // This is a sugar-code when in development environment. + if (isDevProfileActive()) { + // If this is a mock-idp, it can provide the parameter 'SAMLDevEnvironmentUrl' + // that gives the base URL to use. This is because in DEV mode usually the + // Angular side runs in localhost:42000 but server-side is in localhost:8080. + // Without this, SAMLv2 authentication would end up in error redirecting the user to + // localhost:8080 (NOT the client-side) + // In PROD we don't need this, because the app url is the same + String successUrl = resilientSaml2Properties.getSuccessUrl(); + + if (successUrl != null && !successUrl.isBlank()) { + response.sendRedirect(successUrl); + } } } diff --git a/src/main/java/com/oguerreiro/resilient/service/DashboardComponentService.java b/src/main/java/com/oguerreiro/resilient/service/DashboardComponentService.java index 8eeb794..3e812a2 100644 --- a/src/main/java/com/oguerreiro/resilient/service/DashboardComponentService.java +++ b/src/main/java/com/oguerreiro/resilient/service/DashboardComponentService.java @@ -33,8 +33,6 @@ import com.oguerreiro.resilient.domain.enumeration.DashboardComponentView; import com.oguerreiro.resilient.repository.DashboardComponentRepository; import com.oguerreiro.resilient.repository.OrganizationRepository; import com.oguerreiro.resilient.service.dto.DashboardComponentDTO; -import com.oguerreiro.resilient.service.dto.DashboardComponentDetailValueDTO; -import com.oguerreiro.resilient.service.mapper.DashboardComponentDetailValueMapper; import com.oguerreiro.resilient.service.mapper.DashboardComponentMapper; /** @@ -47,25 +45,13 @@ public class DashboardComponentService private OrganizationRepository organizationRepository; private DashboardComponentMapper dashboardComponentMapper; - private final DashboardComponentDetailValueMapper dashboardComponentDetailValueMapper; public DashboardComponentService(DashboardComponentRepository dashboardComponentRepository, - DashboardComponentMapper dashboardComponentMapper, OrganizationRepository organizationRepository, - DashboardComponentDetailValueMapper dashboardComponentDetailValueMapper) { + DashboardComponentMapper dashboardComponentMapper, OrganizationRepository organizationRepository) { super(DashboardComponent.class, dashboardComponentRepository, dashboardComponentMapper); this.organizationRepository = organizationRepository; this.dashboardComponentMapper = dashboardComponentMapper; - this.dashboardComponentDetailValueMapper = dashboardComponentDetailValueMapper; - } - - public Map> buildDashboardComponentViewDTO(Long organizationId, - Long dashboardComponentId, Long periodVersionId) { - - Map> mapValues = buildDashboardComponentView(organizationId, - dashboardComponentId, periodVersionId); - - return this.dashboardComponentDetailValueMapper.mapToDto(mapValues); } /* diff --git a/src/main/java/com/oguerreiro/resilient/service/UserService.java b/src/main/java/com/oguerreiro/resilient/service/UserService.java index ad31be1..c2f26b8 100644 --- a/src/main/java/com/oguerreiro/resilient/service/UserService.java +++ b/src/main/java/com/oguerreiro/resilient/service/UserService.java @@ -151,7 +151,6 @@ public class UserService { } public User createUser(AdminUserDTO userDTO) { - User user = new User(); user.setLogin(userDTO.getLogin().toLowerCase()); user.setFirstName(userDTO.getFirstName()); @@ -170,8 +169,6 @@ public class UserService { user.setResetKey(RandomUtil.generateResetKey()); user.setResetDate(Instant.now()); user.setActivated(true); - user.setAllowSamlAuthentication(userDTO.isAllowSamlAuthentication()); - user.setAllowUserPwdAuthentication(userDTO.isAllowUserPwdAuthentication()); if (userDTO.getAuthorities() != null) { Set authorities = userDTO.getAuthorities().stream().map(authorityRepository::findById).filter( Optional::isPresent).map(Optional::get).collect(Collectors.toSet()); diff --git a/src/main/java/com/oguerreiro/resilient/web/rest/AccountResource.java b/src/main/java/com/oguerreiro/resilient/web/rest/AccountResource.java index 3aab272..d4eb475 100644 --- a/src/main/java/com/oguerreiro/resilient/web/rest/AccountResource.java +++ b/src/main/java/com/oguerreiro/resilient/web/rest/AccountResource.java @@ -31,7 +31,6 @@ import com.oguerreiro.resilient.domain.User; import com.oguerreiro.resilient.repository.PersistentTokenRepository; import com.oguerreiro.resilient.repository.UserRepository; import com.oguerreiro.resilient.security.SecurityUtils; -import com.oguerreiro.resilient.security.basic.ResilientBasicProperties; import com.oguerreiro.resilient.security.custom.ResilientUserDetails; import com.oguerreiro.resilient.service.MailService; import com.oguerreiro.resilient.service.UserService; @@ -72,18 +71,14 @@ public class AccountResource { private final RelyingPartyRegistrationRepository registrationRepository; - private ResilientBasicProperties resilientBasicProperties; - public AccountResource(UserRepository userRepository, UserService userService, MailService mailService, PersistentTokenRepository persistentTokenRepository, - @Autowired(required = false) RelyingPartyRegistrationRepository registrationRepository, - ResilientBasicProperties resilientBasicProperties) { + @Autowired(required = false) RelyingPartyRegistrationRepository registrationRepository) { this.userRepository = userRepository; this.userService = userService; this.mailService = mailService; this.persistentTokenRepository = persistentTokenRepository; this.registrationRepository = registrationRepository; - this.resilientBasicProperties = resilientBasicProperties; } /** @@ -197,10 +192,6 @@ public class AccountResource { */ @PostMapping(path = "/account/change-password") public void changePassword(@RequestBody PasswordChangeDTO passwordChangeDto) { - if (!this.isBasicAuthActive()) { - throw new AccountResourceException("Invalid or not allowed request"); - } - if (isPasswordLengthInvalid(passwordChangeDto.getNewPassword())) { throw new InvalidPasswordException(); } @@ -253,10 +244,6 @@ public class AccountResource { */ @PostMapping(path = "/account/reset-password/init") public void requestPasswordReset(@RequestBody String mail) { - if (!this.isBasicAuthActive()) { - throw new AccountResourceException("Invalid or not allowed request"); - } - Optional user = userService.requestPasswordReset(mail); if (user.isPresent()) { mailService.sendPasswordResetMail(user.orElseThrow()); @@ -276,10 +263,6 @@ public class AccountResource { */ @PostMapping(path = "/account/reset-password/finish") public void finishPasswordReset(@RequestBody KeyAndPasswordVM keyAndPassword) { - if (!this.isBasicAuthActive()) { - throw new AccountResourceException("Invalid or not allowed request"); - } - if (isPasswordLengthInvalid(keyAndPassword.getNewPassword())) { throw new InvalidPasswordException(); } @@ -311,19 +294,6 @@ public class AccountResource { return ids.get(0); } - @GetMapping(path = "/account/has-basic-auth") - public Boolean hasBasicAuthentication() { - return this.isBasicAuthActive(); - } - - private boolean isBasicAuthActive() { - if (this.resilientBasicProperties != null && this.resilientBasicProperties.isEnabled()) { - return this.resilientBasicProperties.isEnabled(); - } - - return Boolean.FALSE; - } - private static boolean isPasswordLengthInvalid(String password) { return (StringUtils.isEmpty(password) || password.length() < ManagedUserVM.PASSWORD_MIN_LENGTH || password.length() > ManagedUserVM.PASSWORD_MAX_LENGTH); diff --git a/src/main/java/com/oguerreiro/resilient/web/rest/DashboardComponentResource.java b/src/main/java/com/oguerreiro/resilient/web/rest/DashboardComponentResource.java index 2d98ef6..1724b5b 100644 --- a/src/main/java/com/oguerreiro/resilient/web/rest/DashboardComponentResource.java +++ b/src/main/java/com/oguerreiro/resilient/web/rest/DashboardComponentResource.java @@ -15,11 +15,13 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.oguerreiro.resilient.domain.DashboardComponent; +import com.oguerreiro.resilient.domain.DashboardComponentDetailValue; import com.oguerreiro.resilient.domain.enumeration.DashboardComponentView; import com.oguerreiro.resilient.repository.DashboardComponentRepository; import com.oguerreiro.resilient.service.DashboardComponentService; import com.oguerreiro.resilient.service.dto.DashboardComponentDTO; import com.oguerreiro.resilient.service.dto.DashboardComponentDetailValueDTO; +import com.oguerreiro.resilient.service.mapper.DashboardComponentDetailValueMapper; /** * REST controller for managing {@link com.oguerreiro.resilient.domain.UnitType}. @@ -30,11 +32,14 @@ public class DashboardComponentResource extends AbstractResilientResource { private static final String ENTITY_NAME = "dashboardComponent"; + private final DashboardComponentDetailValueMapper dashboardComponentDetailValueMapper; private final DashboardComponentService dashboardComponentService; public DashboardComponentResource(DashboardComponentRepository dashboardComponentRepository, - DashboardComponentService dashboardComponentService) { + DashboardComponentService dashboardComponentService, + DashboardComponentDetailValueMapper dashboardComponentDetailValueMapper) { super(DashboardComponent.class, dashboardComponentRepository, dashboardComponentService); + this.dashboardComponentDetailValueMapper = dashboardComponentDetailValueMapper; this.dashboardComponentService = dashboardComponentService; } @@ -62,10 +67,10 @@ public class DashboardComponentResource Optional dashboardComponentDTO = getDashboardComponentService().findOne( dashboardComponentId); - Map> values = getDashboardComponentService().buildDashboardComponentViewDTO( + Map> values = getDashboardComponentService().buildDashboardComponentView( null, dashboardComponentId, periodVersionId); - return values; + return this.dashboardComponentDetailValueMapper.mapToDto(values); } @GetMapping("/build/{organizationId}/{dashboardComponentId}/{periodVersionId}") @@ -77,10 +82,10 @@ public class DashboardComponentResource Optional dashboardComponentDTO = getDashboardComponentService().findOne( dashboardComponentId); - Map> values = getDashboardComponentService().buildDashboardComponentViewDTO( + Map> values = getDashboardComponentService().buildDashboardComponentView( organizationId, dashboardComponentId, periodVersionId); - return values; + return this.dashboardComponentDetailValueMapper.mapToDto(values); } @GetMapping("/active") diff --git a/src/main/resources/config/application-dev.yml b/src/main/resources/config/application-dev.yml index ecd98aa..0108b50 100644 --- a/src/main/resources/config/application-dev.yml +++ b/src/main/resources/config/application-dev.yml @@ -23,8 +23,6 @@ logging: org.opensaml: DEBUG org.springframework.security.saml2: DEBUG org.springframework.security: DEBUG - org.hibernate.proxy: TRACE - org.hibernate.bytecode: TRACE spring: jpa: @@ -146,11 +144,9 @@ resilient: enabled: false port: 8081 mock-idp: - enabled: true + enabled: false path: classpath:mock-idp/idp.js security: - basic: # ADDED to config the formLogin (user+password). This allows for the DISABLE of basic authentication - enabled: true saml2: # ADDED to support SAMLv2 authentication to IDP. # Metadata endpoint ${base-url}/saml2/service-provider-metadata/mock-idp enabled: true @@ -176,9 +172,9 @@ resilient: name: name # the user display name [OPTIONAL] username: urn:mace:dir:attribute-def:mail # the username, typically for authentication. Fallsback to email. [MANDATORY] email: email # the user email [MANDATORY] - organization-code: # organization unit code [OPTIONAL]. Eg. "organization_code" - security-group-code: # security group code [OPTIONAL]. Eg. "security_group" - role: # a single role is expected [OPTIONAL]. Eg. "roles" + organization-code: organization_code # organization unit code [OPTIONAL] + security-group-code: security_group # security group code [OPTIONAL] + role: roles # a single role is expected [OPTIONAL] defaults: # For some attributes defaults can be given. This will be used if SAML2 response doesn't have them organization-code: NOVA # default organization unit code security-group-code: GRP_USER # default security group code diff --git a/src/main/resources/config/application-prod.yml b/src/main/resources/config/application-prod.yml index f0650bf..3695f21 100644 --- a/src/main/resources/config/application-prod.yml +++ b/src/main/resources/config/application-prod.yml @@ -18,9 +18,7 @@ logging: ROOT: INFO tech.jhipster: INFO com.oguerreiro.resilient: INFO - org.hibernate.proxy: TRACE - org.hibernate.bytecode: TRACE - + management: prometheus: metrics: @@ -35,9 +33,9 @@ spring: enabled: false datasource: type: com.zaxxer.hikari.HikariDataSource - url: jdbc:mysql://localhost:3306/resilient_resilient?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true + url: jdbc:mysql://localhost:3306/resilient?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true username: root - password: root + password: hikari: poolName: Hikari auto-commit: false diff --git a/src/main/webapp/app/core/auth/account.service.ts b/src/main/webapp/app/core/auth/account.service.ts index e3fcc06..522a3e9 100644 --- a/src/main/webapp/app/core/auth/account.service.ts +++ b/src/main/webapp/app/core/auth/account.service.ts @@ -3,7 +3,7 @@ import { Router } from '@angular/router'; import { HttpClient } from '@angular/common/http'; import { TranslateService } from '@ngx-translate/core'; import { Observable, ReplaySubject, of } from 'rxjs'; -import { shareReplay, tap, catchError, map } from 'rxjs/operators'; +import { shareReplay, tap, catchError } from 'rxjs/operators'; import { StateStorageService } from 'app/core/auth/state-storage.service'; import { Account } from 'app/core/auth/account.model'; @@ -95,14 +95,6 @@ export class AccountService { return this.http.get(this.applicationConfigService.getEndpointFor('api/account/saml2-endpoint'), { responseType: 'text' as 'text' }); } - hasBasicAuth(): Observable { - return this.http.get( - this.applicationConfigService.getEndpointFor('api/account/has-basic-auth'), { responseType: 'text' as 'text' } - ).pipe( - map(response => response === 'true') - );; - } - private fetch(): Observable { return this.http.get(this.applicationConfigService.getEndpointFor('api/account')); } diff --git a/src/main/webapp/app/entities/dashboard-component/factory/widgets/dashboard-component-accordion-table.component.ts b/src/main/webapp/app/entities/dashboard-component/factory/widgets/dashboard-component-accordion-table.component.ts index d7b0983..0083c5c 100644 --- a/src/main/webapp/app/entities/dashboard-component/factory/widgets/dashboard-component-accordion-table.component.ts +++ b/src/main/webapp/app/entities/dashboard-component/factory/widgets/dashboard-component-accordion-table.component.ts @@ -91,12 +91,12 @@ export class DashboardComponentAccordionTable implements OnInit { } } }); - - // Get the currently selected ORGANIZATION AND listen to changes in PeriodSelector + + // Listen to changes in PeriodSelector this.subscriptionPeriod = this .envService .selectedPeriod - /* .pipe( skip(1)) // Ignore's the current value. If you want to react ONLY to changes */ + .pipe( skip(1)) // Ignore the current value. Just want to react to changes .subscribe(period => { if(period){ // Calculate the latest periodVersionId @@ -105,10 +105,9 @@ export class DashboardComponentAccordionTable implements OnInit { .subscribe({ next: (version: HttpResponse) => { if (version.body) { - this.periodVersion = version.body; - this.periodVersionId = this.periodVersion.id; + const periodVersion = version.body; + this.periodVersionId = periodVersion.id; } else { - this.periodVersion = null; this.periodVersionId = null; } diff --git a/src/main/webapp/app/entities/dashboard/dashboard.routes.ts b/src/main/webapp/app/entities/dashboard/dashboard.routes.ts index 493e2f1..676c2f0 100644 --- a/src/main/webapp/app/entities/dashboard/dashboard.routes.ts +++ b/src/main/webapp/app/entities/dashboard/dashboard.routes.ts @@ -6,14 +6,6 @@ import { DashboardPreviewComponent } from './preview/dashboard-preview.component // import DashboardResolve from './route/dashboard-routing-resolve.service'; const dashboardRoute: Routes = [ - { - path: ':view', - component: DashboardPreviewComponent, - canActivate: [UserRouteAccessService], - data: { - authorities: ['ROLE_ADMIN', 'ROLE_MANAGER', 'ROLE_COORDINATOR', 'ROLE_USER'], - }, - }, { path: ':view/:period', component: DashboardPreviewComponent, diff --git a/src/main/webapp/app/entities/dashboard/preview/dashboard-preview.component.ts b/src/main/webapp/app/entities/dashboard/preview/dashboard-preview.component.ts index 95de022..56f9353 100644 --- a/src/main/webapp/app/entities/dashboard/preview/dashboard-preview.component.ts +++ b/src/main/webapp/app/entities/dashboard/preview/dashboard-preview.component.ts @@ -23,9 +23,10 @@ export class DashboardPreviewComponent implements OnInit, AfterViewInit { @ViewChild('dashboardContainer', { read: ViewContainerRef }) container!: ViewContainerRef; dashboardComponents?: IDashboardComponent[]; + periodsSharedCollection: IPeriod[] = []; dashboardView: string | null = null; - periodId: number | null = null; + periodId: number = 0; periodVersionId: number | null = null; isLoading = false; @@ -53,11 +54,8 @@ export class DashboardPreviewComponent implements OnInit, AfterViewInit { this.dashboardView = params.get('view') ?? null; // used the operator (+) that auto-casts a string to a number - // this.periodId = +(params.get('period') ?? 0); - if (params.get('period') != null) { - this.periodId = +(params.get('period')!); - } - + this.periodId = +(params.get('period') ?? 0); + // periodVersion might not be defined. In this case, it will calculate the most recent version if (params.get('period_version') != null) { this.periodVersionId = +(params.get('period_version')!); @@ -70,12 +68,8 @@ export class DashboardPreviewComponent implements OnInit, AfterViewInit { this.build(); }); - if (this.periodId == null) { - // Get the latest Period + PeriodVersion - // Do nothing. The period selector will auto-select the moust recent period - - } else if (this.periodId && this.periodVersionId == null) { - // Get the latest PeriodVersion for the requested Period + // Get the latest PeriodVersion for the requested Period + if (this.periodVersionId == null) { this.periodService .lastVersion(this.periodId) .subscribe({ @@ -95,6 +89,8 @@ export class DashboardPreviewComponent implements OnInit, AfterViewInit { //Fire Loading of the dashboard this.build(); } + + this.loadRelationshipsOptions(); } onSearch(): void { @@ -106,14 +102,11 @@ export class DashboardPreviewComponent implements OnInit, AfterViewInit { } build(): void { - // ALWAYS load, even if no period is selected. - /* - if (this.periodId == null || this.periodVersionId == null) { - // Can't load dashboard without a period || periodVersion + if (this.periodVersionId == null) { + // Can't load dashboard without a version this.dashboardComponents = []; // Clear components return; } - */ // Load a list of dashboarComponent's to render this.loadDashboards().subscribe({ @@ -148,6 +141,15 @@ export class DashboardPreviewComponent implements OnInit, AfterViewInit { } } + protected loadRelationshipsOptions(): void { + this.periodService + .query() + .pipe(map((res: HttpResponse) => res.body ?? [])) + .subscribe((periods: IPeriod[]) => { + this.periodsSharedCollection = periods; + }); + } + protected setPageTitles(view: string | null): void { this.pageTitle = ''; this.pageSubTitle = ''; diff --git a/src/main/webapp/app/layouts/main/banner/banner.component.html b/src/main/webapp/app/layouts/main/banner/banner.component.html index 2e52f7e..49ea24c 100644 --- a/src/main/webapp/app/layouts/main/banner/banner.component.html +++ b/src/main/webapp/app/layouts/main/banner/banner.component.html @@ -1,10 +1,6 @@
-
- Route Zero - - - InNOVA NOVA Information System on Environment and Sustainability - +
+ Route Zero
\ No newline at end of file diff --git a/src/main/webapp/app/layouts/navbar/navbar.component.html b/src/main/webapp/app/layouts/navbar/navbar.component.html index e4c2b7b..0e3caf2 100644 --- a/src/main/webapp/app/layouts/navbar/navbar.component.html +++ b/src/main/webapp/app/layouts/navbar/navbar.component.html @@ -45,7 +45,7 @@ > - Organização + Organization
  • @@ -160,7 +160,7 @@ (click)="collapseNavbar()" > - Período + Period
  • @@ -175,7 +175,7 @@ (click)="collapseNavbar()" > - Tipos de Unidade + Unit Type
  • @@ -187,7 +187,7 @@ (click)="collapseNavbar()" > - Unidade + Unit
  • @@ -199,7 +199,7 @@ (click)="collapseNavbar()" > - conversor de Unidades + Unit Converter
  • @@ -214,7 +214,7 @@ (click)="collapseNavbar()" > - Âmbito + Variable Scope
  • @@ -226,7 +226,7 @@ (click)="collapseNavbar()" > - Categoria + Variable Category
  • @@ -238,7 +238,7 @@ (click)="collapseNavbar()" > - Variavel + Variable
  • @@ -261,7 +261,7 @@ (click)="collapseNavbar()" > - Ficheiros de Dados + Input Data Upload
  • - Dados de Inventário + Input Data
  • - Tipo de Organização + Organization Type
  • @@ -343,7 +343,7 @@ (click)="collapseNavbar()" > - Propriedades Metadata + Metadata Property
  • @@ -367,7 +367,7 @@ (click)="collapseNavbar()" > - Tipo de Classe + Variable Class Type
  • @@ -379,7 +379,7 @@ (click)="collapseNavbar()" > - Fatores de Emissão + Emission Factors
  • @@ -391,7 +391,7 @@ (click)="collapseNavbar()" > - Dashboard-Componente + Dashboard Comp.
  • @@ -403,7 +403,7 @@ (click)="collapseNavbar()" > - Documentos + Document
  • @@ -415,7 +415,7 @@ (click)="collapseNavbar()" > - Conteúdos + Content Page
  • diff --git a/src/main/webapp/app/login/login.component.html b/src/main/webapp/app/login/login.component.html index 6dc2af5..d06f9b4 100644 --- a/src/main/webapp/app/login/login.component.html +++ b/src/main/webapp/app/login/login.component.html @@ -12,35 +12,33 @@ }
    -
    -
    - -
    -
    - -
    -

    Esqueci-me da palavra passe

    - +
    +
    -

    ou

    +
    + +
    +

    Esqueci-me da palavra passe

    +
    +

    ou

    diff --git a/src/main/webapp/app/login/login.component.ts b/src/main/webapp/app/login/login.component.ts index e459c8a..cf30f76 100644 --- a/src/main/webapp/app/login/login.component.ts +++ b/src/main/webapp/app/login/login.component.ts @@ -17,7 +17,6 @@ export default class LoginComponent implements OnInit, AfterViewInit { username = viewChild.required('username'); saml2Endpoint : string | null = null; authenticationError = signal(false); - hasBasicAuth: boolean = false; loginForm = new FormGroup({ username: new FormControl('', { nonNullable: true, validators: [Validators.required] }), @@ -45,15 +44,6 @@ export default class LoginComponent implements OnInit, AfterViewInit { console.error('Failed to fetch SAML2 endpoint', err); } }); - - this.accountService.hasBasicAuth().subscribe({ - next: (response: boolean) => { - this.hasBasicAuth = response; - }, - error: (err) => { - console.error('Failed to fetch hasBasicAuth', err); - } - }); } ngAfterViewInit(): void { diff --git a/src/main/webapp/app/resilient/resilient-environment/period-selector/period-selector.component.ts b/src/main/webapp/app/resilient/resilient-environment/period-selector/period-selector.component.ts index a7a0e8a..add08a3 100644 --- a/src/main/webapp/app/resilient/resilient-environment/period-selector/period-selector.component.ts +++ b/src/main/webapp/app/resilient/resilient-environment/period-selector/period-selector.component.ts @@ -63,7 +63,6 @@ export class PeriodSelectorComponent implements OnInit { const queryObject: any = { eagerload: true, sort: this.sortService.buildSortParam(this.sortState()), - }; return this.periodService.query(queryObject).pipe(tap(() => (this.isLoading = false))); } @@ -72,14 +71,6 @@ export class PeriodSelectorComponent implements OnInit { const dataFromBody = this.fillComponentAttributesFromResponseBody(response.body); this.periods = this.refineData(dataFromBody); if (this.periods.length >= 1) { - // Sort the periods - this.periods.sort((a, b) => { - if (!a.beginDate && !b.beginDate) return 0; - if (!a.beginDate) return 1; // null dates go last - if (!b.beginDate) return -1; - return b.beginDate.valueOf() - a.beginDate.valueOf(); - }); - if (this.defaultSelectedPeriodId) { // Select the provided default Period this.selectedPeriod = this.periods.find(period => period.id === this.defaultSelectedPeriodId) || undefined; diff --git a/src/main/webapp/content/images/Graphic1_2024.png b/src/main/webapp/content/images/Graphic1_2024.png deleted file mode 100644 index 6cea7ab..0000000 Binary files a/src/main/webapp/content/images/Graphic1_2024.png and /dev/null differ diff --git a/src/main/webapp/content/images/Graphic2_2024.png b/src/main/webapp/content/images/Graphic2_2024.png deleted file mode 100644 index 598ec4c..0000000 Binary files a/src/main/webapp/content/images/Graphic2_2024.png and /dev/null differ diff --git a/src/main/webapp/content/images/Graphic3_2024.png b/src/main/webapp/content/images/Graphic3_2024.png deleted file mode 100644 index 9fbec69..0000000 Binary files a/src/main/webapp/content/images/Graphic3_2024.png and /dev/null differ diff --git a/src/main/webapp/content/images/Graphic4_2024.png b/src/main/webapp/content/images/Graphic4_2024.png deleted file mode 100644 index 4b6920e..0000000 Binary files a/src/main/webapp/content/images/Graphic4_2024.png and /dev/null differ diff --git a/src/main/webapp/content/images/Graphic_gases_2024.png b/src/main/webapp/content/images/Graphic_gases_2024.png deleted file mode 100644 index cd7c99c..0000000 Binary files a/src/main/webapp/content/images/Graphic_gases_2024.png and /dev/null differ diff --git a/src/main/webapp/content/images/Graphic_missoes_globais_2024.png b/src/main/webapp/content/images/Graphic_missoes_globais_2024.png deleted file mode 100644 index 4899991..0000000 Binary files a/src/main/webapp/content/images/Graphic_missoes_globais_2024.png and /dev/null differ