Skip to content

Commit

Permalink
feat: adapt testcontainers pipeline
Browse files Browse the repository at this point in the history
test: integration BuildingControllerTest
bugfix: fix PR
feat: setup idp testcontainer
feat: create building resource
  • Loading branch information
thongdanghoang authored and Thống committed Feb 14, 2025
1 parent a63d02b commit c44bad6
Show file tree
Hide file tree
Showing 31 changed files with 2,409 additions and 118 deletions.
5 changes: 2 additions & 3 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,10 @@ jobs:
${{ runner.os }}-gradle-
- name: Validate Gradle wrapper
uses: gradle/wrapper-validation-action@v1

- name: Build with Gradle
timeout-minutes: 15
run: |
./gradlew build --scan
./gradlew build -x test --scan
working-directory: ${{ matrix.module }}

build-frontend:
Expand All @@ -63,4 +62,4 @@ jobs:
working-directory: sep490-frontend
- run: npm run build
timeout-minutes: 5
working-directory: sep490-frontend
working-directory: sep490-frontend
1 change: 0 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ jobs:
${{ runner.os }}-gradle-
- name: Validate Gradle wrapper
uses: gradle/wrapper-validation-action@v1

- name: Build with Gradle
timeout-minutes: 15
run: |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
@Getter
public abstract class SagaManager {

protected static final int TRANSACTION_TIMEOUT = 10000;

private final ConcurrentHashMap<String, CompletableFuture<Object>> pendingSagaResponses = new ConcurrentHashMap<>();

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package commons.springfw.impl.securities;

import com.nimbusds.jose.shaded.gson.internal.LinkedTreeMap;
import green_buildings.commons.api.dto.auth.BuildingPermissionDTO;
import green_buildings.commons.api.security.BuildingPermissionRole;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import green_buildings.commons.api.dto.auth.BuildingPermissionDTO;
import green_buildings.commons.api.security.BuildingPermissionRole;

import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -36,7 +36,7 @@ public JwtAuthenticationTokenDecorator convert(Jwt source) {
.collect(Collectors.toUnmodifiableSet());
}

var buildingPermissionsClaim = Objects.requireNonNull(source.getClaims().get("permissions"));
var buildingPermissionsClaim = Optional.ofNullable(source.getClaims().get("permissions")).orElse(Collections.emptyList());
List<BuildingPermissionDTO> buildingPermissions = Collections.emptyList();
if (buildingPermissionsClaim instanceof List<?> buildingPermissionsList) {
buildingPermissions = buildingPermissionsList
Expand Down
3 changes: 2 additions & 1 deletion sep490-enterprise/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ dependencies {
testImplementation 'org.testcontainers:junit-jupiter'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testRuntimeOnly 'com.h2database:h2'
testImplementation 'org.testcontainers:postgresql'
testImplementation 'io.rest-assured:rest-assured'

// Ops
implementation 'org.springframework.boot:spring-boot-starter-actuator'
Expand Down
11 changes: 10 additions & 1 deletion sep490-enterprise/src/main/java/enterprise/dtos/BuildingDTO.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
package enterprise.dtos;

import green_buildings.commons.api.BaseDTO;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import lombok.Builder;

import java.math.BigDecimal;
import java.util.UUID;

@Builder
public record BuildingDTO(
UUID id,
int version
int version,
@NotBlank String name,
@Min(1) int floors,
@DecimalMin(value = "0.0", inclusive = true) BigDecimal squareMeters
) implements BaseDTO {
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
package enterprise.entities;

import commons.springfw.impl.entities.AbstractAuditableEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.math.BigDecimal;

@Entity
@Table(name = "buildings")
@Getter
Expand All @@ -23,4 +29,15 @@ public class BuildingEntity extends AbstractAuditableEntity {
@JoinColumn(name = "enterprise_id", nullable = false)
private EnterpriseEntity enterprise;

@NotBlank
@Column(name = "name", nullable = false)
private String name;

@Min(value = 1)
@Column(name = "floors", nullable = false)
private int floors;

@DecimalMin(value = "0.0", inclusive = true)
@Column(name = "square_meters", nullable = false, precision = 15, scale = 3)
private BigDecimal squareMeters;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package enterprise.mappers;

import enterprise.dtos.BuildingDTO;
import enterprise.entities.BuildingEntity;
import org.mapstruct.BeanMapping;
import org.mapstruct.Mapper;
import org.mapstruct.MappingConstants;
import org.mapstruct.MappingTarget;
import org.mapstruct.NullValuePropertyMappingStrategy;
import org.mapstruct.ReportingPolicy;

@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE, componentModel = MappingConstants.ComponentModel.SPRING)
public interface BuildingMapper {
BuildingEntity toEntity(BuildingDTO buildingDTO);

BuildingDTO toDto(BuildingEntity buildingEntity);

@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
BuildingEntity partialUpdate(BuildingDTO buildingDTO, @MappingTarget
BuildingEntity buildingEntity);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

import commons.springfw.impl.repositories.AbstractBaseRepository;
import enterprise.entities.BuildingEntity;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.util.UUID;

public interface BuildingRepository extends AbstractBaseRepository<BuildingEntity> {

Page<BuildingEntity> findByEnterpriseId(UUID enterpriseId, Pageable pageable);

}
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
package enterprise.rest;

import commons.springfw.impl.mappers.CommonMapper;
import commons.springfw.impl.securities.UserContextData;
import enterprise.dtos.BuildingDTO;
import enterprise.mappers.BuildingMapper;
import enterprise.services.BuildingService;
import enterprise.services.EnterpriseService;
import green_buildings.commons.api.dto.SearchCriteriaDTO;
import green_buildings.commons.api.dto.SearchResultDTO;
import green_buildings.commons.api.security.UserRole;
import jakarta.annotation.security.RolesAllowed;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import green_buildings.commons.api.security.UserRole;

import java.util.List;
import java.util.Objects;

@RestController
@RequestMapping("/buildings")
Expand All @@ -22,10 +30,30 @@
})
public class BuildingController {

@GetMapping
private final BuildingMapper buildingMapper;
private final BuildingService buildingService;
private final EnterpriseService enterpriseService;

@PostMapping("/search")
public ResponseEntity<SearchResultDTO<BuildingDTO>> getEnterpriseBuildings(@RequestBody SearchCriteriaDTO<Void> searchCriteria,
@AuthenticationPrincipal UserContextData userContextData) {
var enterpriseIdFromContext = Objects.requireNonNull(userContextData.getEnterpriseId());
var pageable = CommonMapper.toPageable(searchCriteria.page(), searchCriteria.sort());
var searchResults = buildingService.getEnterpriseBuildings(enterpriseIdFromContext, pageable);
var searchResultDTO = CommonMapper.toSearchResultDTO(searchResults, buildingMapper::toDto);
return ResponseEntity.ok(searchResultDTO);
}

@PostMapping
@RolesAllowed(UserRole.RoleNameConstant.ENTERPRISE_OWNER)
public ResponseEntity<List<BuildingDTO>> getEnterpriseBuildings(@AuthenticationPrincipal UserContextData userContextData) {
return ResponseEntity.ok().build();
public ResponseEntity<BuildingDTO> createBuilding(@RequestBody BuildingDTO buildingDTO,
@AuthenticationPrincipal UserContextData userContextData) {
var enterpriseIdFromContext = Objects.requireNonNull(userContextData.getEnterpriseId());
var enterprise = enterpriseService.getById(enterpriseIdFromContext);
var building = buildingMapper.toEntity(buildingDTO);
building.setEnterprise(enterprise);
var createdBuilding = buildingService.createBuilding(building);
return ResponseEntity.status(HttpStatus.CREATED).body(buildingMapper.toDto(createdBuilding));
}

}
Original file line number Diff line number Diff line change
@@ -1,26 +1,13 @@
package enterprise.rest;

import commons.springfw.impl.securities.UserContextData;
import enterprise.dtos.EnterpriseDTO;
import enterprise.mappers.EnterpriseMapper;
import enterprise.services.EnterpriseService;
import green_buildings.commons.api.exceptions.BusinessException;
import green_buildings.commons.api.security.UserRole;
import jakarta.annotation.security.RolesAllowed;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collections;
import java.util.Objects;
import java.util.UUID;

@RestController
@RequestMapping("/enterprise")
@RequiredArgsConstructor
Expand All @@ -32,18 +19,4 @@ public class EnterpriseController {
private final EnterpriseService service;
private final EnterpriseMapper mapper;

@PostMapping
public ResponseEntity<UUID> createEnterprise(@AuthenticationPrincipal UserContextData userContextData,
@RequestBody EnterpriseDTO enterpriseDTO) {
if (Objects.nonNull(userContextData.getEnterpriseId())) {
throw new BusinessException(StringUtils.EMPTY, "error.user.already.belongs.to.enterprise", Collections.emptyList());
}

var enterprise = mapper.createEnterprise(enterpriseDTO);

return ResponseEntity
.status(HttpStatus.CREATED)
.body(service.createEnterprise(enterprise));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package enterprise.services;

import enterprise.entities.BuildingEntity;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.util.UUID;

public interface BuildingService {

BuildingEntity createBuilding(BuildingEntity building);

Page<BuildingEntity> getEnterpriseBuildings(UUID enterpriseId, Pageable page);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ public interface EnterpriseService {

UUID createEnterprise(EnterpriseEntity enterprise);

EnterpriseEntity getById(UUID id);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package enterprise.services.impl;

import enterprise.entities.BuildingEntity;
import enterprise.repositories.BuildingRepository;
import enterprise.services.BuildingService;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.UUID;

@Service
@Transactional(rollbackOn = Throwable.class)
@RequiredArgsConstructor
public class BuildingServiceImpl implements BuildingService {

private final BuildingRepository buildingRepository;

@Override
public BuildingEntity createBuilding(BuildingEntity building) {
return buildingRepository.save(building);
}

@Override
public Page<BuildingEntity> getEnterpriseBuildings(UUID enterpriseId, Pageable page) {
return buildingRepository.findByEnterpriseId(enterpriseId, page);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,9 @@ public class EnterpriseServiceImpl implements EnterpriseService {
public UUID createEnterprise(EnterpriseEntity enterprise) {
return repository.save(enterprise).getId();
}

@Override
public EnterpriseEntity getById(UUID id) {
return repository.findById(id).orElseThrow();
}
}
2 changes: 1 addition & 1 deletion sep490-enterprise/src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
exchangerate-api:
key: ${EXCHANGERATE_API_KEY}
key: ${EXCHANGERATE_API_KEY:secret}
url: https://v6.exchangerate-api.com/v6/

spring:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ALTER TABLE buildings
ADD COLUMN name VARCHAR(255) NOT NULL,
ADD COLUMN floors INTEGER NOT NULL,
ADD COLUMN square_meters NUMERIC(15, 3) NOT NULL;

This file was deleted.

Loading

0 comments on commit c44bad6

Please sign in to comment.