diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 13cf30e..868293e 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -1,41 +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:
-
- runs-on: ubuntu-latest
-
+ Build:
+ runs-on: self-hosted
steps:
- uses: actions/checkout@v4
+
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
- distribution: 'corretto'
+ distribution: 'temurin'
cache: maven
+
- name: Build with Maven
env:
- DATASOURCE_PASSWORD: ${{ secrets.DATASOURCE_PASSWORD }}
- DATASOURCE_URL: ${{ secrets.DATASOURCE_URL }}
- DATASOURCE_USERNAME: ${{ secrets.DATASOURCE_USERNAME }}
- GOOGLE_ADMIN_CONFIG_TYPE: ${{ secrets.GOOGLE_ADMIN_CONFIG_TYPE }}
- GOOGLE_ADMIN_CONFIG_PROJECT_ID: ${{ secrets.GOOGLE_ADMIN_CONFIG_PROJECT_ID }}
- GOOGLE_ADMIN_CONFIG_PRIVATE_KEY: ${{ secrets.GOOGLE_ADMIN_CONFIG_PRIVATE_KEY }}
- GOOGLE_ADMIN_CONFIG_PRIVATE_KEY_ID: ${{ secrets.GOOGLE_ADMIN_CONFIG_PRIVATE_KEY_ID }}
- GOOGLE_ADMIN_CONFIG_CLIENT_EMAIL: ${{ secrets.GOOGLE_ADMIN_CONFIG_CLIENT_EMAIL }}
- GOOGLE_ADMIN_CONFIG_CLIENT_ID: ${{ secrets.GOOGLE_ADMIN_CONFIG_CLIENT_ID }}
- GOOGLE_ADMIN_CONFIG_CLIENT_X509_CERT_URL: ${{ secrets.GOOGLE_ADMIN_CONFIG_CLIENT_X509_CERT_URL }}
+ 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/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 55dc48c..dea936c 100644
--- a/README.md
+++ b/README.md
@@ -21,12 +21,23 @@ Microservicio encargado de gestionar los eventos de la plataforma __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 💻
diff --git a/pom.xml b/pom.xml
index 0004786..b38b702 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
@@ -74,6 +81,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/eventsservice/config/FirebaseConfig.java b/src/main/java/co/allconnected/fussiontech/eventsservice/config/FirebaseConfig.java
new file mode 100644
index 0000000..6d96a9a
--- /dev/null
+++ b/src/main/java/co/allconnected/fussiontech/eventsservice/config/FirebaseConfig.java
@@ -0,0 +1,43 @@
+package co.allconnected.fussiontech.eventsservice.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/eventsservice/config/FirebaseConfigProperties.java b/src/main/java/co/allconnected/fussiontech/eventsservice/config/FirebaseConfigProperties.java
new file mode 100644
index 0000000..a27d551
--- /dev/null
+++ b/src/main/java/co/allconnected/fussiontech/eventsservice/config/FirebaseConfigProperties.java
@@ -0,0 +1,22 @@
+package co.allconnected.fussiontech.eventsservice.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/eventsservice/config/WebConfig.java b/src/main/java/co/allconnected/fussiontech/eventsservice/config/WebConfig.java
new file mode 100644
index 0000000..8128a14
--- /dev/null
+++ b/src/main/java/co/allconnected/fussiontech/eventsservice/config/WebConfig.java
@@ -0,0 +1,18 @@
+package co.allconnected.fussiontech.eventsservice.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class WebConfig implements WebMvcConfigurer {
+
+ @Override
+ public void addCorsMappings(CorsRegistry registry) {
+ registry.addMapping("/**")
+ .allowedOriginPatterns("*")
+ .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
+ .allowedHeaders("*")
+ .allowCredentials(true);
+ }
+}
diff --git a/src/main/java/co/allconnected/fussiontech/eventsservice/controllers/EventController.java b/src/main/java/co/allconnected/fussiontech/eventsservice/controllers/EventController.java
new file mode 100644
index 0000000..191e10a
--- /dev/null
+++ b/src/main/java/co/allconnected/fussiontech/eventsservice/controllers/EventController.java
@@ -0,0 +1,85 @@
+package co.allconnected.fussiontech.eventsservice.controllers;
+
+import co.allconnected.fussiontech.eventsservice.dtos.EventCreateDto;
+import co.allconnected.fussiontech.eventsservice.dtos.EventDto;
+import co.allconnected.fussiontech.eventsservice.dtos.Response;
+import co.allconnected.fussiontech.eventsservice.services.EventService;
+import co.allconnected.fussiontech.eventsservice.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;
+import java.util.List;
+
+@RestController
+@RequestMapping("/api/v0/events")
+public class EventController {
+ // Services
+ private final EventService eventService;
+
+ @Autowired
+ public EventController(EventService eventService) {
+ this.eventService = eventService;
+ }
+
+ // Get all events
+ @GetMapping
+ public ResponseEntity> getAllEvents() {
+ List events = eventService.getAllEvents();
+ return new ResponseEntity<>(events, HttpStatus.OK);
+ }
+
+ // Get event by ID
+ @GetMapping("/{id_event}")
+ public ResponseEntity getEventById(@PathVariable("id_event") Integer id) {
+ EventDto event = eventService.getEventById(id);
+ return new ResponseEntity<>(event, HttpStatus.OK);
+ }
+
+ // Create a new event
+ @PostMapping
+ public ResponseEntity> createEvent(
+ @ModelAttribute EventCreateDto eventDto,
+ @RequestParam(value = "photo", required = false) MultipartFile photo) {
+ try {
+ EventDto newEvent = eventService.createEvent(eventDto, photo);
+ return new ResponseEntity<>(newEvent, HttpStatus.CREATED);
+ } 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()));
+ }
+ }
+
+ // Update an event
+ @PutMapping("/{id_event}")
+ public ResponseEntity updateEvent(
+ @PathVariable("id_event") Integer id,
+ @RequestBody EventDto eventDto,
+ @RequestParam MultipartFile photo) {
+ EventDto updatedEvent = eventService.updateEvent(id, eventDto, photo);
+ return new ResponseEntity<>(updatedEvent, HttpStatus.OK);
+ }
+
+ // Delete an event
+ @DeleteMapping("/{id_event}")
+ public ResponseEntity deleteEvent(@PathVariable("id_event") Integer id) {
+ eventService.deleteEvent(id);
+ return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+ }
+
+ // Add a label to an event
+ @PostMapping("/{id_event}/labels")
+ public ResponseEntity addLabelToEvent(@PathVariable("id_event") Integer eventId, @RequestBody Integer labelId) {
+ EventDto updatedEvent = eventService.addLabelToEvent(eventId, labelId);
+ return new ResponseEntity<>(updatedEvent, HttpStatus.CREATED);
+ }
+
+ // Remove a label from an event
+ @DeleteMapping("/{id_event}/labels/{id_label}")
+ public ResponseEntity removeLabelFromEvent(@PathVariable("id_event") Integer eventId, @PathVariable("id_label") Integer labelId) {
+ eventService.removeLabelFromEvent(eventId, labelId);
+ return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+ }
+}
diff --git a/src/main/java/co/allconnected/fussiontech/eventsservice/controllers/FooController.java b/src/main/java/co/allconnected/fussiontech/eventsservice/controllers/FooController.java
deleted file mode 100644
index d79e2c0..0000000
--- a/src/main/java/co/allconnected/fussiontech/eventsservice/controllers/FooController.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package co.allconnected.fussiontech.eventsservice.controllers;
-
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-@RestController
-public class FooController {
- @GetMapping("/foo")
- public String fooBar() {
- return "Foo Bar";
- }
-}
diff --git a/src/main/java/co/allconnected/fussiontech/eventsservice/controllers/GreetController.java b/src/main/java/co/allconnected/fussiontech/eventsservice/controllers/GreetController.java
deleted file mode 100644
index e807b6d..0000000
--- a/src/main/java/co/allconnected/fussiontech/eventsservice/controllers/GreetController.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package co.allconnected.fussiontech.eventsservice.controllers;
-
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-@RestController
-public class GreetController {
- @GetMapping("/")
- public String index() {
- return "Hello world!";
- }
-}
diff --git a/src/main/java/co/allconnected/fussiontech/eventsservice/controllers/LabelController.java b/src/main/java/co/allconnected/fussiontech/eventsservice/controllers/LabelController.java
new file mode 100644
index 0000000..e2be42a
--- /dev/null
+++ b/src/main/java/co/allconnected/fussiontech/eventsservice/controllers/LabelController.java
@@ -0,0 +1,57 @@
+package co.allconnected.fussiontech.eventsservice.controllers;
+
+import co.allconnected.fussiontech.eventsservice.dtos.LabelDto;
+import co.allconnected.fussiontech.eventsservice.services.LabelService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/api/v0/labels")
+public class LabelController {
+
+ private final LabelService labelService;
+
+ @Autowired
+ public LabelController(LabelService labelService) {
+ this.labelService = labelService;
+ }
+
+ // Create a new label
+ @PostMapping
+ public ResponseEntity createLabel(@RequestBody LabelDto labelDto) {
+ LabelDto createdLabel = labelService.createLabel(labelDto);
+ return new ResponseEntity<>(createdLabel, HttpStatus.CREATED);
+ }
+
+ // Get all labels
+ @GetMapping
+ public ResponseEntity> getAllLabels() {
+ List labels = labelService.getAllLabels();
+ return new ResponseEntity<>(labels, HttpStatus.OK);
+ }
+
+ // Get a label by ID
+ @GetMapping("/{id_label}")
+ public ResponseEntity getLabelById(@PathVariable Integer id_label) {
+ LabelDto label = labelService.getLabelById(id_label);
+ return new ResponseEntity<>(label, HttpStatus.OK);
+ }
+
+ // Update the label by ID
+ @PutMapping("/{id_label}")
+ public ResponseEntity updateLabel(@PathVariable Integer id_label, @RequestBody LabelDto labelDto) {
+ LabelDto updatedLabel = labelService.put(id_label, labelDto);
+ return new ResponseEntity<>(updatedLabel, HttpStatus.OK);
+ }
+
+ // Delete a label by ID
+ @DeleteMapping("/{id_label}")
+ public ResponseEntity deleteLabel(@PathVariable Integer id_label) {
+ labelService.deleteLabel(id_label);
+ return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+ }
+}
diff --git a/src/main/java/co/allconnected/fussiontech/eventsservice/dtos/EventCreateDto.java b/src/main/java/co/allconnected/fussiontech/eventsservice/dtos/EventCreateDto.java
new file mode 100644
index 0000000..6213411
--- /dev/null
+++ b/src/main/java/co/allconnected/fussiontech/eventsservice/dtos/EventCreateDto.java
@@ -0,0 +1,26 @@
+package co.allconnected.fussiontech.eventsservice.dtos;
+
+
+import co.allconnected.fussiontech.eventsservice.models.Label;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.Instant;
+import java.util.Set;
+
+/**
+ * DTO for {@link co.allconnected.fussiontech.eventsservice.models.Event}
+ */
+@Data
+@Builder
+@AllArgsConstructor
+public class EventCreateDto implements Serializable {
+ private String name;
+ private String description;
+ private String photoUrl;
+ private Integer capacity;
+ private Instant date;
+ private Double price;
+}
\ No newline at end of file
diff --git a/src/main/java/co/allconnected/fussiontech/eventsservice/dtos/EventDto.java b/src/main/java/co/allconnected/fussiontech/eventsservice/dtos/EventDto.java
new file mode 100644
index 0000000..1d13124
--- /dev/null
+++ b/src/main/java/co/allconnected/fussiontech/eventsservice/dtos/EventDto.java
@@ -0,0 +1,30 @@
+package co.allconnected.fussiontech.eventsservice.dtos;
+
+import co.allconnected.fussiontech.eventsservice.models.EventParticipant;
+import co.allconnected.fussiontech.eventsservice.models.Label;
+import lombok.*;
+
+import java.io.Serializable;
+import java.time.Instant;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * DTO for {@link co.allconnected.fussiontech.eventsservice.models.Event}
+ */
+@Data
+@Builder
+@AllArgsConstructor
+public class EventDto implements Serializable {
+ private Integer id;
+ private String idBusiness;
+ private String name;
+ private String description;
+ private String photoUrl;
+ private Integer capacity;
+ private Instant date;
+ private Boolean active;
+ private Double price;
+ private Set