diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 842c9ae..868293e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,36 +1,22 @@ -# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven - -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - name: Build Project on: - push: - branches: [ "main", "develop" ] pull_request: - branches: [ "main" ] + branches: [ "main", "develop", "release" ] jobs: - build: - + Build: runs-on: self-hosted - steps: - - uses: actions/checkout@v4 - - name: Install Maven - run: sudo apt-get install -y maven - - name: Set up JDK 21 - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: 'temurin' - cache: maven - - name: Build with Maven - env: - DATASOURCE_PASSWORD: ${{ secrets.DATASOURCE_PASSWORD }} - DATASOURCE_URL: ${{ secrets.DATASOURCE_URL }} - DATASOURCE_USERNAME: ${{ secrets.DATASOURCE_USERNAME }} - run: mvn clean install + - uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + cache: maven + + - name: Build with Maven + env: + CONFIG_IP: ${{ secrets.DEV_INTEG_HOST }} + run: mvn clean install diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml new file mode 100644 index 0000000..8a79107 --- /dev/null +++ b/.github/workflows/deploy-dev.yml @@ -0,0 +1,36 @@ +name: Deploy Develop +on: + pull_request: + branches: + - develop + types: + - closed + workflow_dispatch: +jobs: + Deploy: + name: Deploy on Develop + if: ${{ github.event.pull_request.merged == true }} + runs-on: self-hosted + steps: + - name: executing remote ssh commands using ssh key + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.DEV_HOST }} + username: ${{ secrets.HOSTS_USERNAME }} + key: ${{ secrets.DEV_SSH_KEY }} + port: ${{ secrets.SSH_PORT }} + script: | + cd AllConnected/${{ github.event.repository.name }} + echo "Fetching latest code..." + git fetch + git checkout develop + git pull + echo "Building Docker image..." + docker build -t ${{ github.event.repository.name }} . + echo "Creating .env file..." + echo "PROFILE=dev" >> .env + echo "CONFIG_IP=10.43.101.114" >> .env + docker rm -f ${{ github.event.repository.name }} + docker run --name ${{ github.event.repository.name }} --network all_connected -d -p ${{ secrets.SERVICE_PORT }}:8080 --env-file .env ${{ github.event.repository.name }} + echo "Docker container running..." + rm .env diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml new file mode 100644 index 0000000..b292e56 --- /dev/null +++ b/.github/workflows/deploy-prod.yml @@ -0,0 +1,33 @@ +name: Deploy PROD +on: + push: + tags: + - '*' + workflow_dispatch: +jobs: + Deploy: + name: Deploy on PROD + runs-on: self-hosted + steps: + - name: executing remote ssh commands using ssh key + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.PROD_G1_HOST }} + username: ${{ secrets.HOSTS_USERNAME }} + key: ${{ secrets.PROD_G1_SSH_KEY }} + port: ${{ secrets.SSH_PORT }} + script: | + cd AllConnected/${{ github.event.repository.name }} + echo "Fetching latest code..." + git fetch + git checkout main + git pull + echo "Building Docker image..." + docker build -t ${{ github.event.repository.name }} . + echo "Creating .env file..." + echo "PROFILE=prod1" >> .env + echo "CONFIG_IP=10.43.101.72" >> .env + docker rm -f ${{ github.event.repository.name }} + docker run --name ${{ github.event.repository.name }} --network all_connected -d -p ${{ secrets.SERVICE_PORT }}:8080 --env-file .env ${{ github.event.repository.name }} + echo "Docker container running..." + rm .env diff --git a/.github/workflows/deploy-qa.yml b/.github/workflows/deploy-qa.yml new file mode 100644 index 0000000..12b532f --- /dev/null +++ b/.github/workflows/deploy-qa.yml @@ -0,0 +1,36 @@ +name: Deploy QA +on: + pull_request: + branches: + - release + types: + - closed + workflow_dispatch: +jobs: + Deploy: + name: Deploy on QA + if: ${{ github.event.pull_request.merged == true }} + runs-on: self-hosted + steps: + - name: executing remote ssh commands using ssh key + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.QA_G1_HOST }} + username: ${{ secrets.HOSTS_USERNAME }} + key: ${{ secrets.QA_G1_SSH_KEY }} + port: ${{ secrets.SSH_PORT }} + script: | + cd AllConnected/${{ github.event.repository.name }} + echo "Fetching latest code..." + git fetch + git checkout release + git pull + echo "Building Docker image..." + docker build -t ${{ github.event.repository.name }} . + echo "Creating .env file..." + echo "PROFILE=qa1" >> .env + echo "CONFIG_IP=10.43.100.223" >> .env + docker rm -f ${{ github.event.repository.name }} + docker run --name ${{ github.event.repository.name }} --network all_connected -d -p ${{ secrets.SERVICE_PORT }}:8080 --env-file .env ${{ github.event.repository.name }} + echo "Docker container running..." + rm .env diff --git a/.gitignore b/.gitignore index 549e00a..8c68a52 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,9 @@ build/ ### VS Code ### .vscode/ + +### Firebase ### +spring-firebase-key.json + +### Enviroment variables ### +.env diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d8ac2ee --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ +# Etapa 1: Build +FROM maven:3.9.4-eclipse-temurin-21 AS build + +WORKDIR /app + +# Copiar el pom y código fuente +COPY pom.xml ./ +RUN mvn dependency:go-offline + +COPY src ./src + +RUN mvn clean package -DskipTests + +# Etapa 2: Run +FROM eclipse-temurin:21-jdk-jammy + +WORKDIR /app + +# Copiar el jar generado desde la etapa de build +COPY --from=build /app/target/*.jar app.jar + +EXPOSE 8080 + +ENTRYPOINT ["java", "-jar", "app.jar"] diff --git a/README.md b/README.md index aec6ca9..79467bd 100644 --- a/README.md +++ b/README.md @@ -21,12 +21,23 @@ Microservicio encargado del CRUD de usuarios de la aplicación AllConnected Para ejecutar este proyecto, necesitarás agregar las siguientes variables de entorno a tu archivo .env -`DATASOURCE_URL` +### Conexion a la base de datos +`DATASOURCE_URL` `DATASOURCE_USERNAME` - `DATASOURCE_PASSWORD` +### Configuración de Firebase +Estas variables son extraidas del archivo de configuración de Firebase en formato JSON + +`GOOGLE_ADMIN_CONFIG_TYPE` +`GOOGLE_ADMIN_CONFIG_PROJECT_ID` +`GOOGLE_ADMIN_CONFIG_PRIVATE_KEY` +`GOOGLE_ADMIN_CONFIG_PRIVATE_KEY_ID` +`GOOGLE_ADMIN_CONFIG_CLIENT_EMAIL` +`GOOGLE_ADMIN_CONFIG_CLIENT_ID` +`GOOGLE_ADMIN_CONFIG_CLIENT_X509_CERT_URL` + --- ## Ejecutar Localmente 💻 @@ -54,6 +65,23 @@ Inicia el servidor mvn spring-boot:run ``` +--- +## Ejecutar con Docker 🐋 + +```bash + git clone https://github.com/FusionTech-2430/users-service +``` + +Ve al directorio del proyecto + +```bash + cd users-service +``` + +```bash + docker-compose up +``` + --- ## Autores 🧑🏻‍💻 diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..e6de309 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,20 @@ +version: '3.8' + +services: + spring-app: + build: . + ports: + - "8080:8080" + env_file: + - .env + environment: + - DATASOURCE_URL=${DATASOURCE_URL} + - DATASOURCE_USERNAME=${DATASOURCE_USERNAME} + - DATASOURCE_PASSWORD=${DATASOURCE_PASSWORD} + - GOOGLE_ADMIN_CONFIG_TYPE=${GOOGLE_ADMIN_CONFIG_TYPE} + - GOOGLE_ADMIN_CONFIG_PROJECT_ID=${GOOGLE_ADMIN_CONFIG_PROJECT_ID} + - GOOGLE_ADMIN_CONFIG_PRIVATE_KEY=${GOOGLE_ADMIN_CONFIG_PRIVATE_KEY} + - GOOGLE_ADMIN_CONFIG_PRIVATE_KEY_ID=${GOOGLE_ADMIN_CONFIG_PRIVATE_KEY_ID} + - GOOGLE_ADMIN_CONFIG_CLIENT_EMAIL=${GOOGLE_ADMIN_CONFIG_CLIENT_EMAIL} + - GOOGLE_ADMIN_CONFIG_CLIENT_ID=${GOOGLE_ADMIN_CONFIG_CLIENT_ID} + - GOOGLE_ADMIN_CONFIG_CLIENT_X509_CERT_URL=${GOOGLE_ADMIN_CONFIG_CLIENT_X509_CERT_URL} diff --git a/pom.xml b/pom.xml index 38890cf..2873cd8 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,14 @@ org.springframework.cloud spring-cloud-starter-netflix-eureka-client - + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.cloud + spring-cloud-starter-config + org.springframework.boot spring-boot-devtools @@ -64,6 +71,14 @@ lombok true + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.cloud + spring-cloud-starter-config + org.springframework.boot spring-boot-starter-test @@ -74,6 +89,23 @@ reactor-test test + + + com.google.firebase + firebase-admin + 9.1.0 + + + com.google.cloud + google-cloud-storage + 2.11.0 + + + + commons-io + commons-io + 2.16.1 + diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/config/FirebaseConfig.java b/src/main/java/co/allconnected/fussiontech/usersservice/config/FirebaseConfig.java new file mode 100644 index 0000000..b8a89ec --- /dev/null +++ b/src/main/java/co/allconnected/fussiontech/usersservice/config/FirebaseConfig.java @@ -0,0 +1,43 @@ +package co.allconnected.fussiontech.usersservice.config; + +import com.google.auth.oauth2.GoogleCredentials; +import com.google.firebase.FirebaseApp; +import com.google.firebase.FirebaseOptions; +import com.google.gson.Gson; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.PostConstruct; +import java.io.ByteArrayInputStream; +import java.io.IOException; + +@Configuration +public class FirebaseConfig { + + private final FirebaseConfigProperties firebaseConfigProperties; + + public FirebaseConfig(FirebaseConfigProperties firebaseConfigProperties) { + this.firebaseConfigProperties = firebaseConfigProperties; + } + + @PostConstruct + public FirebaseApp initializeFirebase() throws IOException { + firebaseConfigProperties.setPrivate_key( + firebaseConfigProperties.getPrivate_key().replace("\\n", "\n") + ); + + String json = new Gson().toJson(firebaseConfigProperties); + + GoogleCredentials credentials = GoogleCredentials.fromStream(new ByteArrayInputStream(json.getBytes())); + + FirebaseOptions options = FirebaseOptions.builder() + .setCredentials(credentials) + .setStorageBucket(firebaseConfigProperties.getProject_id()+".appspot.com") + .build(); + + if(FirebaseApp.getApps().isEmpty()) { + FirebaseApp.initializeApp(options); + } + + return FirebaseApp.getInstance(); + } +} diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/config/FirebaseConfigProperties.java b/src/main/java/co/allconnected/fussiontech/usersservice/config/FirebaseConfigProperties.java new file mode 100644 index 0000000..80482e0 --- /dev/null +++ b/src/main/java/co/allconnected/fussiontech/usersservice/config/FirebaseConfigProperties.java @@ -0,0 +1,22 @@ +package co.allconnected.fussiontech.usersservice.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "firebase") +@Data +public class FirebaseConfigProperties { + private String type; + private String project_id; + private String private_key; + private String private_key_id; + private String client_email; + private String client_id; + private String auth_uri; + private String token_uri; + private String auth_provider_x509_cert_url; + private String client_x509_cert_url; + private String universe_domain; +} diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/controllers/UsersController.java b/src/main/java/co/allconnected/fussiontech/usersservice/controllers/UsersController.java new file mode 100644 index 0000000..2ff4bfd --- /dev/null +++ b/src/main/java/co/allconnected/fussiontech/usersservice/controllers/UsersController.java @@ -0,0 +1,155 @@ +package co.allconnected.fussiontech.usersservice.controllers; + +import co.allconnected.fussiontech.usersservice.dtos.*; +import co.allconnected.fussiontech.usersservice.services.UserService; +import co.allconnected.fussiontech.usersservice.utils.OperationException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +@RestController +@RequestMapping("/api/v1/users") +public class UsersController { + + private final UserService userService; + + @Autowired + public UsersController(UserService userService) { + this.userService = userService; + } + + @PostMapping + public ResponseEntity createUser( + @ModelAttribute UserDTO user, + @RequestParam(value = "photo", required = false) MultipartFile photo) { + try { + UserDTO userDTO = userService.createUser(user, photo); + return ResponseEntity.status(HttpStatus.CREATED).body(userDTO); + } catch (OperationException e) { + return ResponseEntity.status(e.getCode()).body(new Response(e.getCode(), e.getMessage())); + } catch (RuntimeException e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new Response(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage())); + } + } + + @PostMapping("/from-admin") + public ResponseEntity createUserFromAdmin( + @ModelAttribute UserCreateDTO user, + @RequestParam(value = "photo", required = false) MultipartFile photo) { + try { + UserDTO userDTO = userService.createUserFromAdmin(user, photo); + return ResponseEntity.status(HttpStatus.CREATED).body(userDTO); + } catch (OperationException e) { + return ResponseEntity.status(e.getCode()).body(new Response(e.getCode(), e.getMessage())); + } catch (RuntimeException e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new Response(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage())); + } + } + + @PostMapping("/guest") + public ResponseEntity createGuestUser() { + try { + UserDTO userDTO = userService.createGuestUser(); + return ResponseEntity.status(HttpStatus.CREATED).body(userDTO); + } catch (OperationException e) { + return ResponseEntity.status(e.getCode()).body(new Response(e.getCode(), e.getMessage())); + } + } + + @GetMapping + public ResponseEntity getUsers( + @RequestParam(value = "fullname", required = false) String fullname, + @RequestParam(value = "username", required = false) String username, + @RequestParam(value = "mail", required = false) String mail, + @RequestParam(value = "rol", required = false) String rol, + @RequestParam(value = "active", required = false) Boolean active + ) { + try { + UserDTO[] listUsersDTO = userService.getUsers(fullname, username, mail, rol, active); + return ResponseEntity.status(HttpStatus.OK).body(listUsersDTO); + } catch (OperationException e) { + return ResponseEntity.status(e.getCode()).body(new Response(e.getCode(), e.getMessage())); + } catch (RuntimeException e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new Response(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage())); + } + } + + @GetMapping("/{id}") + public ResponseEntity getUser(@PathVariable String id) { + try { + return ResponseEntity.status(HttpStatus.OK).body(userService.getUser(id)); + } catch (OperationException e) { + return ResponseEntity.status(e.getCode()).body(new Response(e.getCode(), e.getMessage())); + } + } + + @PutMapping("/{id}") + public ResponseEntity updateUser( + @PathVariable String id, + @ModelAttribute UserCreateDTO user, + @RequestParam(value = "photo", required = false) MultipartFile photo) { + try { + System.out.println("Actualizando usuario"); + UserDTO userDTO = userService.updateUser(id, user, photo); + ResponseEntity response = ResponseEntity.status(HttpStatus.OK).body(userDTO); + System.out.println(response.getHeaders()); + return response; + } catch (OperationException e) { + return ResponseEntity.status(e.getCode()).body(new Response(e.getCode(), e.getMessage())); + } catch (RuntimeException e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new Response(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage())); + } + } + + @DeleteMapping("/{id}") + public ResponseEntity deleteUser(@PathVariable String id) { + try { + userService.deleteUser(id); + return ResponseEntity.status(HttpStatus.NO_CONTENT).build(); + } catch (OperationException e) { + return ResponseEntity.status(e.getCode()).body(new Response(e.getCode(), e.getMessage())); + } + } + + @PostMapping("/{id}/deactivate") + public ResponseEntity deactivateUser(@PathVariable String id, @RequestBody DeleteRequestDTO deleteRequest) { + try { + DeletedDTO deletedDTO = userService.deactivateUser(id, deleteRequest.delete_reason()); + return ResponseEntity.status(HttpStatus.OK).body(deletedDTO); + } catch (OperationException e) { + return ResponseEntity.status(e.getCode()).body(new Response(e.getCode(), e.getMessage())); + } + } + + @PostMapping("/{id}/activate") + public ResponseEntity activateUser(@PathVariable String id) { + try { + UserDTO user = userService.activateUser(id); + return ResponseEntity.status(HttpStatus.OK).body(user); + } catch (OperationException e) { + return ResponseEntity.status(e.getCode()).body(new Response(e.getCode(), e.getMessage())); + } + } + + @PostMapping("/{id}/roles") + public ResponseEntity addRole(@PathVariable String id, @RequestBody RolesDTO roles) { + try { + UserDTO userDTO = userService.addRoles(id, roles.roles()); + return ResponseEntity.status(HttpStatus.CREATED).body(userDTO); + } catch (OperationException e) { + return ResponseEntity.status(e.getCode()).body(new Response(e.getCode(), e.getMessage())); + } + } + + @DeleteMapping("/{id}/roles/{rol}") + public ResponseEntity removeRole(@PathVariable String id, @PathVariable String rol) { + try { + UserDTO userDTO = userService.removeRoles(id, rol); + return ResponseEntity.status(HttpStatus.OK).body(userDTO); + } catch (OperationException e) { + return ResponseEntity.status(e.getCode()).body(new Response(e.getCode(), e.getMessage())); + } + } +} \ No newline at end of file diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/controllers/fileToRemove.txt b/src/main/java/co/allconnected/fussiontech/usersservice/controllers/fileToRemove.txt deleted file mode 100644 index 7755816..0000000 --- a/src/main/java/co/allconnected/fussiontech/usersservice/controllers/fileToRemove.txt +++ /dev/null @@ -1 +0,0 @@ -Este archivo es para dejar la estructura de carpetas del proyecto. Eliminar cuando se tenga el proyecto. \ No newline at end of file diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/dtos/DeleteRequestDTO.java b/src/main/java/co/allconnected/fussiontech/usersservice/dtos/DeleteRequestDTO.java new file mode 100644 index 0000000..092bb2c --- /dev/null +++ b/src/main/java/co/allconnected/fussiontech/usersservice/dtos/DeleteRequestDTO.java @@ -0,0 +1,3 @@ +package co.allconnected.fussiontech.usersservice.dtos; +public record DeleteRequestDTO(String delete_reason) { +} diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/dtos/DeletedDTO.java b/src/main/java/co/allconnected/fussiontech/usersservice/dtos/DeletedDTO.java new file mode 100644 index 0000000..44d8c0c --- /dev/null +++ b/src/main/java/co/allconnected/fussiontech/usersservice/dtos/DeletedDTO.java @@ -0,0 +1,8 @@ +// src/main/java/co/allconnected/fussiontech/usersservice/dtos/DeletedDTO.java +package co.allconnected.fussiontech.usersservice.dtos; + +import java.io.Serializable; +import java.time.Instant; + +public record DeletedDTO(String id_user, String delete_reason, Instant delete_date) implements Serializable { +} \ No newline at end of file diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/dtos/InactiveUserDTO.java b/src/main/java/co/allconnected/fussiontech/usersservice/dtos/InactiveUserDTO.java new file mode 100644 index 0000000..0525dcf --- /dev/null +++ b/src/main/java/co/allconnected/fussiontech/usersservice/dtos/InactiveUserDTO.java @@ -0,0 +1,21 @@ +package co.allconnected.fussiontech.usersservice.dtos; + +import co.allconnected.fussiontech.usersservice.model.User; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.Instant; + +@Getter +@Setter +@NoArgsConstructor +public class InactiveUserDTO extends UserDTO{ + private String delete_reason; + private Instant delete_date; + public InactiveUserDTO(User user){ + super(user); + this.delete_reason = user.getDeleted().getReason(); + this.delete_date = user.getDeleted().getDeleteDate(); + } +} diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/dtos/Response.java b/src/main/java/co/allconnected/fussiontech/usersservice/dtos/Response.java new file mode 100644 index 0000000..85a6af6 --- /dev/null +++ b/src/main/java/co/allconnected/fussiontech/usersservice/dtos/Response.java @@ -0,0 +1,4 @@ +package co.allconnected.fussiontech.usersservice.dtos; + +public record Response(int code, String message) { +} diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/dtos/RolesDTO.java b/src/main/java/co/allconnected/fussiontech/usersservice/dtos/RolesDTO.java new file mode 100644 index 0000000..a1a7073 --- /dev/null +++ b/src/main/java/co/allconnected/fussiontech/usersservice/dtos/RolesDTO.java @@ -0,0 +1,4 @@ +package co.allconnected.fussiontech.usersservice.dtos; + +public record RolesDTO(String[] roles) { +} diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/dtos/UserCreateDTO.java b/src/main/java/co/allconnected/fussiontech/usersservice/dtos/UserCreateDTO.java new file mode 100644 index 0000000..4c5915d --- /dev/null +++ b/src/main/java/co/allconnected/fussiontech/usersservice/dtos/UserCreateDTO.java @@ -0,0 +1,4 @@ +package co.allconnected.fussiontech.usersservice.dtos; + +public record UserCreateDTO(String fullname, String username, String password, String mail, String[] roles) { +} \ No newline at end of file diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/dtos/UserDTO.java b/src/main/java/co/allconnected/fussiontech/usersservice/dtos/UserDTO.java new file mode 100644 index 0000000..2757db0 --- /dev/null +++ b/src/main/java/co/allconnected/fussiontech/usersservice/dtos/UserDTO.java @@ -0,0 +1,30 @@ +package co.allconnected.fussiontech.usersservice.dtos; + +import co.allconnected.fussiontech.usersservice.model.Rol; +import co.allconnected.fussiontech.usersservice.model.User; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +public class UserDTO { + private String id_user; + private String fullname; + private String username; + private String mail; + private String photo_url; + private String[] roles; + private boolean active; + + public UserDTO(User user){ + this.id_user = user.getIdUser(); + this.fullname = user.getFullname(); + this.username = user.getUsername(); + this.mail = user.getMail(); + this.photo_url = user.getPhotoUrl(); + this.roles = user.getRoles().stream().map(Rol::getIdRol).toArray(String[]::new); + this.active = user.getActive(); + } +} diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/dtos/fileToRemove.txt b/src/main/java/co/allconnected/fussiontech/usersservice/dtos/fileToRemove.txt deleted file mode 100644 index 7755816..0000000 --- a/src/main/java/co/allconnected/fussiontech/usersservice/dtos/fileToRemove.txt +++ /dev/null @@ -1 +0,0 @@ -Este archivo es para dejar la estructura de carpetas del proyecto. Eliminar cuando se tenga el proyecto. \ No newline at end of file diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/model/Deleted.java b/src/main/java/co/allconnected/fussiontech/usersservice/model/Deleted.java new file mode 100644 index 0000000..8f5c71d --- /dev/null +++ b/src/main/java/co/allconnected/fussiontech/usersservice/model/Deleted.java @@ -0,0 +1,35 @@ +package co.allconnected.fussiontech.usersservice.model; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.Instant; + +@Getter +@Setter +@Entity +@NoArgsConstructor +@Table(name = "deleted", schema = "all_connected_users") +public class Deleted { + public Deleted(String idUser, String reason) { + this.idUser = idUser; + this.reason = reason; + this.deleteDate = Instant.now(); + } + + @Id + @Column(name = "id_user", nullable = false, length = 50) + private String idUser; + + @OneToOne + @JoinColumn(name = "id_user") + private User user; + + @Column(name = "reason", nullable = false, length = 200) + private String reason; + + @Column(name = "delete_date", nullable = false) + private Instant deleteDate; +} \ No newline at end of file diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/model/Rol.java b/src/main/java/co/allconnected/fussiontech/usersservice/model/Rol.java new file mode 100644 index 0000000..371d3b4 --- /dev/null +++ b/src/main/java/co/allconnected/fussiontech/usersservice/model/Rol.java @@ -0,0 +1,21 @@ +package co.allconnected.fussiontech.usersservice.model; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; + +import java.util.LinkedHashSet; +import java.util.Set; + +@Getter +@Setter +@Entity +@Table(name = "rol", schema = "all_connected_users") +public class Rol { + @Id + @Column(name = "id_rol", nullable = false, length = Integer.MAX_VALUE) + private String idRol; + + @ManyToMany(mappedBy = "roles") + private Set users = new LinkedHashSet<>(); +} \ No newline at end of file diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/model/User.java b/src/main/java/co/allconnected/fussiontech/usersservice/model/User.java new file mode 100644 index 0000000..7e79832 --- /dev/null +++ b/src/main/java/co/allconnected/fussiontech/usersservice/model/User.java @@ -0,0 +1,64 @@ +package co.allconnected.fussiontech.usersservice.model; + +import co.allconnected.fussiontech.usersservice.dtos.UserCreateDTO; +import co.allconnected.fussiontech.usersservice.dtos.UserDTO; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.LinkedHashSet; +import java.util.Set; + +@Getter +@Setter +@Entity +@NoArgsConstructor +@Table(name = "\"user\"", schema = "all_connected_users") +public class User { + + public User(UserCreateDTO dto){ + this.fullname = dto.fullname(); + this.username = dto.username(); + this.mail = dto.mail(); + this.active = true; + } + + public User(UserDTO dto){ + this.idUser = dto.getId_user(); + this.fullname = dto.getFullname(); + this.username = dto.getUsername(); + this.mail = dto.getMail(); + this.photoUrl = dto.getMail(); + this.active = true; + } + + @Id + @Column(name = "id_user", nullable = false, length = 28) + private String idUser; + + @Column(name = "fullname", length = 100) + private String fullname; + + @Column(name = "username", nullable = false, length = 45) + private String username; + + @Column(name = "mail", length = 45) + private String mail; + + @Column(name = "photo_url", length = 200) + private String photoUrl; + + @Column(name = "active", nullable = false) + private Boolean active = false; + + @ManyToMany + @JoinTable(name = "user_rol", + schema = "all_connected_users", + joinColumns = @JoinColumn(name = "id_user"), + inverseJoinColumns = @JoinColumn(name = "id_rol")) + private Set roles = new LinkedHashSet<>(); + + @OneToOne(mappedBy = "user", cascade = CascadeType.ALL) + private Deleted deleted; +} \ No newline at end of file diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/model/fileToRemove.txt b/src/main/java/co/allconnected/fussiontech/usersservice/model/fileToRemove.txt deleted file mode 100644 index 7755816..0000000 --- a/src/main/java/co/allconnected/fussiontech/usersservice/model/fileToRemove.txt +++ /dev/null @@ -1 +0,0 @@ -Este archivo es para dejar la estructura de carpetas del proyecto. Eliminar cuando se tenga el proyecto. \ No newline at end of file diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/repository/DeletedRepository.java b/src/main/java/co/allconnected/fussiontech/usersservice/repository/DeletedRepository.java new file mode 100644 index 0000000..86dc627 --- /dev/null +++ b/src/main/java/co/allconnected/fussiontech/usersservice/repository/DeletedRepository.java @@ -0,0 +1,7 @@ +package co.allconnected.fussiontech.usersservice.repository; + +import co.allconnected.fussiontech.usersservice.model.Deleted; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface DeletedRepository extends JpaRepository { +} \ No newline at end of file diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/repository/RolRepository.java b/src/main/java/co/allconnected/fussiontech/usersservice/repository/RolRepository.java new file mode 100644 index 0000000..1950f71 --- /dev/null +++ b/src/main/java/co/allconnected/fussiontech/usersservice/repository/RolRepository.java @@ -0,0 +1,7 @@ +package co.allconnected.fussiontech.usersservice.repository; + +import co.allconnected.fussiontech.usersservice.model.Rol; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface RolRepository extends JpaRepository { +} \ No newline at end of file diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/repository/UserRepository.java b/src/main/java/co/allconnected/fussiontech/usersservice/repository/UserRepository.java new file mode 100644 index 0000000..6939a9f --- /dev/null +++ b/src/main/java/co/allconnected/fussiontech/usersservice/repository/UserRepository.java @@ -0,0 +1,24 @@ +package co.allconnected.fussiontech.usersservice.repository; + +import co.allconnected.fussiontech.usersservice.model.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; + +public interface UserRepository extends JpaRepository { + @Query("SELECT u FROM User u " + + "LEFT JOIN u.roles r " + + "WHERE (:fullname IS NULL OR u.fullname LIKE %:fullname%) " + + "AND (:username IS NULL OR u.username LIKE %:username%) " + + "AND (:mail IS NULL OR u.mail LIKE %:mail%) " + + "AND (:rol IS NULL OR r.idRol LIKE %:rol%) " + + "AND (:active IS NULL OR u.active = :active)") + List findUsersByFilters(@Param("fullname") String fullname, + @Param("username") String username, + @Param("mail") String mail, + @Param("rol") String rol, + @Param("active") Boolean active); + +} \ No newline at end of file diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/repository/fileToRemove.txt b/src/main/java/co/allconnected/fussiontech/usersservice/repository/fileToRemove.txt deleted file mode 100644 index 7755816..0000000 --- a/src/main/java/co/allconnected/fussiontech/usersservice/repository/fileToRemove.txt +++ /dev/null @@ -1 +0,0 @@ -Este archivo es para dejar la estructura de carpetas del proyecto. Eliminar cuando se tenga el proyecto. \ No newline at end of file diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/services/FirebaseService.java b/src/main/java/co/allconnected/fussiontech/usersservice/services/FirebaseService.java new file mode 100644 index 0000000..23ff78e --- /dev/null +++ b/src/main/java/co/allconnected/fussiontech/usersservice/services/FirebaseService.java @@ -0,0 +1,77 @@ +package co.allconnected.fussiontech.usersservice.services; + +import com.google.cloud.storage.Bucket; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseAuthException; +import com.google.firebase.auth.UserRecord; +import com.google.firebase.cloud.StorageClient; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +@Service +public class FirebaseService { + + public String uploadImg(String imageName, String extension, MultipartFile imageFile) throws IOException { + InputStream inputStream = imageFile.getInputStream(); + Bucket bucket = StorageClient.getInstance().bucket(); + bucket.create("user_photos/"+imageName, inputStream, "image/"+extension); + return bucket.get("user_photos/"+imageName) + .signUrl(360, java.util.concurrent.TimeUnit.DAYS).toString(); + } + + public void deleteImg(String imageName) { + Bucket bucket = StorageClient.getInstance().bucket(); + bucket.get("user_photos/"+imageName).delete(); + } + + public String createUser(String email, String password, String[] roles) throws FirebaseAuthException { + UserRecord.CreateRequest request = new UserRecord.CreateRequest() + .setEmail(email) + .setPassword(password); + + // Add custom claims + Map claims = new HashMap<>(); + claims.put("roles", roles); + + // Create user and set custom claims + UserRecord userRecord = FirebaseAuth.getInstance().createUser(request); + FirebaseAuth.getInstance().setCustomUserClaims(userRecord.getUid(), claims); + return userRecord.getUid(); + } + + public void deleteUser(String uid) throws FirebaseAuthException { + FirebaseAuth.getInstance().deleteUser(uid); + } + + public void disableUser(String uid) throws FirebaseAuthException { + UserRecord.UpdateRequest request = new UserRecord.UpdateRequest(uid) + .setDisabled(true); + FirebaseAuth.getInstance().updateUser(request); + } + + public void enableUser(String uid) throws FirebaseAuthException { + UserRecord.UpdateRequest request = new UserRecord.UpdateRequest(uid) + .setDisabled(false); + FirebaseAuth.getInstance().updateUser(request); + } + + public void updateUser(String uid, String email, String password) throws FirebaseAuthException { + UserRecord.UpdateRequest request = new UserRecord.UpdateRequest(uid); + if (email != null) + request.setEmail(email); + if (password != null) + request.setPassword(password); + FirebaseAuth.getInstance().updateUser(request); + } + + public void updateCustomClaims(String uid, String[] roles) throws FirebaseAuthException { + Map claims = new HashMap<>(); + claims.put("roles", roles); + FirebaseAuth.getInstance().setCustomUserClaims(uid, claims); } +} diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/services/RolService.java b/src/main/java/co/allconnected/fussiontech/usersservice/services/RolService.java new file mode 100644 index 0000000..caff223 --- /dev/null +++ b/src/main/java/co/allconnected/fussiontech/usersservice/services/RolService.java @@ -0,0 +1,40 @@ +package co.allconnected.fussiontech.usersservice.services; + +import co.allconnected.fussiontech.usersservice.model.Rol; +import co.allconnected.fussiontech.usersservice.repository.RolRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +public class RolService { + + private final RolRepository rolRepository; + + @Autowired + public RolService(RolRepository rolRepository) { + this.rolRepository = rolRepository; + } + + public Rol createRol(Rol rol) { + return rolRepository.save(rol); + } + + public Optional getRol(String id) { + return rolRepository.findById(id); + } + + public List getAllRoles() { + return rolRepository.findAll(); + } + + public Rol updateRol(Rol rol) { + return rolRepository.save(rol); + } + + public void deleteRol(String id) { + rolRepository.deleteById(id); + } +} \ No newline at end of file diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/services/UserService.java b/src/main/java/co/allconnected/fussiontech/usersservice/services/UserService.java new file mode 100644 index 0000000..e6e686f --- /dev/null +++ b/src/main/java/co/allconnected/fussiontech/usersservice/services/UserService.java @@ -0,0 +1,243 @@ +package co.allconnected.fussiontech.usersservice.services; + +import co.allconnected.fussiontech.usersservice.dtos.DeletedDTO; +import co.allconnected.fussiontech.usersservice.dtos.InactiveUserDTO; +import co.allconnected.fussiontech.usersservice.dtos.UserCreateDTO; +import co.allconnected.fussiontech.usersservice.dtos.UserDTO; +import co.allconnected.fussiontech.usersservice.model.Deleted; +import co.allconnected.fussiontech.usersservice.model.Rol; +import co.allconnected.fussiontech.usersservice.model.User; +import co.allconnected.fussiontech.usersservice.repository.DeletedRepository; +import co.allconnected.fussiontech.usersservice.repository.UserRepository; +import co.allconnected.fussiontech.usersservice.utils.OperationException; +import com.google.firebase.auth.FirebaseAuthException; +import org.apache.commons.io.FilenameUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + +@Service +public class UserService { + + private final UserRepository userRepository; + private final DeletedRepository deletedRepository; + private final RolService rolService; + private final FirebaseService firebaseService; + + @Autowired + public UserService(UserRepository userRepository, DeletedRepository deletedRepository, RolService rolService, FirebaseService firebaseService) { + this.userRepository = userRepository; + this.firebaseService = firebaseService; + this.rolService = rolService; + this.deletedRepository = deletedRepository; + } + + public UserDTO createUser(UserDTO userDto, MultipartFile photo) { + User user = new User(userDto); + // Add roles to user + for (String rol : userDto.getRoles()) { + Optional rolEntity = rolService.getRol(rol); + if(rolEntity.isEmpty()) throw new OperationException(404, "Rol not found"); + user.getRoles().add(rolEntity.get()); + } + + // Update claims + try{ + firebaseService.updateCustomClaims(user.getIdUser(), userDto.getRoles()); + } catch (FirebaseAuthException e) { + throw new OperationException(500, "Firebase authentication error: " + e.getMessage()); + } + + // Upload photo to firebase + if (photo != null) { + String photoName = user.getIdUser(); + String extension = FilenameUtils.getExtension(photo.getOriginalFilename()); + try{ + user.setPhotoUrl(firebaseService.uploadImg(photoName, extension, photo)); + } catch (IOException e) { + throw new OperationException(500, "Error uploading photo: " + e.getMessage()); + } + } + return new UserDTO(userRepository.save(user)); + } + + public UserDTO createUserFromAdmin(UserCreateDTO userDto, MultipartFile photo) { + User user = new User(userDto); + + // Create user in firebase + try { + user.setIdUser(firebaseService.createUser(userDto.mail(), userDto.password(), userDto.roles())); + } catch (FirebaseAuthException e) { + throw new OperationException(500, "Firebase authentication error: " + e.getMessage()); + } + + // Add roles to user + for (String rol : userDto.roles()) { + Optional rolEntity = rolService.getRol(rol); + if(rolEntity.isEmpty()) throw new OperationException(404, "Rol not found"); + user.getRoles().add(rolEntity.get()); + } + + // Upload photo to firebase + if (photo != null) { + String photoName = user.getIdUser(); + String extension = FilenameUtils.getExtension(photo.getOriginalFilename()); + try{ + user.setPhotoUrl(firebaseService.uploadImg(photoName, extension, photo)); + } catch (IOException e) { + throw new OperationException(500, "Error uploading photo: " + e.getMessage()); + } + } + return new UserDTO(userRepository.save(user)); + } + + public UserDTO createGuestUser(){ + User user = new User(); + user.setIdUser(UUID.randomUUID().toString().replace("-", "").substring(0, 28)); + + user.setUsername("Guest<" + user.getIdUser() + ">"); + user.setFullname("Guest"); + user.setActive(true); + + Rol rolEntity = rolService.getRol("guest").orElseThrow(); + user.getRoles().add(rolEntity); + + return new UserDTO(userRepository.save(user)); + } + + public void deleteUser(String id) { + Optional userOptional = userRepository.findById(id); + if (userOptional.isPresent()) { + User user = userOptional.get(); + if (user.getPhotoUrl() != null) + firebaseService.deleteImg(user.getIdUser()); + // check if user is guest + if (user.getRoles().stream().noneMatch(rol -> rol.getIdRol().equals("guest"))) try { + firebaseService.deleteUser(user.getIdUser()); + } catch (FirebaseAuthException e) { + throw new OperationException(500, "Firebase authentication error: " + e.getMessage()); + } + userRepository.delete(user); + } else { + throw new OperationException(404, "User not found"); + } + } + + public DeletedDTO deactivateUser(String id, String reason) { + return userRepository.findById(id).map(user -> { + Deleted deleted = new Deleted(user.getIdUser(), reason); + user.setActive(false); + user.setDeleted(deletedRepository.save(deleted)); + userRepository.save(user); + if (user.getRoles().stream().noneMatch(rol -> rol.getIdRol().equals("guest"))) try { + firebaseService.disableUser(user.getIdUser()); + } catch (FirebaseAuthException e) { + throw new OperationException(500, e.getMessage()); + } + return new DeletedDTO(deleted.getIdUser(), deleted.getReason(), deleted.getDeleteDate()); + }).orElseThrow(() -> new OperationException(404, "User not found")); + } + + public UserDTO activateUser(String id){ + return userRepository.findById(id).map(user -> { + user.setActive(true); + user.setDeleted(null); + userRepository.save(user); + if (user.getRoles().stream().noneMatch(rol -> rol.getIdRol().equals("guest"))) try { + firebaseService.enableUser(user.getIdUser()); + } catch (FirebaseAuthException e) { + throw new OperationException(500, e.getMessage()); + } + return new UserDTO(user); + }).orElseThrow(() -> new OperationException(404, "User not found")); + } + + public UserDTO[] getUsers(String fullname, String username, String mail, String rol, Boolean active) { + return userRepository.findUsersByFilters(fullname, username, mail, rol, active).stream() + .map(user -> user.getActive() ? new UserDTO(user) : new InactiveUserDTO(user)) + .toArray(UserDTO[]::new); + } + + public UserDTO getUser(String id) { + return userRepository.findById(id) + .map(user -> user.getActive() ? new UserDTO(user) : new InactiveUserDTO(user)) + .orElseThrow(() -> new OperationException(404, "User not found")); + } + + public UserDTO updateUser(String id, UserCreateDTO userDTO, MultipartFile photo) { + User user = userRepository.findById(id).orElseThrow(() -> new OperationException(404, "User not found")); + + if(userDTO.fullname() != null && !user.getFullname().equals(userDTO.fullname())) + user.setFullname(userDTO.fullname()); + + if(userDTO.username() != null && !user.getUsername().equals(userDTO.username())) + user.setUsername(userDTO.username()); + + // Update mail and password in firebase if they changed + if (userDTO.mail() != null && !user.getMail().equals(userDTO.mail()) || userDTO.password() != null) { + try { + firebaseService.updateUser(user.getIdUser(), userDTO.mail(), userDTO.password()); + user.setMail(userDTO.mail()); + } catch (FirebaseAuthException e) { + throw new OperationException(500, "Firebase authentication error: " + e.getMessage()); + } + } + + // Update photo if not null + if (photo != null) { + if (user.getPhotoUrl() != null) + firebaseService.deleteImg(user.getIdUser()); + String photoName = user.getIdUser(); + String extension = FilenameUtils.getExtension(photo.getOriginalFilename()); + try{ + user.setPhotoUrl(firebaseService.uploadImg(photoName, extension, photo)); + } catch (IOException e) { + throw new OperationException(500, "Error uploading photo: " + e.getMessage()); + } + } + return new UserDTO(userRepository.save(user)); + } + + public UserDTO addRoles(String id, String[] roles) { + User user = userRepository.findById(id).orElseThrow(() -> new OperationException(404, "User not found")); + for (String rol : roles) { + Rol rolEntity = rolService.getRol(rol).orElseThrow(); + user.getRoles().add(rolEntity); + } + + // Update custom claims in firebase + try { + firebaseService.updateCustomClaims(user.getIdUser(), roles); + } catch (FirebaseAuthException e) { + throw new OperationException(500, "Firebase authentication error: " + e.getMessage()); + } + + return new UserDTO(userRepository.save(user)); + } + + public UserDTO removeRoles(String id, String role) { + User user = userRepository.findById(id).orElseThrow(() -> new OperationException(404, "User not found")); + Rol rolEntity = rolService.getRol(role).orElseThrow(() -> new OperationException(404, "Rol not found")); + user.getRoles().remove(rolEntity); + user = userRepository.save(user); + + // Update custom claims in firebase + String[] roles = user.getRoles().stream() + .map(Rol::getIdRol) + .toArray(String[]::new); + + try { + firebaseService.updateCustomClaims(user.getIdUser(), roles); + } catch (FirebaseAuthException e) { + throw new OperationException(500, "Firebase authentication error: " + e.getMessage()); + } + + return new UserDTO(user); + } +} \ No newline at end of file diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/services/fileToRemove.txt b/src/main/java/co/allconnected/fussiontech/usersservice/services/fileToRemove.txt deleted file mode 100644 index 7755816..0000000 --- a/src/main/java/co/allconnected/fussiontech/usersservice/services/fileToRemove.txt +++ /dev/null @@ -1 +0,0 @@ -Este archivo es para dejar la estructura de carpetas del proyecto. Eliminar cuando se tenga el proyecto. \ No newline at end of file diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/utils/OperationException.java b/src/main/java/co/allconnected/fussiontech/usersservice/utils/OperationException.java new file mode 100644 index 0000000..e826e6f --- /dev/null +++ b/src/main/java/co/allconnected/fussiontech/usersservice/utils/OperationException.java @@ -0,0 +1,14 @@ +package co.allconnected.fussiontech.usersservice.utils; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class OperationException extends RuntimeException { + private final Integer code; + public OperationException(Integer code, String message) { + super(message); + this.code = code; + } +} diff --git a/src/main/java/co/allconnected/fussiontech/usersservice/utils/fileToRemove.txt b/src/main/java/co/allconnected/fussiontech/usersservice/utils/fileToRemove.txt deleted file mode 100644 index 7755816..0000000 --- a/src/main/java/co/allconnected/fussiontech/usersservice/utils/fileToRemove.txt +++ /dev/null @@ -1 +0,0 @@ -Este archivo es para dejar la estructura de carpetas del proyecto. Eliminar cuando se tenga el proyecto. \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 8024e8d..4884193 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,12 +1,7 @@ - spring: application: name: users-service - datasource: - url: ${DATASOURCE_URL} - username: ${DATASOURCE_USERNAME} - password: ${DATASOURCE_PASSWORD} - driver-class-name: org.postgresql.Driver -eureka: - client: - enabled: false + config: + import: configserver:http://${CONFIG_IP:localhost}:8888 + profiles: + active: ${PROFILE:keveldev}