Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • xvicenik/formula-team-management
1 result
Show changes
Commits on Source (34)
Showing
with 418 additions and 38 deletions
......@@ -14,14 +14,36 @@ default:
stages:
- build
- test
- tests
build:
stage: build
script:
- echo "We are building your project"
- mvn clean install $MAVEN_CLI_OPTS -DskipTests
test:
stage: test
unit_test:
stage: tests
script:
- mvn test $MAVEN_CLI_OPTS
\ No newline at end of file
- echo "We are testing your project build with unit tests"
- mvn test $MAVEN_CLI_OPTS
artifacts:
expire_in: 10 min
paths:
- "*/target/surefire-reports/*"
reports:
junit:
- "*/target/surefire-reports/*.xml"
integration_test:
stage: tests
script:
- echo "We are testing your project build with integration tests"
- mvn verify $MAVEN_CLI_OPTS
artifacts:
expire_in: 10 min
paths:
- "*/target/failsafe-reports/*"
reports:
junit:
- "*/target/failsafe-reports/*.xml"
......@@ -97,6 +97,15 @@ Just note that each module runs on a different port by default, so care where yo
These ports can be overridden either in the application.properties file of each module, or by specifying the port
manually when running the "mvn" command to run the module.
## Seed and clear DB
DB is at the start of the app seeded with some Data, thus you don't have to do it manually.
For users are available 2 endpoints:
- /seed - Seed DB with some Data
- /clear - Clear DB whenever during running
*Note: /seed will always seed DB with the same Data. Keep in mind, If you seed DB after startup, DB will contain the same data twice.*
## Build and run the app with Docker
For purpose of this build and run the installation of Docker/Podman
......@@ -153,10 +162,40 @@ To run all modules at once in one container, you can run in root directory
docker-compose up
```
*Note: in case you want to also rebuild images, use flag `--build`*
*Note: use flag `-d` for detached mode*
To stop container
To stop container run
```bash
docker-compose down
```
## Collecting Metrics
Create network for being able to communicate between two separate
docker images
```bash
docker network create grafana-prometheus
```
To collect the metrics in an automated way we use Prometheus.
First, make sure that every service you want to observe is running on predefined port.
Then run Prometheus in docker with respect to location of `prometheus.yml` file:
```bash
docker run --rm --name prometheus --network grafana-prometheus --network-alias prometheus -p 9090:9090 -v ${PWD}/prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus:v2.43.0 --config.file=/etc/prometheus/prometheus.yml
```
## Grafana
Run Grafana in separate container:
```bash
docker run --rm --name grafana --network grafana-prometheus -p 3000:3000 grafana/grafana:9.1.7
```
1. Log into Grafana with default user and password is `admin`.
2. Add data source in Configuration -> Data sources (http://prometheus:9090)
3. Import Dashboard as JSON file (two options - [simple](https://gitlab.fi.muni.cz/xvicenik/formula-team-management/-/blob/11-actuator/grafana.json), [advanced](https://gitlab.fi.muni.cz/xvicenik/formula-team-management/-/blob/11-actuator/justai-system-monitor_rev2.json))
......@@ -5,15 +5,17 @@ info:
Hand-made OpenAPI document.
version: 1.0.0
servers:
- url: "http://localhost:8080"
- url: "http://localhost:8081"
tags:
- name: ApplicationService
- name: DBManagementService
components:
schemas:
ApplicationStatus:
type: string
description: Status of application
enum:
- pending
- rejected
- accepted
......@@ -26,6 +28,7 @@ components:
- name
- surname
- fillingOutDate
- email
properties:
id:
type: integer
......@@ -36,15 +39,20 @@ components:
type: string
description: Name of the person
example: Max
maxLength: 35
surname:
type: string
description: Surname of the person
example: Verstappen
maxLength: 35
birthday:
type: string
description: Date of birth
example: 09-30-1997
format: date
email:
type: string
description: Email address of the person
fillingOutDate:
type: string
description: Date of filling out the application
......@@ -58,17 +66,23 @@ components:
name:
type: string
description: Name of the person
maxLength: 35
surname:
type: string
description: Name of the person
maxLength: 35
birthday:
type: string
description: Date of birth
example: 1977-09-30
format: date
email:
type: string
description: Email address of the person
required:
- name
- surname
- email
responses:
NotFound:
......@@ -91,6 +105,16 @@ components:
properties:
message:
type: string
Successful:
description: Successfully processed
content:
application/json:
schema:
type: object
title: Successfully processed
properties:
message:
type: string
paths:
/application:
......@@ -170,5 +194,28 @@ paths:
$ref: '#/components/schemas/ApplicationDto'
"404":
$ref: '#/components/responses/NotFound'
default:
$ref: '#/components/responses/Unexpected'
/seed:
post:
tags:
- DBManagementService
summary: Seed DB with data
operationId: seedDB
responses:
"200":
$ref: '#/components/responses/Successful'
default:
$ref: '#/components/responses/Unexpected'
/clear:
post:
tags:
- DBManagementService
summary: Clear DB
operationId: clearDB
responses:
"200":
$ref: '#/components/responses/Successful'
default:
$ref: '#/components/responses/Unexpected'
\ No newline at end of file
......@@ -152,5 +152,17 @@
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<!-- Actuator dependency-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Prometheus dependency -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
</dependencies>
</project>
package cz.muni.pa165.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.client.RestTemplate;
/**
* @author Michal Badin
......@@ -11,4 +13,8 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
@ComponentScan
@EnableTransactionManagement
public class ServiceConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
\ No newline at end of file
......@@ -7,8 +7,11 @@ import com.fasterxml.jackson.annotation.JsonValue;
* @author Michal Badin
*/
public enum ApplicationStatusEnum {
ACCEPTED("accepted"),
REJECTED("rejected");
PENDING("pending"),
REJECTED("rejected"),
ACCEPTED("accepted");
private final String value;
......
......@@ -2,10 +2,7 @@ package cz.muni.pa165.data.model;
import cz.muni.pa165.data.enums.ApplicationStatusEnum;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Past;
import jakarta.validation.constraints.PastOrPresent;
import jakarta.validation.constraints.*;
import java.io.Serializable;
import java.time.LocalDate;
......@@ -25,26 +22,33 @@ public class Application implements Serializable {
private ApplicationStatusEnum status;
@NotEmpty
@Size(max = 35)
private String name;
@NotEmpty
@Size(max = 35)
private String surname;
@Past
@NotNull
private LocalDate birthday;
@Email
private String email;
@Column(name = "filling_out_date")
@PastOrPresent
private LocalDate fillingOutDate;
public Application() {}
public Application() {
}
public Application(ApplicationStatusEnum status, String name, String surname, LocalDate birthday, LocalDate fillingOutDate) {
public Application(ApplicationStatusEnum status, String name, String surname, LocalDate birthday, String email, LocalDate fillingOutDate) {
this.status = status;
this.name = name;
this.surname = surname;
this.birthday = birthday;
this.email = email;
this.fillingOutDate = fillingOutDate;
}
......@@ -88,6 +92,14 @@ public class Application implements Serializable {
this.birthday = birthday;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public LocalDate getFillingOutDate() {
return fillingOutDate;
}
......
......@@ -4,8 +4,6 @@ import cz.muni.pa165.data.model.Application;
import cz.muni.pa165.generated.model.ApplicationCreateDto;
import cz.muni.pa165.generated.model.ApplicationDto;
import org.mapstruct.Mapper;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import java.util.List;
......@@ -19,9 +17,5 @@ public interface ApplicationMapper {
Application mapFromCreateDto(ApplicationCreateDto carCreateDto);
List<ApplicationDto> mapToList(List<Application> cars);
default Page<ApplicationDto> mapToPageDto(Page<Application> cars) {
return new PageImpl<>(mapToList(cars.getContent()), cars.getPageable(), cars.getTotalPages());
}
}
package cz.muni.pa165.rest;
import cz.muni.pa165.generated.api.DbManagementServiceApiDelegate;
import cz.muni.pa165.generated.model.SuccessfullyProcessed;
import cz.muni.pa165.service.DBManagementService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
/**
* @author Michal Badin
*/
@Profile("dev")
@Component
public class DBManagementController implements DbManagementServiceApiDelegate {
private static final Logger log = LoggerFactory.getLogger(DBManagementController.class);
private final DBManagementService dbManagementService;
@Autowired
public DBManagementController(DBManagementService dbManagementService) {
this.dbManagementService = dbManagementService;
}
@Override
public ResponseEntity<SuccessfullyProcessed> seedDB() {
log.debug("seedDB() called");
dbManagementService.seed();
return new ResponseEntity<>(HttpStatus.OK);
}
@Override
public ResponseEntity<SuccessfullyProcessed> clearDB() {
log.debug("clearDB() called");
dbManagementService.clear();
return new ResponseEntity<>(HttpStatus.OK);
}
}
......@@ -4,12 +4,21 @@ import cz.muni.pa165.data.enums.ApplicationStatusEnum;
import cz.muni.pa165.data.model.Application;
import cz.muni.pa165.data.repository.ApplicationRepository;
import cz.muni.pa165.exceptions.ResourceNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
......@@ -17,12 +26,18 @@ import java.util.Optional;
*/
@Service
public class ApplicationService {
private static final Logger log = LoggerFactory.getLogger(ApplicationService.class);
private static final String NOTIFICATION_MODULE_URL_NEW = "http://localhost:8083/notification/application/new";
private static final String NOTIFICATION_MODULE_URL_STATUS = "http://localhost:8083/notification/application/status";
private static final List<String> NOTIFICATION_RECEIVERS = List.of("formula.team.management@gmail.com");
private final ApplicationRepository applicationRepository;
private final RestTemplate restTemplate;
@Autowired
public ApplicationService(ApplicationRepository applicationRepository) {
public ApplicationService(ApplicationRepository applicationRepository, RestTemplate restTemplate) {
this.applicationRepository = applicationRepository;
this.restTemplate = restTemplate;
}
@Transactional(readOnly = true)
......@@ -32,7 +47,17 @@ public class ApplicationService {
public Application create(Application application) {
application.setFillingOutDate(LocalDate.now());
return applicationRepository.save(application);
application.setStatus(ApplicationStatusEnum.PENDING);
var savedApplication = applicationRepository.save(application);
try {
sendPostRequest(savedApplication, NOTIFICATION_MODULE_URL_NEW, List.of(savedApplication.getEmail()));
} catch (RestClientException | IllegalArgumentException e) {
log.debug(String.format("The notification module is not reachable on the URL: %s", NOTIFICATION_MODULE_URL_NEW));
}
return savedApplication;
}
@Transactional(readOnly = true)
......@@ -50,6 +75,27 @@ public class ApplicationService {
applicationFromDb.get().setStatus(applicationStatusEnum);
return applicationRepository.save(applicationFromDb.get());
var savedApplication = applicationRepository.save(applicationFromDb.get());
if (savedApplication.getStatus() != ApplicationStatusEnum.PENDING) {
try {
sendPostRequest(savedApplication, NOTIFICATION_MODULE_URL_STATUS, NOTIFICATION_RECEIVERS);
} catch (RestClientException | IllegalArgumentException e) {
log.debug(String.format("The notification module is not reachable on the URL: %s", NOTIFICATION_MODULE_URL_NEW));
}
}
return savedApplication;
}
private void sendPostRequest(Application application, String url, List<String> receivers) {
Map<String, Object> notification = new HashMap<>();
notification.put("application", application);
notification.put("receivers", receivers);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Map<String, Object>> request = new HttpEntity<>(notification, headers);
restTemplate.postForObject(url, request, String.class);
}
}
package cz.muni.pa165.service;
import cz.muni.pa165.data.enums.ApplicationStatusEnum;
import cz.muni.pa165.data.model.Application;
import cz.muni.pa165.data.repository.ApplicationRepository;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
/**
* @author Michal Badin
*/
@Service
@Profile("dev")
public class DBManagementService {
private final ApplicationRepository applicationRepository;
@Autowired
public DBManagementService(ApplicationRepository applicationRepository) {
this.applicationRepository = applicationRepository;
}
@Transactional
@PostConstruct
public void seed() {
saveApplication(ApplicationStatusEnum.PENDING,
"Marek",
"Mrkvicka",
"marek.mrkvicka@example.com",
LocalDate.of(1999, 3, 8),
LocalDate.now());
saveApplication(ApplicationStatusEnum.ACCEPTED,
"Anuja",
"Ankska",
"ankska.anuja@example.com",
LocalDate.of(2000, 1, 30),
LocalDate.of(2010, 7, 18));
saveApplication(ApplicationStatusEnum.ACCEPTED,
"Xiao",
"Chen",
"xiao.chen@example.com",
LocalDate.of(1995, 7, 29),
LocalDate.of(2012, 10, 9));
saveApplication(ApplicationStatusEnum.REJECTED,
"Gertruda",
"Fialkova",
"gertruda.fialkova@example.com",
LocalDate.of(1965, 6, 2),
LocalDate.of(2023, 4, 26));
}
private void saveApplication(ApplicationStatusEnum status, String name, String surname, String email, LocalDate birthday, LocalDate fillingOutDate) {
Application application = new Application(status, name, surname, birthday, email, fillingOutDate);
applicationRepository.save(application);
}
@Transactional
public void clear() {
applicationRepository.deleteAll();
}
}
......@@ -10,4 +10,10 @@ spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.show-sql=true
spring.jackson.property-naming-strategy=SNAKE_CASE
spring.cache.type=NONE
appconfig.enablecache=false
\ No newline at end of file
spring.profiles.active=dev
appconfig.enablecache=false
management.endpoints.web.exposure.include=health,metrics,loggers,beans,prometheus
management.endpoint.health.show-details=always
management.endpoint.health.show-components=always
management.endpoint.health.probes.enabled=true
\ No newline at end of file
package cz.muni.pa165.rest;
package cz.muni.pa165;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
......@@ -7,6 +7,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import java.time.LocalDate;
......@@ -21,9 +22,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
*/
@SpringBootTest
@AutoConfigureMockMvc
class IntegrationTests {
@ActiveProfiles("test")
class ApplicationIT {
private static final Logger log = LoggerFactory.getLogger(IntegrationTests.class);
private static final Logger log = LoggerFactory.getLogger(ApplicationIT.class);
@Autowired
private MockMvc mockMvc;
......@@ -32,7 +34,7 @@ class IntegrationTests {
void testCreateApplication() throws Exception {
log.info("testApplicationModuleResponse() running");
String testRequestContent = "{\"name\":\"John\",\"surname\":\"Doe\",\"birthday\":\"2000-01-01\"}";
String testRequestContent = "{\"name\":\"John\",\"surname\":\"Doe\",\"birthday\":\"2000-01-01\",\"email\":\"john.doe@aaa.com\"}";
String response = mockMvc.perform(
post("/application")
......@@ -43,7 +45,7 @@ class IntegrationTests {
.andReturn().getResponse().getContentAsString();
log.info("response: {}", response);
String expectedResponse = "{\"id\":1,\"name\":\"John\",\"surname\":\"Doe\",\"birthday\":\"2000-01-01\",\"fillingOutDate\":\"" + LocalDate.now() + "\",\"status\":null}";
String expectedResponse = "{\"id\":1,\"name\":\"John\",\"surname\":\"Doe\",\"birthday\":\"2000-01-01\",\"email\":\"john.doe@aaa.com\",\"fillingOutDate\":\"" + LocalDate.now() + "\",\"status\":\"pending\"}";
assertEquals(expectedResponse, response);
}
......
......@@ -7,6 +7,7 @@ import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.test.context.ActiveProfiles;
class ApplicationControllerTest {
......
......@@ -6,6 +6,8 @@ import cz.muni.pa165.data.repository.ApplicationRepository;
import cz.muni.pa165.exceptions.ResourceNotFoundException;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.web.client.RestTemplate;
import java.time.LocalDate;
import java.util.Optional;
......@@ -16,8 +18,10 @@ import static org.mockito.Mockito.when;
class ApplicationServiceTest {
ApplicationRepository applicationRepository = Mockito.mock(ApplicationRepository.class);
ApplicationService service = new ApplicationService(applicationRepository);
Application application = new Application(ApplicationStatusEnum.ACCEPTED, "John", "Doe", LocalDate.now().minusYears(20), LocalDate.now());
RestTemplate restTemplate = Mockito.mock(RestTemplate.class);
ApplicationService service = new ApplicationService(applicationRepository, restTemplate);
Application application = new Application(ApplicationStatusEnum.ACCEPTED, "John", "Doe",
LocalDate.now().minusYears(20), "john.doe@example.com", LocalDate.now());
@Test
......@@ -27,11 +31,13 @@ class ApplicationServiceTest {
Application created = service.create(application);
assertEquals(application, created);
assertEquals(ApplicationStatusEnum.PENDING, created.getStatus());
}
@Test
void setStatus() {
Application expected = new Application(ApplicationStatusEnum.REJECTED, "John", "Doe", LocalDate.now().minusYears(20), LocalDate.now());
Application expected = new Application(ApplicationStatusEnum.REJECTED, "John", "Doe",
LocalDate.now().minusYears(20), "john.doe@example.com", LocalDate.now());
when(applicationRepository.save(application)).thenReturn(expected);
when(applicationRepository.findById(application.getId())).thenReturn(java.util.Optional.ofNullable(application));
......@@ -44,7 +50,7 @@ class ApplicationServiceTest {
void setStatusUnknownApplication() {
when(applicationRepository.findById(application.getId())).thenReturn(Optional.empty());
assertThrows(ResourceNotFoundException.class, () -> service.setStatus(application.getId(), ApplicationStatusEnum.REJECTED));
assertThrows(ResourceNotFoundException.class,
() -> service.setStatus(application.getId(), ApplicationStatusEnum.REJECTED));
}
}
\ No newline at end of file
spring.datasource.url=jdbc:h2:mem:testApplicationdb;MODE=PostgreSQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.url=jdbc:h2:mem:testApplicationdb;MODE=PostgreSQL;DB_CLOSE_DELAY=-1;
spring.datasource.username=formulky-application-test
spring.datasource.password=
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.hibernate.ddl-auto=create
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.jpa.properties.hibernate.generate_statistics=true
spring.jpa.properties.hibernate.format_sql=true
......
......@@ -47,6 +47,7 @@ components:
type: string
description: Specific information about component
example: lightweight front wing v2 (black)
maxLength: 100
CarComponentCreateDto:
type: object
properties:
......@@ -58,6 +59,7 @@ components:
information:
type: string
description: Specific information about component
maxLength: 100
required:
- componentType
- weight
......@@ -69,10 +71,11 @@ components:
$ref: '#/components/schemas/CarComponentType'
weight:
type: number
description: car's weight
description: car component's weight
information:
type: string
description: Specific information about component
maxLength: 100
CarDto:
type: object
......@@ -130,10 +133,12 @@ components:
type: string
description: Name of the driver
example: Max
maxLength: 35
surname:
type: string
description: Surname of the driver
example: Verstappen
maxLength: 35
height:
type: integer
description: Height in cm
......@@ -147,6 +152,7 @@ components:
type: string
description: Nationality of the driver
example: Dutch
maxLength: 20
characteristics:
type: array
description: Set of driver's characteristics
......@@ -158,12 +164,15 @@ components:
name:
type: string
description: Name of the driver
maxLength: 35
surname:
type: string
description: Name of the driver
maxLength: 35
nationality:
type: string
description: nationality of the driver
maxLength: 20
height:
type: integer
description: Height in cm
......@@ -178,12 +187,15 @@ components:
name:
type: string
description: Name of the driver
maxLength: 35
surname:
type: string
description: Name of the driver
maxLength: 35
nationality:
type: string
description: Nationality of the driver
maxLength: 20
height:
type: integer
description: Height in cm
......@@ -220,10 +232,12 @@ components:
type: string
description: Name of the engineer
example: John
maxLength: 35
surname:
type: string
description: Surname of the engineer
example: Doe
maxLength: 35
EngineerCreateDto:
type: object
title: Engineer
......@@ -236,10 +250,12 @@ components:
type: string
description: Name of the engineer
example: John
maxLength: 35
surname:
type: string
description: Surname of the engineer
example: Doe
maxLength: 35
DepartmentDto:
type: object
......@@ -259,6 +275,7 @@ components:
specialization:
type: string
example: "Aerodynamics"
maxLength: 100
DepartmentUpdateDto:
type: object
properties:
......@@ -266,6 +283,7 @@ components:
type: string
example: "Aerodynamics"
description: New specialization
maxLength: 100
required:
- specialization
DepartmentCreateDto:
......@@ -274,6 +292,7 @@ components:
specialization:
type: string
example: "Aerodynamics"
maxLength: 100
required:
- specialization
Pageable:
......@@ -347,6 +366,16 @@ components:
properties:
message:
type: string
Successful:
description: Successfully processed
content:
application/json:
schema:
type: object
title: Successfully processed
properties:
message:
type: string
paths:
/driver:
......@@ -949,3 +978,26 @@ paths:
$ref: '#/components/responses/NotFound'
default:
$ref: '#/components/responses/Unexpected'
/seed:
post:
tags:
- DBManagementService
summary: Seed DB with data
operationId: seedDB
responses:
"200":
$ref: '#/components/responses/Successful'
default:
$ref: '#/components/responses/Unexpected'
/clear:
post:
tags:
- DBManagementService
summary: Clear DB
operationId: clearDB
responses:
"200":
$ref: '#/components/responses/Successful'
default:
$ref: '#/components/responses/Unexpected'
......@@ -159,6 +159,18 @@
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<!-- Actuator dependency-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Prometheus dependency -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package cz.muni.pa165.actuator;
import org.springframework.boot.actuate.info.Info;
import org.springframework.boot.actuate.info.InfoContributor;
import org.springframework.stereotype.Component;
@Component
public class CustomInfoContributor implements InfoContributor {
@Override
public void contribute(Info.Builder builder) {
builder.withDetail("course", "PA165").withDetail("module", "core").build();
}
}
......@@ -11,7 +11,7 @@ import java.util.Set;
@Entity
@Table(name = "car")
public class Car extends DomainObject implements Serializable {
public class Car extends DomainObject<Long> implements Serializable {
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "driver_id")
@Nullable
......