diff --git a/.env.sample b/.env.sample index 2fe438c3..7f9fd9e3 100644 --- a/.env.sample +++ b/.env.sample @@ -3,6 +3,7 @@ MYSQL_DB_USERNAME=testuser MYSQL_DB_PASSWORD=testpassword MYSQL_ROOT_PASSWORD=password DB_DDL_POLICY=update +RDS_BACKEND_BASE_URL=http://localhost:3000 RDS_PUBLIC_KEY="-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAg5HrGgKFmH485DXLG4fG 1mKNXceWthXgAozsUGHxLIM3Fa5wU+tLi7tLDZ6LRKo4ZZV2gJJdDqFSNsvn1Uvr diff --git a/skill-tree/src/main/java/com/RDS/skilltree/User/UserSkillsModel.java b/skill-tree/src/main/java/com/RDS/skilltree/User/UserSkillsModel.java index 4754cb64..a4c1adf6 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/User/UserSkillsModel.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/User/UserSkillsModel.java @@ -16,7 +16,7 @@ public class UserSkillsModel { @Id @GeneratedValue - @Column(name = "id", columnDefinition = "BINARY(16)") + @Column(name = "id") private UUID id; @JsonBackReference diff --git a/skill-tree/src/main/java/com/RDS/skilltree/apis/SkillsApi.java b/skill-tree/src/main/java/com/RDS/skilltree/apis/SkillsApi.java index b5e76f43..1a0f65ad 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/apis/SkillsApi.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/apis/SkillsApi.java @@ -2,18 +2,16 @@ import com.RDS.skilltree.User.UserRoleEnum; import com.RDS.skilltree.annotations.AuthorizedRoles; +import com.RDS.skilltree.dtos.SkillRequestsDto; import com.RDS.skilltree.services.EndorsementService; import com.RDS.skilltree.services.SkillService; import com.RDS.skilltree.viewmodels.CreateSkillViewModel; import com.RDS.skilltree.viewmodels.EndorsementViewModel; import com.RDS.skilltree.viewmodels.SkillViewModel; import jakarta.validation.Valid; -import jakarta.validation.constraints.Min; import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -31,6 +29,12 @@ public ResponseEntity> getAll() { return ResponseEntity.ok(skillService.getAll()); } + @GetMapping("/requests") + @AuthorizedRoles({UserRoleEnum.SUPERUSER}) + public ResponseEntity getAllRequests() { + return ResponseEntity.ok(skillService.getAllRequests()); + } + @PostMapping @AuthorizedRoles({UserRoleEnum.SUPERUSER}) public ResponseEntity create(@Valid @RequestBody CreateSkillViewModel skill) { @@ -38,11 +42,8 @@ public ResponseEntity create(@Valid @RequestBody CreateSkillView } @GetMapping("/{id}/endorsements") - public ResponseEntity> getEndorsementsBySkillId( - @RequestParam(name = "offset", defaultValue = "0", required = false) @Min(0) int offset, - @RequestParam(name = "limit", defaultValue = "10", required = false) @Min(1) int limit, + public ResponseEntity> getEndorsementsBySkillId( @PathVariable(value = "id") Integer skillID) { - PageRequest pageRequest = PageRequest.of(offset, limit); - return ResponseEntity.ok(endorsementService.getAllEndorsementsBySkillId(skillID, pageRequest)); + return ResponseEntity.ok(endorsementService.getAllEndorsementsBySkillId(skillID)); } } diff --git a/skill-tree/src/main/java/com/RDS/skilltree/config/AppConfig.java b/skill-tree/src/main/java/com/RDS/skilltree/config/AppConfig.java new file mode 100644 index 00000000..8a71d39f --- /dev/null +++ b/skill-tree/src/main/java/com/RDS/skilltree/config/AppConfig.java @@ -0,0 +1,13 @@ +package com.RDS.skilltree.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +@Configuration +public class AppConfig { + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } +} diff --git a/skill-tree/src/main/java/com/RDS/skilltree/dtos/SkillRequestsDto.java b/skill-tree/src/main/java/com/RDS/skilltree/dtos/SkillRequestsDto.java new file mode 100644 index 00000000..cbb3f277 --- /dev/null +++ b/skill-tree/src/main/java/com/RDS/skilltree/dtos/SkillRequestsDto.java @@ -0,0 +1,23 @@ +package com.RDS.skilltree.dtos; + +import com.RDS.skilltree.viewmodels.SkillRequestViewModel; +import com.RDS.skilltree.viewmodels.UserViewModel; +import java.util.List; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class SkillRequestsDto { + private List requests; + private List users; + + public static SkillRequestsDto toDto( + List skillRequests, List users) { + SkillRequestsDto skillRequestsDto = new SkillRequestsDto(); + skillRequestsDto.setRequests(skillRequests); + skillRequestsDto.setUsers(users); + + return skillRequestsDto; + } +} diff --git a/skill-tree/src/main/java/com/RDS/skilltree/repositories/EndorsementRepository.java b/skill-tree/src/main/java/com/RDS/skilltree/repositories/EndorsementRepository.java index c5e8d670..9b8d3c2f 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/repositories/EndorsementRepository.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/repositories/EndorsementRepository.java @@ -1,10 +1,11 @@ package com.RDS.skilltree.repositories; import com.RDS.skilltree.models.Endorsement; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; +import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; public interface EndorsementRepository extends JpaRepository { - Page findBySkillId(Integer skillId, Pageable pageable); + List findBySkillId(Integer skillId); + + List findByEndorseIdAndSkillId(String endorseId, Integer skillId); } diff --git a/skill-tree/src/main/java/com/RDS/skilltree/repositories/UserSkillRepository.java b/skill-tree/src/main/java/com/RDS/skilltree/repositories/UserSkillRepository.java new file mode 100644 index 00000000..d4aeeb41 --- /dev/null +++ b/skill-tree/src/main/java/com/RDS/skilltree/repositories/UserSkillRepository.java @@ -0,0 +1,12 @@ +package com.RDS.skilltree.repositories; + +import com.RDS.skilltree.User.UserSkillStatusEnum; +import com.RDS.skilltree.User.UserSkillsModel; +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UserSkillRepository extends JpaRepository { + List findByStatus(UserSkillStatusEnum status); + + List findByUserIdAndSkillId(String userId, Integer skillId); +} diff --git a/skill-tree/src/main/java/com/RDS/skilltree/services/EndorsementService.java b/skill-tree/src/main/java/com/RDS/skilltree/services/EndorsementService.java index b11d73f6..36ca6653 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/services/EndorsementService.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/services/EndorsementService.java @@ -3,11 +3,10 @@ import com.RDS.skilltree.viewmodels.CreateEndorsementViewModel; import com.RDS.skilltree.viewmodels.EndorsementViewModel; import com.RDS.skilltree.viewmodels.UpdateEndorsementViewModel; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; +import java.util.List; public interface EndorsementService { - Page getAllEndorsementsBySkillId(Integer skillId, Pageable pageable); + List getAllEndorsementsBySkillId(Integer skillId); EndorsementViewModel create(CreateEndorsementViewModel endorsement); diff --git a/skill-tree/src/main/java/com/RDS/skilltree/services/EndorsementServiceImplementation.java b/skill-tree/src/main/java/com/RDS/skilltree/services/EndorsementServiceImplementation.java index e16fe967..008364cc 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/services/EndorsementServiceImplementation.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/services/EndorsementServiceImplementation.java @@ -2,6 +2,8 @@ import com.RDS.skilltree.User.UserModel; import com.RDS.skilltree.User.UserRepository; +import com.RDS.skilltree.User.UserSkillStatusEnum; +import com.RDS.skilltree.User.UserSkillsModel; import com.RDS.skilltree.exceptions.EndorsementNotFoundException; import com.RDS.skilltree.exceptions.SelfEndorsementNotAllowedException; import com.RDS.skilltree.exceptions.SkillNotFoundException; @@ -10,14 +12,14 @@ import com.RDS.skilltree.models.Skill; import com.RDS.skilltree.repositories.EndorsementRepository; import com.RDS.skilltree.repositories.SkillRepository; +import com.RDS.skilltree.repositories.UserSkillRepository; import com.RDS.skilltree.viewmodels.CreateEndorsementViewModel; import com.RDS.skilltree.viewmodels.EndorsementViewModel; import com.RDS.skilltree.viewmodels.UpdateEndorsementViewModel; +import java.util.List; import java.util.Objects; import java.util.Optional; import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; @Service @@ -26,12 +28,12 @@ public class EndorsementServiceImplementation implements EndorsementService { private final UserRepository userRepository; private final SkillRepository skillRepository; private final EndorsementRepository endorsementRepository; + private final UserSkillRepository userSkillRepository; @Override - public Page getAllEndorsementsBySkillId( - Integer skillId, Pageable pageable) { - Page endorsementPage = endorsementRepository.findBySkillId(skillId, pageable); - return endorsementPage.map(EndorsementViewModel::toViewModel); + public List getAllEndorsementsBySkillId(Integer skillId) { + List endorsements = endorsementRepository.findBySkillId(skillId); + return endorsements.stream().map(EndorsementViewModel::toViewModel).toList(); } @Override @@ -42,7 +44,7 @@ public EndorsementViewModel create(CreateEndorsementViewModel endorsementViewMod String endorseId = endorsementViewModel.getEndorseId(); // TODO: Get this from security context once the login api is implemented. - String endorserId = "ae7a6673c5574140838f209de4c644fc"; + String endorserId = "cf8893a16cee42cc94387a9bd086ed46"; if (Objects.equals(endorseId, endorserId)) { throw new SelfEndorsementNotAllowedException("Self endorsement not allowed"); @@ -64,6 +66,8 @@ public EndorsementViewModel create(CreateEndorsementViewModel endorsementViewMod throw new SkillNotFoundException(String.format("Skill id: %s not found", skillId)); } + List userSkillEntry = + userSkillRepository.findByUserIdAndSkillId(endorseId, skillId); Endorsement endorsement = new Endorsement(); endorsement.setMessage(message); @@ -71,7 +75,18 @@ public EndorsementViewModel create(CreateEndorsementViewModel endorsementViewMod endorsement.setEndorse(endorseDetails.get()); endorsement.setEndorser(endorserDetails.get()); - return EndorsementViewModel.toViewModel(endorsementRepository.save(endorsement)); + if (userSkillEntry.isEmpty()) { + UserSkillsModel userSkillsModel = new UserSkillsModel(); + userSkillsModel.setUser(endorseDetails.get()); + userSkillsModel.setSkill(skillDetails.get()); + userSkillsModel.setStatus(UserSkillStatusEnum.PENDING); + + userSkillRepository.save(userSkillsModel); + } + + Endorsement newEndorsement = endorsementRepository.save(endorsement); + + return EndorsementViewModel.toViewModel(newEndorsement); } @Override diff --git a/skill-tree/src/main/java/com/RDS/skilltree/services/SkillService.java b/skill-tree/src/main/java/com/RDS/skilltree/services/SkillService.java index 10368a0a..e456ade1 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/services/SkillService.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/services/SkillService.java @@ -1,5 +1,6 @@ package com.RDS.skilltree.services; +import com.RDS.skilltree.dtos.SkillRequestsDto; import com.RDS.skilltree.viewmodels.CreateSkillViewModel; import com.RDS.skilltree.viewmodels.SkillViewModel; import java.util.List; @@ -8,4 +9,6 @@ public interface SkillService { List getAll(); SkillViewModel create(CreateSkillViewModel skill); + + SkillRequestsDto getAllRequests(); } diff --git a/skill-tree/src/main/java/com/RDS/skilltree/services/SkillServiceImplementation.java b/skill-tree/src/main/java/com/RDS/skilltree/services/SkillServiceImplementation.java index 8797205c..8fa7a904 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/services/SkillServiceImplementation.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/services/SkillServiceImplementation.java @@ -1,15 +1,19 @@ package com.RDS.skilltree.services; -import com.RDS.skilltree.User.JwtUserModel; -import com.RDS.skilltree.User.UserModel; -import com.RDS.skilltree.User.UserRepository; +import com.RDS.skilltree.User.*; +import com.RDS.skilltree.dtos.SkillRequestsDto; import com.RDS.skilltree.exceptions.SkillAlreadyExistsException; import com.RDS.skilltree.exceptions.UserNotFoundException; +import com.RDS.skilltree.models.Endorsement; import com.RDS.skilltree.models.Skill; +import com.RDS.skilltree.repositories.EndorsementRepository; import com.RDS.skilltree.repositories.SkillRepository; -import com.RDS.skilltree.viewmodels.CreateSkillViewModel; -import com.RDS.skilltree.viewmodels.SkillViewModel; +import com.RDS.skilltree.repositories.UserSkillRepository; +import com.RDS.skilltree.services.external.RdsService; +import com.RDS.skilltree.viewmodels.*; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; @@ -20,8 +24,11 @@ @Service @RequiredArgsConstructor public class SkillServiceImplementation implements SkillService { + private final RdsService rdsService; private final SkillRepository skillRepository; private final UserRepository userRepository; + private final UserSkillRepository userSkillRepository; + private final EndorsementRepository endorsementRepository; @Override public List getAll() { @@ -30,6 +37,71 @@ public List getAll() { .collect(Collectors.toList()); } + @Override + public SkillRequestsDto getAllRequests() { + List pendingSkills = + userSkillRepository.findByStatus(UserSkillStatusEnum.PENDING); + + // store all users data that are a part of this request + Map userDetails = new HashMap<>(); + + // make a list of all pending skill requests with their endorsement details + List skillRequests = + pendingSkills.stream() + .map( + skill -> { + Integer skillId = skill.getSkill().getId(); + String endorseId = skill.getUser().getId(); + String endorseRdsUserId = skill.getUser().getRdsUserId(); + + // Get all endorsement for a specific skill and user Id + List endorsements = + endorsementRepository.findByEndorseIdAndSkillId(endorseId, skillId); + + if (!userDetails.containsKey(endorseId)) { + RdsUserViewModel endorseRdsDetails = + rdsService.getUserDetails(endorseRdsUserId); + UserViewModel endorseDetails = + getUserModalFromRdsDetails(endorseId, endorseRdsDetails); + userDetails.put(endorseId, endorseDetails); + } + + endorsements.forEach( + endorsement -> { + String endorserId = endorsement.getEndorser().getId(); + String endorserRdsUserId = endorsement.getEndorser().getRdsUserId(); + + if (!userDetails.containsKey(endorserId)) { + RdsUserViewModel endorserRdsDetails = + rdsService.getUserDetails(endorserRdsUserId); + UserViewModel endorserDetails = + getUserModalFromRdsDetails(endorserId, endorserRdsDetails); + userDetails.put(endorserId, endorserDetails); + } + }); + + return SkillRequestViewModel.toViewModel(skill, endorsements); + }) + .toList(); + + return SkillRequestsDto.toDto(skillRequests, userDetails.values().stream().toList()); + } + + private static UserViewModel getUserModalFromRdsDetails(String id, RdsUserViewModel rdsDetails) { + String firstName = + rdsDetails.getUser().getFirst_name() != null ? rdsDetails.getUser().getFirst_name() : ""; + String lastName = + rdsDetails.getUser().getLast_name() != null ? rdsDetails.getUser().getLast_name() : ""; + + String username = firstName + ' ' + lastName; + + UserViewModel user = new UserViewModel(); + user.setId(id); + user.setName(username); + + return user; + } + @Override public SkillViewModel create(CreateSkillViewModel skill) { if (skillRepository.existsByName(skill.getName())) { diff --git a/skill-tree/src/main/java/com/RDS/skilltree/services/external/RdsService.java b/skill-tree/src/main/java/com/RDS/skilltree/services/external/RdsService.java new file mode 100644 index 00000000..6166d00d --- /dev/null +++ b/skill-tree/src/main/java/com/RDS/skilltree/services/external/RdsService.java @@ -0,0 +1,7 @@ +package com.RDS.skilltree.services.external; + +import com.RDS.skilltree.viewmodels.RdsUserViewModel; + +public interface RdsService { + RdsUserViewModel getUserDetails(String id); +} diff --git a/skill-tree/src/main/java/com/RDS/skilltree/services/external/RdsServiceImplementation.java b/skill-tree/src/main/java/com/RDS/skilltree/services/external/RdsServiceImplementation.java new file mode 100644 index 00000000..7885ec9d --- /dev/null +++ b/skill-tree/src/main/java/com/RDS/skilltree/services/external/RdsServiceImplementation.java @@ -0,0 +1,32 @@ +package com.RDS.skilltree.services.external; + +import com.RDS.skilltree.viewmodels.RdsUserViewModel; +import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; + +@Service +@RequiredArgsConstructor +public class RdsServiceImplementation implements RdsService { + private static final Logger log = LoggerFactory.getLogger(RdsServiceImplementation.class); + private final RestTemplate restTemplate; + + @Value("${rds.backendBaseUrl}") + private String rdsBackendBaseUrl; + + @Override + public RdsUserViewModel getUserDetails(String id) { + String url = rdsBackendBaseUrl + "/users?id=" + id; + + try { + return restTemplate.getForObject(url, RdsUserViewModel.class); + } catch (RestClientException error) { + log.error("Error calling url: {}, Error : {}", url, error.getMessage()); + throw new RuntimeException("Failed to communicate with RDS backend"); + } + } +} diff --git a/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/MinimalEndorsementViewModel.java b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/MinimalEndorsementViewModel.java new file mode 100644 index 00000000..b6206e46 --- /dev/null +++ b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/MinimalEndorsementViewModel.java @@ -0,0 +1,25 @@ +package com.RDS.skilltree.viewmodels; + +import com.RDS.skilltree.models.Endorsement; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class MinimalEndorsementViewModel { + private Integer id; + private String endorserId; + private String endorsementDate; + private String message; + + public static MinimalEndorsementViewModel toViewModel(Endorsement endorsement) { + MinimalEndorsementViewModel endorsementViewModel = new MinimalEndorsementViewModel(); + + endorsementViewModel.setId(endorsement.getId()); + endorsementViewModel.setMessage(endorsement.getMessage()); + endorsementViewModel.setEndorsementDate(endorsement.getCreatedAt().toString()); + endorsementViewModel.setEndorserId(endorsement.getEndorser().getId()); + + return endorsementViewModel; + } +} diff --git a/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/RdsUserViewModel.java b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/RdsUserViewModel.java new file mode 100644 index 00000000..76284c89 --- /dev/null +++ b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/RdsUserViewModel.java @@ -0,0 +1,56 @@ +package com.RDS.skilltree.viewmodels; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class RdsUserViewModel { + + private String message; + private User user; + + @Getter + @Setter + public static class User { + private String id; + private boolean incomplete_user_details; + private String discord_joined_at; + private String discord_id; + private Roles roles; + private String linkedin_id; + private Picture picture; + private float yoe; + private long github_created_at; + private String github_display_name; + private String github_id; + private String twitter_id; + private String username; + private String github_user_id; + private String first_name; + private String profile_url; + private String website; + private String last_name; + private String company; + private String designation; + private String instagram_id; + private String profile_status; + private long updated_at; + private long created_at; + } + + @Getter + @Setter + public static class Roles { + private boolean archived; + private boolean in_discord; + private boolean member; + } + + @Getter + @Setter + public static class Picture { + private String url; + private String public_id; + } +} diff --git a/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/SkillRequestViewModel.java b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/SkillRequestViewModel.java new file mode 100644 index 00000000..48b433c1 --- /dev/null +++ b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/SkillRequestViewModel.java @@ -0,0 +1,39 @@ +package com.RDS.skilltree.viewmodels; + +import com.RDS.skilltree.User.UserModel; +import com.RDS.skilltree.User.UserSkillsModel; +import com.RDS.skilltree.models.Endorsement; +import com.RDS.skilltree.models.Skill; +import java.util.List; +import java.util.stream.Collectors; +import lombok.Data; + +@Data +public class SkillRequestViewModel { + private Integer skillId; + private String skillName; + private String endorseId; + private List endorsements; + + public SkillRequestViewModel( + Integer id, String name, String endorseId, List endorsements) { + this.skillId = id; + this.skillName = name; + this.endorseId = endorseId; + this.endorsements = endorsements; + } + + public static SkillRequestViewModel toViewModel( + UserSkillsModel userSkillsModel, List endorsements) { + Skill skill = userSkillsModel.getSkill(); + UserModel user = userSkillsModel.getUser(); + + return new SkillRequestViewModel( + skill.getId(), + skill.getName(), + user.getId(), + endorsements.stream() + .map(MinimalEndorsementViewModel::toViewModel) + .collect(Collectors.toList())); + } +} diff --git a/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/UserViewModel.java b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/UserViewModel.java index e9a98d3a..d0f28ed3 100644 --- a/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/UserViewModel.java +++ b/skill-tree/src/main/java/com/RDS/skilltree/viewmodels/UserViewModel.java @@ -8,6 +8,7 @@ @Getter @Setter public class UserViewModel { + private String id; private String name; public static UserViewModel toViewModel(UserModel user) { diff --git a/skill-tree/src/main/resources/application.properties b/skill-tree/src/main/resources/application.properties index 6929702e..13e2719b 100644 --- a/skill-tree/src/main/resources/application.properties +++ b/skill-tree/src/main/resources/application.properties @@ -11,3 +11,4 @@ management.endpoints.web.exposure.include=health,info,metrics logging.level.root=ERROR # If no value received from env default is dev spring.profiles.active=${SPRING_PROFILES_ACTIVE:dev} +rds.backendBaseUrl=${RDS_BACKEND_BASE_URL} \ No newline at end of file