diff --git a/.gitignore b/.gitignore
index bb3186038..f787dd454 100644
--- a/.gitignore
+++ b/.gitignore
@@ -354,6 +354,9 @@ scripts/dockerize/dockerfiles
/jdk_21_maven/cs/rest/testing-system/target/
/jdk_21_maven/em/external/rest/testing-system/target/
/jdk_21_maven/em/embedded/rest/testing-system/target/
+/jdk_21_maven/cs/rest/flight-search-api/target/
+/jdk_21_maven/em/external/rest/flight-search-api/target/
+/jdk_21_maven/em/embedded/rest/flight-search-api/target/
/jdk_11_maven/em/embedded/rest/tracking-system/target/
/jdk_11_maven/em/external/rest/tracking-system/target/
/jdk_17_maven/em/embedded/rest/tiltaksgjennomforing/target/
diff --git a/README.md b/README.md
index f612246d4..31e94118d 100644
--- a/README.md
+++ b/README.md
@@ -85,7 +85,7 @@ How to setup authentication information, based on the current content of the ini
Auth configuration files can found in the [auth](auth) folder.
-### REST: Java/Kotlin (52)
+### REST: Java/Kotlin (53)
* **AdoptMe** (not-known license), [jdk_21_maven/cs/rest/adoptme](jdk_21_maven/cs/rest/adoptme), from [https://github.com/daanimelian/Programacion3-TPO](https://github.com/daanimelian/Programacion3-TPO)
@@ -109,6 +109,8 @@ Auth configuration files can found in the [auth](auth) folder.
* **Features-Service** (Apache), [jdk_8_maven/cs/rest/original/features-service](jdk_8_maven/cs/rest/original/features-service), from [https://github.com/JavierMF/features-service](https://github.com/JavierMF/features-service)
+* **Flight Search API** (MIT), [jdk_21_maven/cs/rest/flight-search-api](jdk_21_maven/cs/rest/flight-search-api), from [https://github.com/Rapter1990/flightsearchapi](https://github.com/Rapter1990/flightsearchapi)
+
* **GDPR-KV** (not-known license), [jdk_21_gradle/cs/rest/gdpr-kv](jdk_21_gradle/cs/rest/gdpr-kv), from [https://github.com/jessicant/GDPR-KV](https://github.com/jessicant/GDPR-KV)
* **Genome Nexus** (MIT), [jdk_8_maven/cs/rest-gui/genome-nexus](jdk_8_maven/cs/rest-gui/genome-nexus), from [https://github.com/genome-nexus/genome-nexus](https://github.com/genome-nexus/genome-nexus)
diff --git a/auth/flight-search-api-auth.yaml b/auth/flight-search-api-auth.yaml
new file mode 100644
index 000000000..e45f2ef0d
--- /dev/null
+++ b/auth/flight-search-api-auth.yaml
@@ -0,0 +1,25 @@
+auth:
+ - name: WfdAdmin1
+ loginEndpointAuth:
+ payloadRaw: "{\"email\": \"wfd_admin1@wfd.invalid\", \"password\": \"Wfd-Admin-Pass1\"}"
+ - name: WfdAdmin2
+ loginEndpointAuth:
+ payloadRaw: "{\"email\": \"wfd_admin2@wfd.invalid\", \"password\": \"Wfd-Admin-Pass2\"}"
+ - name: WfdUser1
+ loginEndpointAuth:
+ payloadRaw: "{\"email\": \"wfd_user1@wfd.invalid\", \"password\": \"Wfd-User-Pass1\"}"
+ - name: WfdUser2
+ loginEndpointAuth:
+ payloadRaw: "{\"email\": \"wfd_user2@wfd.invalid\", \"password\": \"Wfd-User-Pass2\"}"
+
+authTemplate:
+ loginEndpointAuth:
+ endpoint: /api/v1/authentication/user/login
+ verb: POST
+ contentType: application/json
+ token:
+ extractFrom: body
+ extractSelector: /response/accessToken
+ sendName: Authorization
+ sendIn: header
+ sendTemplate: "Bearer {token}"
diff --git a/dockerfiles/additional_files/flight-search-api/flight-search-api-mongo-seed.js b/dockerfiles/additional_files/flight-search-api/flight-search-api-mongo-seed.js
new file mode 100644
index 000000000..ade1d14c6
--- /dev/null
+++ b/dockerfiles/additional_files/flight-search-api/flight-search-api-mongo-seed.js
@@ -0,0 +1,19 @@
+// MODIFIED (WFD-added, not part of the original SUT): the same four accounts the drivers seed.
+// Airports and flights are left for the search to create (the SUT's own loader is never scheduled).
+db = db.getSiblingDB('flightdatabase');
+
+const user = function (id, hash, type) {
+ return {
+ "_id": id, "EMAIL": id + "@wfd.invalid", "PASSWORD": hash,
+ "FIRST_NAME": id, "LAST_NAME": id, "PHONE_NUMBER": "05550000000",
+ "USER_TYPE": type, "USER_STATUS": "ACTIVE",
+ "_class": "com.example.demo.auth.model.entity.UserEntity"
+ };
+};
+
+db.getCollection('user-collection').insertMany([
+ user("wfd_admin1", "$2a$10$2xOaY0XmjU8VrHnQ6ORmme.4pAD21fsnoM9dcf8Y8NYwmXZztsDsC", "ADMIN"), // Wfd-Admin-Pass1
+ user("wfd_admin2", "$2a$10$qKrL3SboXVhfaaevAMiU.eFAj1wD4.X2VVvI.XSmjVlTPf8.95Z9y", "ADMIN"), // Wfd-Admin-Pass2
+ user("wfd_user1", "$2a$10$t.OcuL3NBcdCtRCUtX4SiuG6RPgGxs0yQpdvVl11J0Mv249/vu9Za", "USER"), // Wfd-User-Pass1
+ user("wfd_user2", "$2a$10$1WlQAEEMP97IO1o8vLl3ROrLeF9hdKRjd0yxlOve.ZhF.HCW9rES.", "USER") // Wfd-User-Pass2
+]);
diff --git a/dockerfiles/flight-search-api.dockerfile b/dockerfiles/flight-search-api.dockerfile
new file mode 100644
index 000000000..3eec2caa8
--- /dev/null
+++ b/dockerfiles/flight-search-api.dockerfile
@@ -0,0 +1,13 @@
+FROM amazoncorretto:21-alpine-jdk
+
+COPY ./dist/flight-search-api-sut.jar .
+COPY ./dist/jacocoagent.jar .
+
+
+
+
+ENTRYPOINT \
+ java \
+ -javaagent:jacocoagent.jar=output=tcpserver,address=*,port=6300,append=false,dumponexit=false \
+ -jar flight-search-api-sut.jar \
+ --server.port=8080 --spring.data.mongodb.host=db --spring.data.mongodb.port=27017 --spring.data.mongodb.database=flightdatabase
\ No newline at end of file
diff --git a/dockerfiles/flight-search-api.yaml b/dockerfiles/flight-search-api.yaml
new file mode 100644
index 000000000..1dde012cb
--- /dev/null
+++ b/dockerfiles/flight-search-api.yaml
@@ -0,0 +1,42 @@
+services:
+ mitmproxy:
+ image: mitmproxy/mitmproxy:10.2.4
+ user: "0:0"
+ environment:
+ MITM_LOG_DIR: /custom-logs
+ MITM_LOG_FILE: ${MITM_LOG_FILE:-minlog.csv}
+ command: >
+ mitmdump
+ --mode reverse:http://sut-flight-search-api:8080
+ --listen-host 0.0.0.0
+ --listen-port 8080
+ --set keep_host_header=true
+ -s /addons/minlog.py
+ volumes:
+ - ${HOST_LOG_DIR:-./mitm-logs}:/custom-logs
+ - ./addons:/addons:ro
+ ports:
+ - "${HOST_PORT:-8080}:8080"
+ depends_on:
+ - sut-flight-search-api
+ sut-flight-search-api:
+ image: webfuzzing/wfd-flight-search-api:FINAL
+# build:
+# dockerfile: ./dockerfiles/flight-search-api.dockerfile
+# context: ..
+ environment:
+ AUTH_PORT: ${AUTH_PORT:-8081}
+ ports:
+ - "${JACOCO_PORT:-6300}:6300"
+ depends_on:
+ db:
+ condition: service_healthy
+ db:
+ image: mongo:7
+ volumes:
+ - ./additional_files/flight-search-api/flight-search-api-mongo-seed.js:/docker-entrypoint-initdb.d/flight-search-api-mongo-seed.js
+ healthcheck:
+ test: mongosh --quiet --eval "db.adminCommand('ping')"
+ interval: 30s
+ timeout: 30s
+ retries: 3
\ No newline at end of file
diff --git a/experiments/bb-exp.py b/experiments/bb-exp.py
index 172e96d7d..99a9f6ce3 100644
--- a/experiments/bb-exp.py
+++ b/experiments/bb-exp.py
@@ -86,6 +86,7 @@ def __init__(self, name, auth, sleep, schemaformat, classfiles):
Sut("erc20-rest-service",False,SLEEP,JSON,["jdk_8_gradle/cs/rest/erc20-rest-service/build/classes"]),
Sut("familie-ba-sak",True,SLEEP,JSON,["jdk_17_maven/cs/rest/familie-ba-sak/target/classes"]),
Sut("features-service",False,SLEEP,JSON,["jdk_8_maven/cs/rest/original/features-service/target/classes"]),
+ Sut("flight-search-api",True,SLEEP,JSON,["jdk_21_maven/cs/rest/flight-search-api/target/classes"]),
Sut("gdpr-kv",False,SLEEP,JSON,["jdk_21_gradle/cs/rest/gdpr-kv/build/classes"]),
Sut("traccar",True,SLEEP,JSON,["jdk_21_gradle/cs/rest/traccar/build/classes"]),
Sut("genome-nexus",False,SLEEP,JSON,["jdk_8_maven/cs/rest-gui/genome-nexus/component/target/classes",
diff --git a/experiments/wb-exp.py b/experiments/wb-exp.py
index e48a12926..a7d89d6a9 100644
--- a/experiments/wb-exp.py
+++ b/experiments/wb-exp.py
@@ -193,6 +193,7 @@ def __init__(self, name, platform):
Sut("erc20-rest-service", JDK_8),
Sut("familie-ba-sak",JDK_17),
Sut("features-service", JDK_8),
+ Sut("flight-search-api", JDK_21),
Sut("gdpr-kv", JDK_21),
Sut("traccar", JDK_21),
Sut("genome-nexus", JDK_8),
diff --git a/jacoco.dockerfile b/jacoco.dockerfile
index 1f0bc9a6c..1fe52af9b 100644
--- a/jacoco.dockerfile
+++ b/jacoco.dockerfile
@@ -22,6 +22,7 @@ COPY jdk_11_maven/cs/rest/cwa-verification-server/target/classes ${CLASS_FILES}
COPY jdk_8_gradle/cs/rest/erc20-rest-service/build/classes ${CLASS_FILES}/jdk_8_gradle/cs/rest/erc20-rest-service/build/classes
COPY jdk_17_maven/cs/rest/familie-ba-sak/target/classes ${CLASS_FILES}/jdk_17_maven/cs/rest/familie-ba-sak/target/classes
COPY jdk_8_maven/cs/rest/original/features-service/target/classes ${CLASS_FILES}/jdk_8_maven/cs/rest/original/features-service/target/classes
+COPY jdk_21_maven/cs/rest/flight-search-api/target/classes ${CLASS_FILES}/jdk_21_maven/cs/rest/flight-search-api/target/classes
COPY jdk_21_gradle/cs/rest/gdpr-kv/build/classes ${CLASS_FILES}/jdk_21_gradle/cs/rest/gdpr-kv/build/classes
COPY jdk_8_maven/cs/rest-gui/genome-nexus/component/target/classes ${CLASS_FILES}/jdk_8_maven/cs/rest-gui/genome-nexus/component/target/classes
COPY jdk_8_maven/cs/rest-gui/genome-nexus/model/target/classes ${CLASS_FILES}/jdk_8_maven/cs/rest-gui/genome-nexus/model/target/classes
diff --git a/jdk_21_maven/cs/rest/flight-search-api/pom.xml b/jdk_21_maven/cs/rest/flight-search-api/pom.xml
index 2ba7efd47..9057e3104 100644
--- a/jdk_21_maven/cs/rest/flight-search-api/pom.xml
+++ b/jdk_21_maven/cs/rest/flight-search-api/pom.xml
@@ -32,8 +32,11 @@
0.12.3
1.5.5.Final
0.2.0
- 2.1.0
- 2.1.0
+
+
+ 2.7.0
+ 2.7.0
+
0.8.12
3.5.2
3.5.2
@@ -189,6 +192,12 @@
org.springframework.boot
spring-boot-maven-plugin
+
+
+ flight-search-api
+ sut
+
org.projectlombok
diff --git a/jdk_21_maven/cs/rest/pom.xml b/jdk_21_maven/cs/rest/pom.xml
index fada58e36..94365a121 100644
--- a/jdk_21_maven/cs/rest/pom.xml
+++ b/jdk_21_maven/cs/rest/pom.xml
@@ -21,6 +21,7 @@
lovemining
movies-xml
testing-system
+ flight-search-api
diff --git a/jdk_21_maven/em/embedded/rest/flight-search-api/pom.xml b/jdk_21_maven/em/embedded/rest/flight-search-api/pom.xml
new file mode 100644
index 000000000..cbafe8c03
--- /dev/null
+++ b/jdk_21_maven/em/embedded/rest/flight-search-api/pom.xml
@@ -0,0 +1,48 @@
+
+
+
+ 4.0.0
+
+ evomaster-benchmark-jdk21-em-embedded-rest-flight-search-api
+ jar
+
+
+ org.evomaster
+ evomaster-benchmark-jdk21-em-embedded-rest
+ 4.3.1-SNAPSHOT
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ 3.4.1
+ pom
+ import
+
+
+
+
+
+
+
+ com.case
+ flightsearchapi
+ 0.0.1-SNAPSHOT
+
+
+
+ org.testcontainers
+ testcontainers
+ compile
+
+
+
+ org.mongodb
+ mongodb-driver-sync
+
+
+
+
diff --git a/jdk_21_maven/em/embedded/rest/flight-search-api/src/main/java/em/embedded/com/example/demo/EmbeddedEvoMasterController.java b/jdk_21_maven/em/embedded/rest/flight-search-api/src/main/java/em/embedded/com/example/demo/EmbeddedEvoMasterController.java
new file mode 100644
index 000000000..df3e544d7
--- /dev/null
+++ b/jdk_21_maven/em/embedded/rest/flight-search-api/src/main/java/em/embedded/com/example/demo/EmbeddedEvoMasterController.java
@@ -0,0 +1,189 @@
+package em.embedded.com.example.demo;
+
+import com.example.demo.FlightSearchApiApplication;
+import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoClients;
+import com.mongodb.client.MongoDatabase;
+import org.bson.Document;
+import org.evomaster.client.java.controller.AuthUtils;
+import org.evomaster.client.java.controller.EmbeddedSutController;
+import org.evomaster.client.java.controller.InstrumentedSutStarter;
+import org.evomaster.client.java.controller.api.dto.SutInfoDto;
+import org.evomaster.client.java.controller.api.dto.auth.AuthenticationDto;
+import org.evomaster.client.java.controller.problem.ProblemInfo;
+import org.evomaster.client.java.controller.problem.RestProblem;
+import org.evomaster.client.java.sql.DbSpecification;
+import org.springframework.boot.SpringApplication;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.testcontainers.containers.GenericContainer;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Class used to start/stop the SUT.
+ */
+public class EmbeddedEvoMasterController extends EmbeddedSutController {
+
+ private static final String MONGODB_IMAGE = "mongo:7";
+
+ private static final int MONGODB_PORT = 27017;
+
+ private static final String MONGODB_DATABASE = "flightdatabase";
+
+ // The DB starts empty (the flight loader is never scheduled); airports and flights can be created via the API
+ private static final List USERS = List.of(
+ user("wfd_admin1", "$2a$10$2xOaY0XmjU8VrHnQ6ORmme.4pAD21fsnoM9dcf8Y8NYwmXZztsDsC", "ADMIN"),
+ user("wfd_admin2", "$2a$10$qKrL3SboXVhfaaevAMiU.eFAj1wD4.X2VVvI.XSmjVlTPf8.95Z9y", "ADMIN"),
+ user("wfd_user1", "$2a$10$t.OcuL3NBcdCtRCUtX4SiuG6RPgGxs0yQpdvVl11J0Mv249/vu9Za", "USER"),
+ user("wfd_user2", "$2a$10$1WlQAEEMP97IO1o8vLl3ROrLeF9hdKRjd0yxlOve.ZhF.HCW9rES.", "USER")
+ );
+
+ private static Document user(String id, String passwordHash, String type) {
+ return new Document("_id", id)
+ .append("EMAIL", id + "@wfd.invalid")
+ .append("PASSWORD", passwordHash)
+ .append("FIRST_NAME", id)
+ .append("LAST_NAME", id)
+ .append("PHONE_NUMBER", "05550000000")
+ .append("USER_TYPE", type)
+ .append("USER_STATUS", "ACTIVE")
+ .append("_class", "com.example.demo.auth.model.entity.UserEntity");
+ }
+
+ private static final GenericContainer mongodb = new GenericContainer(MONGODB_IMAGE)
+ .withExposedPorts(MONGODB_PORT);
+
+ public static void main(String[] args) {
+
+ int port = 40100;
+ if (args.length > 0) {
+ port = Integer.parseInt(args[0]);
+ }
+
+ EmbeddedEvoMasterController controller = new EmbeddedEvoMasterController(port);
+ InstrumentedSutStarter starter = new InstrumentedSutStarter(controller);
+
+ starter.start();
+ }
+
+ private ConfigurableApplicationContext ctx;
+
+ private MongoClient mongoClient;
+
+ public EmbeddedEvoMasterController() {
+ this(0);
+ }
+
+ public EmbeddedEvoMasterController(int port) {
+ setControllerPort(port);
+ }
+
+ @Override
+ public String startSut() {
+
+ mongodb.start();
+ mongoClient = MongoClients.create("mongodb://" + mongodb.getHost() + ":" + mongodb.getMappedPort(MONGODB_PORT));
+ seedUsers();
+
+ ctx = SpringApplication.run(FlightSearchApiApplication.class, new String[]{
+ "--server.port=0",
+ "--spring.data.mongodb.host=" + mongodb.getHost(),
+ "--spring.data.mongodb.port=" + mongodb.getMappedPort(MONGODB_PORT),
+ "--spring.data.mongodb.database=" + MONGODB_DATABASE
+ });
+
+ return "http://localhost:" + getSutPort();
+ }
+
+ private void seedUsers() {
+ List users = new ArrayList<>();
+ for (Document u : USERS) {
+ users.add(new Document(u));
+ }
+ mongoClient.getDatabase(MONGODB_DATABASE).getCollection("user-collection").insertMany(users);
+ }
+
+ protected int getSutPort() {
+ return (Integer) ((Map) ctx.getEnvironment()
+ .getPropertySources().get("server.ports").getSource())
+ .get("local.server.port");
+ }
+
+ @Override
+ public boolean isSutRunning() {
+ return ctx != null && ctx.isRunning();
+ }
+
+ @Override
+ public void stopSut() {
+ if (ctx != null) {
+ ctx.stop();
+ ctx.close();
+ ctx = null;
+ }
+ if (mongoClient != null) {
+ mongoClient.close();
+ mongoClient = null;
+ }
+ mongodb.stop();
+ }
+
+ @Override
+ public String getPackagePrefixesToCover() {
+ return "com.example.demo.";
+ }
+
+ @Override
+ public void resetStateOfSUT() {
+ MongoDatabase db = mongoClient.getDatabase(MONGODB_DATABASE);
+ for (String name : db.listCollectionNames()) {
+ db.getCollection(name).deleteMany(new Document());
+ }
+ seedUsers();
+ }
+
+ @Override
+ public Object getMongoConnection() {
+ return mongoClient;
+ }
+
+ @Override
+ public List getDbSpecifications() {
+ return null;
+ }
+
+ private static AuthenticationDto login(String name, String email, String password) {
+ return AuthUtils.getForJsonTokenBearer(
+ name,
+ "/api/v1/authentication/user/login",
+ "{\"email\": \"" + email + "\", \"password\": \"" + password + "\"}",
+ "/response/accessToken"
+ );
+ }
+
+ @Override
+ public List getInfoForAuthentication() {
+ return List.of(
+ login("WfdAdmin1", "wfd_admin1@wfd.invalid", "Wfd-Admin-Pass1"),
+ login("WfdAdmin2", "wfd_admin2@wfd.invalid", "Wfd-Admin-Pass2"),
+ login("WfdUser1", "wfd_user1@wfd.invalid", "Wfd-User-Pass1"),
+ login("WfdUser2", "wfd_user2@wfd.invalid", "Wfd-User-Pass2")
+ );
+ }
+
+ @Override
+ public ProblemInfo getProblemInfo() {
+ return new RestProblem(
+ "http://localhost:" + getSutPort() + "/v3/api-docs",
+ null
+ );
+ }
+
+ @Override
+ public SutInfoDto.OutputFormat getPreferredOutputFormat() {
+ return SutInfoDto.OutputFormat.JAVA_JUNIT_5;
+ }
+
+}
diff --git a/jdk_21_maven/em/embedded/rest/pom.xml b/jdk_21_maven/em/embedded/rest/pom.xml
index f25c2703d..ba4c6e908 100644
--- a/jdk_21_maven/em/embedded/rest/pom.xml
+++ b/jdk_21_maven/em/embedded/rest/pom.xml
@@ -20,6 +20,7 @@
lovemining
movies-xml
testing-system
+ flight-search-api
diff --git a/jdk_21_maven/em/external/rest/flight-search-api/pom.xml b/jdk_21_maven/em/external/rest/flight-search-api/pom.xml
new file mode 100644
index 000000000..049fefec4
--- /dev/null
+++ b/jdk_21_maven/em/external/rest/flight-search-api/pom.xml
@@ -0,0 +1,87 @@
+
+
+
+ 4.0.0
+
+ evomaster-benchmark-jdk21-em-external-rest-flight-search-api
+ jar
+
+
+ org.evomaster
+ evomaster-benchmark-jdk21-em-external-rest
+ 4.3.1-SNAPSHOT
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ 3.4.1
+ pom
+ import
+
+
+
+
+
+
+ org.testcontainers
+ testcontainers
+ compile
+
+
+
+ org.mongodb
+ mongodb-driver-sync
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.6.2
+
+
+ package
+
+ shade
+
+
+ flight-search-api-evomaster-runner
+
+
+
+ em.external.com.example.demo.ExternalEvoMasterController
+
+ org.evomaster.client.java.instrumentation.InstrumentingAgent
+
+ org.evomaster.client.java.instrumentation.InstrumentingAgent
+
+ true
+ true
+
+
+
+
+
+ org.slf4j
+ shaded.emb.org.slf4j
+
+
+ com.fasterxml.jackson.annotation
+ shaded.emb.com.fasterxml.jackson.annotation
+
+
+
+
+
+
+
+
+
diff --git a/jdk_21_maven/em/external/rest/flight-search-api/src/main/java/em/external/com/example/demo/ExternalEvoMasterController.java b/jdk_21_maven/em/external/rest/flight-search-api/src/main/java/em/external/com/example/demo/ExternalEvoMasterController.java
new file mode 100644
index 000000000..fdff4fedf
--- /dev/null
+++ b/jdk_21_maven/em/external/rest/flight-search-api/src/main/java/em/external/com/example/demo/ExternalEvoMasterController.java
@@ -0,0 +1,242 @@
+package em.external.com.example.demo;
+
+import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoClients;
+import com.mongodb.client.MongoDatabase;
+import org.bson.Document;
+import org.evomaster.client.java.controller.AuthUtils;
+import org.evomaster.client.java.controller.ExternalSutController;
+import org.evomaster.client.java.controller.InstrumentedSutStarter;
+import org.evomaster.client.java.controller.api.dto.SutInfoDto;
+import org.evomaster.client.java.controller.api.dto.auth.AuthenticationDto;
+import org.evomaster.client.java.controller.problem.ProblemInfo;
+import org.evomaster.client.java.controller.problem.RestProblem;
+import org.evomaster.client.java.sql.DbSpecification;
+import org.testcontainers.containers.GenericContainer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ExternalEvoMasterController extends ExternalSutController {
+
+ private static final int DEFAULT_CONTROLLER_PORT = 40100;
+
+ private static final int DEFAULT_SUT_PORT = 12345;
+
+ private static final String MONGODB_IMAGE = "mongo:7";
+
+ private static final int MONGODB_PORT = 27017;
+
+ private static final String MONGODB_DATABASE = "flightdatabase";
+
+ // The DB starts empty (the flight loader is never scheduled); airports and flights can be created via the API
+ private static final List USERS = List.of(
+ user("wfd_admin1", "$2a$10$2xOaY0XmjU8VrHnQ6ORmme.4pAD21fsnoM9dcf8Y8NYwmXZztsDsC", "ADMIN"),
+ user("wfd_admin2", "$2a$10$qKrL3SboXVhfaaevAMiU.eFAj1wD4.X2VVvI.XSmjVlTPf8.95Z9y", "ADMIN"),
+ user("wfd_user1", "$2a$10$t.OcuL3NBcdCtRCUtX4SiuG6RPgGxs0yQpdvVl11J0Mv249/vu9Za", "USER"),
+ user("wfd_user2", "$2a$10$1WlQAEEMP97IO1o8vLl3ROrLeF9hdKRjd0yxlOve.ZhF.HCW9rES.", "USER")
+ );
+
+ private static Document user(String id, String passwordHash, String type) {
+ return new Document("_id", id)
+ .append("EMAIL", id + "@wfd.invalid")
+ .append("PASSWORD", passwordHash)
+ .append("FIRST_NAME", id)
+ .append("LAST_NAME", id)
+ .append("PHONE_NUMBER", "05550000000")
+ .append("USER_TYPE", type)
+ .append("USER_STATUS", "ACTIVE")
+ .append("_class", "com.example.demo.auth.model.entity.UserEntity");
+ }
+
+ private static final GenericContainer mongodb = new GenericContainer(MONGODB_IMAGE)
+ .withExposedPorts(MONGODB_PORT);
+
+ public static void main(String[] args) {
+
+ int controllerPort = DEFAULT_CONTROLLER_PORT;
+ if (args.length > 0) {
+ controllerPort = Integer.parseInt(args[0]);
+ }
+ int sutPort = DEFAULT_SUT_PORT;
+ if (args.length > 1) {
+ sutPort = Integer.parseInt(args[1]);
+ }
+ String jarLocation = "cs/rest/flight-search-api/target";
+ if (args.length > 2) {
+ jarLocation = args[2];
+ }
+ if (!jarLocation.endsWith(".jar")) {
+ jarLocation += "/flight-search-api-sut.jar";
+ }
+
+ int timeoutSeconds = 120;
+ if (args.length > 3) {
+ timeoutSeconds = Integer.parseInt(args[3]);
+ }
+
+ String command = "java";
+ if (args.length > 4) {
+ command = args[4];
+ }
+
+ ExternalEvoMasterController controller =
+ new ExternalEvoMasterController(controllerPort, jarLocation, sutPort, timeoutSeconds, command);
+
+ controller.setNeedsJdk17Options(true);
+
+ InstrumentedSutStarter starter = new InstrumentedSutStarter(controller);
+
+ starter.start();
+ }
+
+ private final int timeoutSeconds;
+
+ private final int sutPort;
+
+ private String jarLocation;
+
+ private MongoClient mongoClient;
+
+ public ExternalEvoMasterController() {
+ this(DEFAULT_CONTROLLER_PORT, "../target/flight-search-api-sut.jar", DEFAULT_SUT_PORT, 120, "java");
+ }
+
+ public ExternalEvoMasterController(String jarLocation) {
+ this();
+ this.jarLocation = jarLocation;
+ }
+
+ public ExternalEvoMasterController(int controllerPort, String jarLocation, int sutPort, int timeoutSeconds, String command) {
+ this.sutPort = sutPort;
+ this.jarLocation = jarLocation;
+ this.timeoutSeconds = timeoutSeconds;
+
+ setControllerPort(controllerPort);
+ setJavaCommand(command);
+ }
+
+ @Override
+ public String[] getInputParameters() {
+ return new String[]{
+ "--server.port=" + sutPort,
+ "--spring.data.mongodb.host=" + mongodb.getHost(),
+ "--spring.data.mongodb.port=" + mongodb.getMappedPort(MONGODB_PORT),
+ "--spring.data.mongodb.database=" + MONGODB_DATABASE
+ };
+ }
+
+ @Override
+ public String[] getJVMParameters() {
+ return new String[]{};
+ }
+
+ @Override
+ public String getBaseURL() {
+ return "http://localhost:" + sutPort;
+ }
+
+ @Override
+ public String getPathToExecutableJar() {
+ return jarLocation;
+ }
+
+ @Override
+ public String getLogMessageOfInitializedServer() {
+ return "Started FlightSearchApiApplication in ";
+ }
+
+ @Override
+ public long getMaxAwaitForInitializationInSeconds() {
+ return timeoutSeconds;
+ }
+
+ @Override
+ public void preStart() {
+ mongodb.start();
+ mongoClient = MongoClients.create("mongodb://" + mongodb.getHost() + ":" + mongodb.getMappedPort(MONGODB_PORT));
+ seedUsers();
+ }
+
+ private void seedUsers() {
+ List users = new ArrayList<>();
+ for (Document u : USERS) {
+ users.add(new Document(u));
+ }
+ mongoClient.getDatabase(MONGODB_DATABASE).getCollection("user-collection").insertMany(users);
+ }
+
+ @Override
+ public void postStart() {
+ }
+
+ @Override
+ public void preStop() {
+ }
+
+ @Override
+ public void postStop() {
+ if (mongoClient != null) {
+ mongoClient.close();
+ mongoClient = null;
+ }
+ mongodb.stop();
+ }
+
+ @Override
+ public String getPackagePrefixesToCover() {
+ return "com.example.demo.";
+ }
+
+ @Override
+ public void resetStateOfSUT() {
+ MongoDatabase db = mongoClient.getDatabase(MONGODB_DATABASE);
+ for (String name : db.listCollectionNames()) {
+ db.getCollection(name).deleteMany(new Document());
+ }
+ seedUsers();
+ }
+
+ @Override
+ public Object getMongoConnection() {
+ return mongoClient;
+ }
+
+ @Override
+ public List getDbSpecifications() {
+ return null;
+ }
+
+ private static AuthenticationDto login(String name, String email, String password) {
+ return AuthUtils.getForJsonTokenBearer(
+ name,
+ "/api/v1/authentication/user/login",
+ "{\"email\": \"" + email + "\", \"password\": \"" + password + "\"}",
+ "/response/accessToken"
+ );
+ }
+
+ @Override
+ public List getInfoForAuthentication() {
+ return List.of(
+ login("WfdAdmin1", "wfd_admin1@wfd.invalid", "Wfd-Admin-Pass1"),
+ login("WfdAdmin2", "wfd_admin2@wfd.invalid", "Wfd-Admin-Pass2"),
+ login("WfdUser1", "wfd_user1@wfd.invalid", "Wfd-User-Pass1"),
+ login("WfdUser2", "wfd_user2@wfd.invalid", "Wfd-User-Pass2")
+ );
+ }
+
+ @Override
+ public ProblemInfo getProblemInfo() {
+ return new RestProblem(
+ getBaseURL() + "/v3/api-docs",
+ null
+ );
+ }
+
+ @Override
+ public SutInfoDto.OutputFormat getPreferredOutputFormat() {
+ return SutInfoDto.OutputFormat.JAVA_JUNIT_5;
+ }
+
+}
diff --git a/jdk_21_maven/em/external/rest/pom.xml b/jdk_21_maven/em/external/rest/pom.xml
index e23485358..4a6a8fc08 100644
--- a/jdk_21_maven/em/external/rest/pom.xml
+++ b/jdk_21_maven/em/external/rest/pom.xml
@@ -21,6 +21,7 @@
lovemining
movies-xml
testing-system
+ flight-search-api
\ No newline at end of file
diff --git a/openapi/flight-search-api.json b/openapi/flight-search-api.json
new file mode 100644
index 000000000..5ba8aa0ce
--- /dev/null
+++ b/openapi/flight-search-api.json
@@ -0,0 +1,2882 @@
+{
+ "openapi": "3.0.1",
+ "info": {
+ "title": "flightsearchapi",
+ "description": "Case Study - Flight Search Api (Java 21, Spring Boot, Mongodb, JUnit, Spring Security, JWT, Docker, Kubernetes, Prometheus, Grafana, Github Actions (CI/CD) ) ",
+ "contact": {
+ "name": "Sercan Noyan Germiyanoğlu",
+ "url": "https://github.com/Rapter1990/flightsearchapi"
+ },
+ "version": "1.0.0"
+ },
+ "servers": [
+ {
+ "url": "http://localhost:8080",
+ "description": "Generated server url"
+ }
+ ],
+ "tags": [
+ {
+ "name": "Search Flight",
+ "description": "Endpoints for searching flights based on given criteria."
+ },
+ {
+ "name": "Actuator",
+ "description": "Monitor and interact",
+ "externalDocs": {
+ "description": "Spring Boot Actuator Web API Documentation",
+ "url": "https://docs.spring.io/spring-boot/docs/current/actuator-api/html/"
+ }
+ },
+ {
+ "name": "Authentication",
+ "description": "Handles user authentication and authorization operations."
+ },
+ {
+ "name": "Flight Management",
+ "description": "Endpoints for managing flights including creation, retrieval, updating, and deletion."
+ },
+ {
+ "name": "Airport Management",
+ "description": "Endpoints for managing airports including creation, retrieval, updating, and deletion."
+ }
+ ],
+ "paths": {
+ "/api/v1/flights/{id}": {
+ "get": {
+ "tags": [
+ "Flight Management"
+ ],
+ "summary": "Get flight by ID",
+ "description": "Retrieves a flight by its ID. Accessible by both ADMIN and USER roles.",
+ "operationId": "getFlightById",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Flight successfully retrieved",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseFlightResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid flight details provided",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseFlightResponse"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthorized, authentication is required",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseFlightResponse"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Access forbidden",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseFlightResponse"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Airport not found",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseFlightResponse"
+ }
+ }
+ }
+ }
+ }
+ },
+ "put": {
+ "tags": [
+ "Flight Management"
+ ],
+ "summary": "Update an flight",
+ "description": "Updates an existing flight by its ID. Accessible by ADMIN only.",
+ "operationId": "updateFlightById",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UpdateFlightRequest"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Flight successfully updated",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseFlightResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid update details provided",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseFlightResponse"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthorized, authentication is required",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseFlightResponse"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Access forbidden",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseFlightResponse"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Flight not found",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseFlightResponse"
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "Flight Management"
+ ],
+ "summary": "Delete an flight",
+ "description": "Deletes a flight by its ID. Accessible by ADMIN only.",
+ "operationId": "deleteAirportById",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Flight successfully deleted",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseString"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid update details provided",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseString"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthorized, authentication is required",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseString"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Access forbidden",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseString"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Flight not found",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseString"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/airports/{id}": {
+ "get": {
+ "tags": [
+ "Airport Management"
+ ],
+ "summary": "Get airport by ID",
+ "description": "Retrieves an airport by its ID. Accessible by both ADMIN and USER roles.",
+ "operationId": "getAirportById",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Airport successfully retrieved",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseAirportResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid airport details provided",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseAirportResponse"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthorized, authentication is required",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseAirportResponse"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Access forbidden",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseAirportResponse"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Airport not found",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseAirportResponse"
+ }
+ }
+ }
+ }
+ }
+ },
+ "put": {
+ "tags": [
+ "Airport Management"
+ ],
+ "summary": "Update an airport",
+ "description": "Updates an existing airport by its ID. Accessible by ADMIN only.",
+ "operationId": "updateAirportById",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UpdateAirportRequest"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Airport successfully updated",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseAirportResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid update details provided",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseAirportResponse"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthorized, authentication is required",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseAirportResponse"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Access forbidden",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseAirportResponse"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Airport not found",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseAirportResponse"
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "Airport Management"
+ ],
+ "summary": "Delete an airport",
+ "description": "Deletes an airport by its ID. Accessible by ADMIN only.",
+ "operationId": "deleteAirportById_1",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Airport successfully deleted",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseString"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid update details provided",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseString"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthorized, authentication is required",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseString"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Access forbidden",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseString"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Airport not found",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseString"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/flights": {
+ "get": {
+ "tags": [
+ "Flight Management"
+ ],
+ "summary": "Get all flights",
+ "description": "Retrieves a paginated list of flights. Accessible by both ADMIN and USER roles.",
+ "operationId": "getAllFlights",
+ "parameters": [
+ {
+ "name": "request",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/AirportPagingRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Flights successfully retrieved",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseCustomPagingResponseFlightResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid flights details provided",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseCustomPagingResponseFlightResponse"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthorized, authentication is required",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseCustomPagingResponseFlightResponse"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Access forbidden",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseCustomPagingResponseFlightResponse"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Flight not found",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseCustomPagingResponseFlightResponse"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "Flight Management"
+ ],
+ "summary": "Create a new flight",
+ "description": "Creates a new flight and saves it to the database. Accessible by ADMIN only.",
+ "operationId": "createFlight",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CreateFlightRequest"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Flight successfully created",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseString"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid flight details provided",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseString"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthorized, authentication is required",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseString"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Access forbidden",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseString"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/flights/search": {
+ "post": {
+ "tags": [
+ "Search Flight"
+ ],
+ "summary": "Search for flights",
+ "description": "Searches for flights based on departure, arrival airports, departure date, and optionally return date. Accessible by ADMIN and USER roles.",
+ "operationId": "searchFlights",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/SearchFlightRequest"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Flights successfully retrieved",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseCustomPagingResponseFlightResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid search criteria provided",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseCustomPagingResponseFlightResponse"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthorized, authentication is required",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseCustomPagingResponseFlightResponse"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Access forbidden",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseCustomPagingResponseFlightResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/authentication/user/register": {
+ "post": {
+ "tags": [
+ "Authentication"
+ ],
+ "summary": "Register a new user",
+ "description": "Registers a new user in the system.",
+ "operationId": "registerAdmin",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RegisterRequest"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "User successfully registered",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseVoid"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid request data",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseVoid"
+ }
+ }
+ }
+ },
+ "409": {
+ "description": "User already exists",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseVoid"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/authentication/user/refresh-token": {
+ "post": {
+ "tags": [
+ "Authentication"
+ ],
+ "summary": "Refresh access token",
+ "description": "Refreshes an expired access token using a valid refresh token.",
+ "operationId": "refreshToken",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenRefreshRequest"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Token successfully refreshed",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseTokenResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid refresh token",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseTokenResponse"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Refresh token expired or invalid",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseTokenResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/authentication/user/logout": {
+ "post": {
+ "tags": [
+ "Authentication"
+ ],
+ "summary": "Log out a user",
+ "description": "Invalidates the provided token, effectively logging out the user.",
+ "operationId": "logout",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenInvalidateRequest"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Logout successful",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseVoid"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid token provided",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseVoid"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/authentication/user/login": {
+ "post": {
+ "tags": [
+ "Authentication"
+ ],
+ "summary": "User login",
+ "description": "Authenticates a user and returns an access and refresh token.",
+ "operationId": "loginAdmin",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/LoginRequest"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Login successful",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseTokenResponse"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Invalid login credentials",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseTokenResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/airports": {
+ "get": {
+ "tags": [
+ "Airport Management"
+ ],
+ "summary": "Get all airports",
+ "description": "Retrieves a paginated list of airports. Accessible by both ADMIN and USER roles.",
+ "operationId": "getAllAirports",
+ "parameters": [
+ {
+ "name": "request",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/AirportPagingRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Airports successfully retrieved",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseCustomPagingResponseAirportResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid airports details provided",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseCustomPagingResponseAirportResponse"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthorized, authentication is required",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseCustomPagingResponseAirportResponse"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Access forbidden",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseCustomPagingResponseAirportResponse"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Airport not found",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseCustomPagingResponseAirportResponse"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "Airport Management"
+ ],
+ "summary": "Create a new airport",
+ "description": "Creates a new airport and saves it to the database. Accessible by ADMIN only.",
+ "operationId": "createAirport",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CreateAirportRequest"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Airport successfully created",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseString"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid airport details provided",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseString"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthorized, authentication is required",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseString"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Access forbidden",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomResponseString"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/actuator/loggers/{name}": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'loggers-name'",
+ "operationId": "loggerLevels",
+ "parameters": [
+ {
+ "name": "name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/vnd.spring-boot.actuator.v3+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/vnd.spring-boot.actuator.v2+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found"
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'loggers-name'",
+ "operationId": "configureLogLevel",
+ "parameters": [
+ {
+ "name": "name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "string",
+ "enum": [
+ "TRACE",
+ "DEBUG",
+ "INFO",
+ "WARN",
+ "ERROR",
+ "FATAL",
+ "OFF"
+ ]
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "No Content"
+ },
+ "400": {
+ "description": "Bad Request"
+ }
+ }
+ }
+ },
+ "/actuator": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator root web endpoint",
+ "operationId": "links",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/vnd.spring-boot.actuator.v3+json": {
+ "schema": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/components/schemas/Link"
+ }
+ }
+ }
+ },
+ "application/vnd.spring-boot.actuator.v2+json": {
+ "schema": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/components/schemas/Link"
+ }
+ }
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/components/schemas/Link"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/actuator/threaddump": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'threaddump'",
+ "operationId": "threadDump",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "text/plain;charset=UTF-8": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/vnd.spring-boot.actuator.v3+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/vnd.spring-boot.actuator.v2+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/actuator/scheduledtasks": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'scheduledtasks'",
+ "operationId": "scheduledTasks",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/vnd.spring-boot.actuator.v3+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/vnd.spring-boot.actuator.v2+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/actuator/sbom": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'sbom'",
+ "operationId": "sboms",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/vnd.spring-boot.actuator.v3+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/vnd.spring-boot.actuator.v2+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/actuator/sbom/{id}": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'sbom-id'",
+ "operationId": "sbom",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/octet-stream": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found"
+ }
+ }
+ }
+ },
+ "/actuator/prometheus": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'prometheus'",
+ "operationId": "scrape",
+ "parameters": [
+ {
+ "name": "format",
+ "in": "query",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "CONTENT_TYPE_004",
+ "CONTENT_TYPE_OPENMETRICS_100",
+ "CONTENT_TYPE_PROTOBUF"
+ ]
+ }
+ },
+ {
+ "name": "includedNames",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "text/plain;version=0.0.4;charset=utf-8": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/openmetrics-text;version=1.0.0;charset=utf-8": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/actuator/metrics": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'metrics'",
+ "operationId": "listNames",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/vnd.spring-boot.actuator.v3+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/vnd.spring-boot.actuator.v2+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/actuator/metrics/{requiredMetricName}": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'metrics-requiredMetricName'",
+ "operationId": "metric",
+ "parameters": [
+ {
+ "name": "requiredMetricName",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "tag",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/vnd.spring-boot.actuator.v3+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/vnd.spring-boot.actuator.v2+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found"
+ }
+ }
+ }
+ },
+ "/actuator/mappings": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'mappings'",
+ "operationId": "mappings",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/vnd.spring-boot.actuator.v3+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/vnd.spring-boot.actuator.v2+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/actuator/loggers": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'loggers'",
+ "operationId": "loggers",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/vnd.spring-boot.actuator.v3+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/vnd.spring-boot.actuator.v2+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/actuator/info": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'info'",
+ "operationId": "info",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/vnd.spring-boot.actuator.v3+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/vnd.spring-boot.actuator.v2+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/actuator/heapdump": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'heapdump'",
+ "operationId": "heapDump",
+ "parameters": [
+ {
+ "name": "live",
+ "in": "query",
+ "schema": {
+ "type": "boolean"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/octet-stream": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/actuator/health": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'health'",
+ "operationId": "health",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/vnd.spring-boot.actuator.v3+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/vnd.spring-boot.actuator.v2+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/actuator/env": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'env'",
+ "operationId": "environment",
+ "parameters": [
+ {
+ "name": "pattern",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/vnd.spring-boot.actuator.v3+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/vnd.spring-boot.actuator.v2+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/actuator/env/{toMatch}": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'env-toMatch'",
+ "operationId": "environmentEntry",
+ "parameters": [
+ {
+ "name": "toMatch",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/vnd.spring-boot.actuator.v3+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/vnd.spring-boot.actuator.v2+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found"
+ }
+ }
+ }
+ },
+ "/actuator/configprops": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'configprops'",
+ "operationId": "configurationProperties",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/vnd.spring-boot.actuator.v3+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/vnd.spring-boot.actuator.v2+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/actuator/configprops/{prefix}": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'configprops-prefix'",
+ "operationId": "configurationPropertiesWithPrefix",
+ "parameters": [
+ {
+ "name": "prefix",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/vnd.spring-boot.actuator.v3+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/vnd.spring-boot.actuator.v2+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found"
+ }
+ }
+ }
+ },
+ "/actuator/conditions": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'conditions'",
+ "operationId": "conditions",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/vnd.spring-boot.actuator.v3+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/vnd.spring-boot.actuator.v2+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/actuator/caches": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'caches'",
+ "operationId": "caches",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/vnd.spring-boot.actuator.v3+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/vnd.spring-boot.actuator.v2+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'caches'",
+ "operationId": "clearCaches",
+ "responses": {
+ "204": {
+ "description": "No Content"
+ }
+ }
+ }
+ },
+ "/actuator/caches/{cache}": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'caches-cache'",
+ "operationId": "cache",
+ "parameters": [
+ {
+ "name": "cache",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "cacheManager",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/vnd.spring-boot.actuator.v3+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/vnd.spring-boot.actuator.v2+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found"
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'caches-cache'",
+ "operationId": "clearCache",
+ "parameters": [
+ {
+ "name": "cache",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "cacheManager",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "No Content"
+ },
+ "404": {
+ "description": "Not Found"
+ }
+ }
+ }
+ },
+ "/actuator/beans": {
+ "get": {
+ "tags": [
+ "Actuator"
+ ],
+ "summary": "Actuator web endpoint 'beans'",
+ "operationId": "beans",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/vnd.spring-boot.actuator.v3+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/vnd.spring-boot.actuator.v2+json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "UpdateFlightRequest": {
+ "required": [
+ "arrivalTime",
+ "departureTime",
+ "fromAirportId",
+ "price",
+ "toAirportId"
+ ],
+ "type": "object",
+ "properties": {
+ "fromAirportId": {
+ "type": "string"
+ },
+ "toAirportId": {
+ "type": "string"
+ },
+ "departureTime": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "arrivalTime": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "price": {
+ "type": "number",
+ "format": "double"
+ }
+ }
+ },
+ "AirportResponse": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "cityName": {
+ "type": "string"
+ }
+ }
+ },
+ "CustomResponseFlightResponse": {
+ "type": "object",
+ "properties": {
+ "time": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "httpStatus": {
+ "type": "string",
+ "enum": [
+ "100 CONTINUE",
+ "101 SWITCHING_PROTOCOLS",
+ "102 PROCESSING",
+ "103 EARLY_HINTS",
+ "103 CHECKPOINT",
+ "200 OK",
+ "201 CREATED",
+ "202 ACCEPTED",
+ "203 NON_AUTHORITATIVE_INFORMATION",
+ "204 NO_CONTENT",
+ "205 RESET_CONTENT",
+ "206 PARTIAL_CONTENT",
+ "207 MULTI_STATUS",
+ "208 ALREADY_REPORTED",
+ "226 IM_USED",
+ "300 MULTIPLE_CHOICES",
+ "301 MOVED_PERMANENTLY",
+ "302 FOUND",
+ "302 MOVED_TEMPORARILY",
+ "303 SEE_OTHER",
+ "304 NOT_MODIFIED",
+ "305 USE_PROXY",
+ "307 TEMPORARY_REDIRECT",
+ "308 PERMANENT_REDIRECT",
+ "400 BAD_REQUEST",
+ "401 UNAUTHORIZED",
+ "402 PAYMENT_REQUIRED",
+ "403 FORBIDDEN",
+ "404 NOT_FOUND",
+ "405 METHOD_NOT_ALLOWED",
+ "406 NOT_ACCEPTABLE",
+ "407 PROXY_AUTHENTICATION_REQUIRED",
+ "408 REQUEST_TIMEOUT",
+ "409 CONFLICT",
+ "410 GONE",
+ "411 LENGTH_REQUIRED",
+ "412 PRECONDITION_FAILED",
+ "413 PAYLOAD_TOO_LARGE",
+ "413 REQUEST_ENTITY_TOO_LARGE",
+ "414 URI_TOO_LONG",
+ "414 REQUEST_URI_TOO_LONG",
+ "415 UNSUPPORTED_MEDIA_TYPE",
+ "416 REQUESTED_RANGE_NOT_SATISFIABLE",
+ "417 EXPECTATION_FAILED",
+ "418 I_AM_A_TEAPOT",
+ "419 INSUFFICIENT_SPACE_ON_RESOURCE",
+ "420 METHOD_FAILURE",
+ "421 DESTINATION_LOCKED",
+ "422 UNPROCESSABLE_ENTITY",
+ "423 LOCKED",
+ "424 FAILED_DEPENDENCY",
+ "425 TOO_EARLY",
+ "426 UPGRADE_REQUIRED",
+ "428 PRECONDITION_REQUIRED",
+ "429 TOO_MANY_REQUESTS",
+ "431 REQUEST_HEADER_FIELDS_TOO_LARGE",
+ "451 UNAVAILABLE_FOR_LEGAL_REASONS",
+ "500 INTERNAL_SERVER_ERROR",
+ "501 NOT_IMPLEMENTED",
+ "502 BAD_GATEWAY",
+ "503 SERVICE_UNAVAILABLE",
+ "504 GATEWAY_TIMEOUT",
+ "505 HTTP_VERSION_NOT_SUPPORTED",
+ "506 VARIANT_ALSO_NEGOTIATES",
+ "507 INSUFFICIENT_STORAGE",
+ "508 LOOP_DETECTED",
+ "509 BANDWIDTH_LIMIT_EXCEEDED",
+ "510 NOT_EXTENDED",
+ "511 NETWORK_AUTHENTICATION_REQUIRED"
+ ]
+ },
+ "isSuccess": {
+ "type": "boolean"
+ },
+ "response": {
+ "$ref": "#/components/schemas/FlightResponse"
+ }
+ }
+ },
+ "FlightResponse": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "fromAirport": {
+ "$ref": "#/components/schemas/AirportResponse"
+ },
+ "toAirport": {
+ "$ref": "#/components/schemas/AirportResponse"
+ },
+ "departureTime": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "arrivalTime": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "price": {
+ "type": "number",
+ "format": "double"
+ }
+ }
+ },
+ "UpdateAirportRequest": {
+ "required": [
+ "cityName",
+ "name"
+ ],
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "cityName": {
+ "type": "string"
+ }
+ }
+ },
+ "CustomResponseAirportResponse": {
+ "type": "object",
+ "properties": {
+ "time": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "httpStatus": {
+ "type": "string",
+ "enum": [
+ "100 CONTINUE",
+ "101 SWITCHING_PROTOCOLS",
+ "102 PROCESSING",
+ "103 EARLY_HINTS",
+ "103 CHECKPOINT",
+ "200 OK",
+ "201 CREATED",
+ "202 ACCEPTED",
+ "203 NON_AUTHORITATIVE_INFORMATION",
+ "204 NO_CONTENT",
+ "205 RESET_CONTENT",
+ "206 PARTIAL_CONTENT",
+ "207 MULTI_STATUS",
+ "208 ALREADY_REPORTED",
+ "226 IM_USED",
+ "300 MULTIPLE_CHOICES",
+ "301 MOVED_PERMANENTLY",
+ "302 FOUND",
+ "302 MOVED_TEMPORARILY",
+ "303 SEE_OTHER",
+ "304 NOT_MODIFIED",
+ "305 USE_PROXY",
+ "307 TEMPORARY_REDIRECT",
+ "308 PERMANENT_REDIRECT",
+ "400 BAD_REQUEST",
+ "401 UNAUTHORIZED",
+ "402 PAYMENT_REQUIRED",
+ "403 FORBIDDEN",
+ "404 NOT_FOUND",
+ "405 METHOD_NOT_ALLOWED",
+ "406 NOT_ACCEPTABLE",
+ "407 PROXY_AUTHENTICATION_REQUIRED",
+ "408 REQUEST_TIMEOUT",
+ "409 CONFLICT",
+ "410 GONE",
+ "411 LENGTH_REQUIRED",
+ "412 PRECONDITION_FAILED",
+ "413 PAYLOAD_TOO_LARGE",
+ "413 REQUEST_ENTITY_TOO_LARGE",
+ "414 URI_TOO_LONG",
+ "414 REQUEST_URI_TOO_LONG",
+ "415 UNSUPPORTED_MEDIA_TYPE",
+ "416 REQUESTED_RANGE_NOT_SATISFIABLE",
+ "417 EXPECTATION_FAILED",
+ "418 I_AM_A_TEAPOT",
+ "419 INSUFFICIENT_SPACE_ON_RESOURCE",
+ "420 METHOD_FAILURE",
+ "421 DESTINATION_LOCKED",
+ "422 UNPROCESSABLE_ENTITY",
+ "423 LOCKED",
+ "424 FAILED_DEPENDENCY",
+ "425 TOO_EARLY",
+ "426 UPGRADE_REQUIRED",
+ "428 PRECONDITION_REQUIRED",
+ "429 TOO_MANY_REQUESTS",
+ "431 REQUEST_HEADER_FIELDS_TOO_LARGE",
+ "451 UNAVAILABLE_FOR_LEGAL_REASONS",
+ "500 INTERNAL_SERVER_ERROR",
+ "501 NOT_IMPLEMENTED",
+ "502 BAD_GATEWAY",
+ "503 SERVICE_UNAVAILABLE",
+ "504 GATEWAY_TIMEOUT",
+ "505 HTTP_VERSION_NOT_SUPPORTED",
+ "506 VARIANT_ALSO_NEGOTIATES",
+ "507 INSUFFICIENT_STORAGE",
+ "508 LOOP_DETECTED",
+ "509 BANDWIDTH_LIMIT_EXCEEDED",
+ "510 NOT_EXTENDED",
+ "511 NETWORK_AUTHENTICATION_REQUIRED"
+ ]
+ },
+ "isSuccess": {
+ "type": "boolean"
+ },
+ "response": {
+ "$ref": "#/components/schemas/AirportResponse"
+ }
+ }
+ },
+ "CreateFlightRequest": {
+ "required": [
+ "arrivalTime",
+ "departureTime",
+ "fromAirportId",
+ "price",
+ "toAirportId"
+ ],
+ "type": "object",
+ "properties": {
+ "fromAirportId": {
+ "type": "string"
+ },
+ "toAirportId": {
+ "type": "string"
+ },
+ "departureTime": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "arrivalTime": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "price": {
+ "type": "number",
+ "format": "double"
+ }
+ }
+ },
+ "CustomResponseString": {
+ "type": "object",
+ "properties": {
+ "time": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "httpStatus": {
+ "type": "string",
+ "enum": [
+ "100 CONTINUE",
+ "101 SWITCHING_PROTOCOLS",
+ "102 PROCESSING",
+ "103 EARLY_HINTS",
+ "103 CHECKPOINT",
+ "200 OK",
+ "201 CREATED",
+ "202 ACCEPTED",
+ "203 NON_AUTHORITATIVE_INFORMATION",
+ "204 NO_CONTENT",
+ "205 RESET_CONTENT",
+ "206 PARTIAL_CONTENT",
+ "207 MULTI_STATUS",
+ "208 ALREADY_REPORTED",
+ "226 IM_USED",
+ "300 MULTIPLE_CHOICES",
+ "301 MOVED_PERMANENTLY",
+ "302 FOUND",
+ "302 MOVED_TEMPORARILY",
+ "303 SEE_OTHER",
+ "304 NOT_MODIFIED",
+ "305 USE_PROXY",
+ "307 TEMPORARY_REDIRECT",
+ "308 PERMANENT_REDIRECT",
+ "400 BAD_REQUEST",
+ "401 UNAUTHORIZED",
+ "402 PAYMENT_REQUIRED",
+ "403 FORBIDDEN",
+ "404 NOT_FOUND",
+ "405 METHOD_NOT_ALLOWED",
+ "406 NOT_ACCEPTABLE",
+ "407 PROXY_AUTHENTICATION_REQUIRED",
+ "408 REQUEST_TIMEOUT",
+ "409 CONFLICT",
+ "410 GONE",
+ "411 LENGTH_REQUIRED",
+ "412 PRECONDITION_FAILED",
+ "413 PAYLOAD_TOO_LARGE",
+ "413 REQUEST_ENTITY_TOO_LARGE",
+ "414 URI_TOO_LONG",
+ "414 REQUEST_URI_TOO_LONG",
+ "415 UNSUPPORTED_MEDIA_TYPE",
+ "416 REQUESTED_RANGE_NOT_SATISFIABLE",
+ "417 EXPECTATION_FAILED",
+ "418 I_AM_A_TEAPOT",
+ "419 INSUFFICIENT_SPACE_ON_RESOURCE",
+ "420 METHOD_FAILURE",
+ "421 DESTINATION_LOCKED",
+ "422 UNPROCESSABLE_ENTITY",
+ "423 LOCKED",
+ "424 FAILED_DEPENDENCY",
+ "425 TOO_EARLY",
+ "426 UPGRADE_REQUIRED",
+ "428 PRECONDITION_REQUIRED",
+ "429 TOO_MANY_REQUESTS",
+ "431 REQUEST_HEADER_FIELDS_TOO_LARGE",
+ "451 UNAVAILABLE_FOR_LEGAL_REASONS",
+ "500 INTERNAL_SERVER_ERROR",
+ "501 NOT_IMPLEMENTED",
+ "502 BAD_GATEWAY",
+ "503 SERVICE_UNAVAILABLE",
+ "504 GATEWAY_TIMEOUT",
+ "505 HTTP_VERSION_NOT_SUPPORTED",
+ "506 VARIANT_ALSO_NEGOTIATES",
+ "507 INSUFFICIENT_STORAGE",
+ "508 LOOP_DETECTED",
+ "509 BANDWIDTH_LIMIT_EXCEEDED",
+ "510 NOT_EXTENDED",
+ "511 NETWORK_AUTHENTICATION_REQUIRED"
+ ]
+ },
+ "isSuccess": {
+ "type": "boolean"
+ },
+ "response": {
+ "type": "string"
+ }
+ }
+ },
+ "CustomPaging": {
+ "type": "object",
+ "properties": {
+ "pageNumber": {
+ "minimum": 1,
+ "type": "integer",
+ "format": "int32"
+ },
+ "pageSize": {
+ "minimum": 1,
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ },
+ "SearchFlightRequest": {
+ "required": [
+ "departureTime",
+ "fromAirportId",
+ "toAirportId"
+ ],
+ "type": "object",
+ "properties": {
+ "pagination": {
+ "$ref": "#/components/schemas/CustomPaging"
+ },
+ "fromAirportId": {
+ "type": "string"
+ },
+ "toAirportId": {
+ "type": "string"
+ },
+ "departureTime": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "arrivalTime": {
+ "type": "string",
+ "format": "date-time"
+ }
+ }
+ },
+ "CustomPagingResponseFlightResponse": {
+ "type": "object",
+ "properties": {
+ "content": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/FlightResponse"
+ }
+ },
+ "pageNumber": {
+ "type": "integer",
+ "format": "int32"
+ },
+ "pageSize": {
+ "type": "integer",
+ "format": "int32"
+ },
+ "totalElementCount": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "totalPageCount": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ },
+ "CustomResponseCustomPagingResponseFlightResponse": {
+ "type": "object",
+ "properties": {
+ "time": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "httpStatus": {
+ "type": "string",
+ "enum": [
+ "100 CONTINUE",
+ "101 SWITCHING_PROTOCOLS",
+ "102 PROCESSING",
+ "103 EARLY_HINTS",
+ "103 CHECKPOINT",
+ "200 OK",
+ "201 CREATED",
+ "202 ACCEPTED",
+ "203 NON_AUTHORITATIVE_INFORMATION",
+ "204 NO_CONTENT",
+ "205 RESET_CONTENT",
+ "206 PARTIAL_CONTENT",
+ "207 MULTI_STATUS",
+ "208 ALREADY_REPORTED",
+ "226 IM_USED",
+ "300 MULTIPLE_CHOICES",
+ "301 MOVED_PERMANENTLY",
+ "302 FOUND",
+ "302 MOVED_TEMPORARILY",
+ "303 SEE_OTHER",
+ "304 NOT_MODIFIED",
+ "305 USE_PROXY",
+ "307 TEMPORARY_REDIRECT",
+ "308 PERMANENT_REDIRECT",
+ "400 BAD_REQUEST",
+ "401 UNAUTHORIZED",
+ "402 PAYMENT_REQUIRED",
+ "403 FORBIDDEN",
+ "404 NOT_FOUND",
+ "405 METHOD_NOT_ALLOWED",
+ "406 NOT_ACCEPTABLE",
+ "407 PROXY_AUTHENTICATION_REQUIRED",
+ "408 REQUEST_TIMEOUT",
+ "409 CONFLICT",
+ "410 GONE",
+ "411 LENGTH_REQUIRED",
+ "412 PRECONDITION_FAILED",
+ "413 PAYLOAD_TOO_LARGE",
+ "413 REQUEST_ENTITY_TOO_LARGE",
+ "414 URI_TOO_LONG",
+ "414 REQUEST_URI_TOO_LONG",
+ "415 UNSUPPORTED_MEDIA_TYPE",
+ "416 REQUESTED_RANGE_NOT_SATISFIABLE",
+ "417 EXPECTATION_FAILED",
+ "418 I_AM_A_TEAPOT",
+ "419 INSUFFICIENT_SPACE_ON_RESOURCE",
+ "420 METHOD_FAILURE",
+ "421 DESTINATION_LOCKED",
+ "422 UNPROCESSABLE_ENTITY",
+ "423 LOCKED",
+ "424 FAILED_DEPENDENCY",
+ "425 TOO_EARLY",
+ "426 UPGRADE_REQUIRED",
+ "428 PRECONDITION_REQUIRED",
+ "429 TOO_MANY_REQUESTS",
+ "431 REQUEST_HEADER_FIELDS_TOO_LARGE",
+ "451 UNAVAILABLE_FOR_LEGAL_REASONS",
+ "500 INTERNAL_SERVER_ERROR",
+ "501 NOT_IMPLEMENTED",
+ "502 BAD_GATEWAY",
+ "503 SERVICE_UNAVAILABLE",
+ "504 GATEWAY_TIMEOUT",
+ "505 HTTP_VERSION_NOT_SUPPORTED",
+ "506 VARIANT_ALSO_NEGOTIATES",
+ "507 INSUFFICIENT_STORAGE",
+ "508 LOOP_DETECTED",
+ "509 BANDWIDTH_LIMIT_EXCEEDED",
+ "510 NOT_EXTENDED",
+ "511 NETWORK_AUTHENTICATION_REQUIRED"
+ ]
+ },
+ "isSuccess": {
+ "type": "boolean"
+ },
+ "response": {
+ "$ref": "#/components/schemas/CustomPagingResponseFlightResponse"
+ }
+ }
+ },
+ "RegisterRequest": {
+ "required": [
+ "firstName",
+ "lastName",
+ "phoneNumber"
+ ],
+ "type": "object",
+ "properties": {
+ "email": {
+ "maxLength": 2147483647,
+ "minLength": 7,
+ "type": "string"
+ },
+ "password": {
+ "maxLength": 2147483647,
+ "minLength": 8,
+ "type": "string"
+ },
+ "firstName": {
+ "type": "string"
+ },
+ "lastName": {
+ "type": "string"
+ },
+ "phoneNumber": {
+ "maxLength": 20,
+ "minLength": 11,
+ "type": "string"
+ },
+ "userType": {
+ "type": "string",
+ "enum": [
+ "USER",
+ "ADMIN"
+ ]
+ }
+ }
+ },
+ "CustomResponseVoid": {
+ "type": "object",
+ "properties": {
+ "time": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "httpStatus": {
+ "type": "string",
+ "enum": [
+ "100 CONTINUE",
+ "101 SWITCHING_PROTOCOLS",
+ "102 PROCESSING",
+ "103 EARLY_HINTS",
+ "103 CHECKPOINT",
+ "200 OK",
+ "201 CREATED",
+ "202 ACCEPTED",
+ "203 NON_AUTHORITATIVE_INFORMATION",
+ "204 NO_CONTENT",
+ "205 RESET_CONTENT",
+ "206 PARTIAL_CONTENT",
+ "207 MULTI_STATUS",
+ "208 ALREADY_REPORTED",
+ "226 IM_USED",
+ "300 MULTIPLE_CHOICES",
+ "301 MOVED_PERMANENTLY",
+ "302 FOUND",
+ "302 MOVED_TEMPORARILY",
+ "303 SEE_OTHER",
+ "304 NOT_MODIFIED",
+ "305 USE_PROXY",
+ "307 TEMPORARY_REDIRECT",
+ "308 PERMANENT_REDIRECT",
+ "400 BAD_REQUEST",
+ "401 UNAUTHORIZED",
+ "402 PAYMENT_REQUIRED",
+ "403 FORBIDDEN",
+ "404 NOT_FOUND",
+ "405 METHOD_NOT_ALLOWED",
+ "406 NOT_ACCEPTABLE",
+ "407 PROXY_AUTHENTICATION_REQUIRED",
+ "408 REQUEST_TIMEOUT",
+ "409 CONFLICT",
+ "410 GONE",
+ "411 LENGTH_REQUIRED",
+ "412 PRECONDITION_FAILED",
+ "413 PAYLOAD_TOO_LARGE",
+ "413 REQUEST_ENTITY_TOO_LARGE",
+ "414 URI_TOO_LONG",
+ "414 REQUEST_URI_TOO_LONG",
+ "415 UNSUPPORTED_MEDIA_TYPE",
+ "416 REQUESTED_RANGE_NOT_SATISFIABLE",
+ "417 EXPECTATION_FAILED",
+ "418 I_AM_A_TEAPOT",
+ "419 INSUFFICIENT_SPACE_ON_RESOURCE",
+ "420 METHOD_FAILURE",
+ "421 DESTINATION_LOCKED",
+ "422 UNPROCESSABLE_ENTITY",
+ "423 LOCKED",
+ "424 FAILED_DEPENDENCY",
+ "425 TOO_EARLY",
+ "426 UPGRADE_REQUIRED",
+ "428 PRECONDITION_REQUIRED",
+ "429 TOO_MANY_REQUESTS",
+ "431 REQUEST_HEADER_FIELDS_TOO_LARGE",
+ "451 UNAVAILABLE_FOR_LEGAL_REASONS",
+ "500 INTERNAL_SERVER_ERROR",
+ "501 NOT_IMPLEMENTED",
+ "502 BAD_GATEWAY",
+ "503 SERVICE_UNAVAILABLE",
+ "504 GATEWAY_TIMEOUT",
+ "505 HTTP_VERSION_NOT_SUPPORTED",
+ "506 VARIANT_ALSO_NEGOTIATES",
+ "507 INSUFFICIENT_STORAGE",
+ "508 LOOP_DETECTED",
+ "509 BANDWIDTH_LIMIT_EXCEEDED",
+ "510 NOT_EXTENDED",
+ "511 NETWORK_AUTHENTICATION_REQUIRED"
+ ]
+ },
+ "isSuccess": {
+ "type": "boolean"
+ },
+ "response": {
+ "type": "object"
+ }
+ }
+ },
+ "TokenRefreshRequest": {
+ "required": [
+ "refreshToken"
+ ],
+ "type": "object",
+ "properties": {
+ "refreshToken": {
+ "type": "string"
+ }
+ }
+ },
+ "CustomResponseTokenResponse": {
+ "type": "object",
+ "properties": {
+ "time": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "httpStatus": {
+ "type": "string",
+ "enum": [
+ "100 CONTINUE",
+ "101 SWITCHING_PROTOCOLS",
+ "102 PROCESSING",
+ "103 EARLY_HINTS",
+ "103 CHECKPOINT",
+ "200 OK",
+ "201 CREATED",
+ "202 ACCEPTED",
+ "203 NON_AUTHORITATIVE_INFORMATION",
+ "204 NO_CONTENT",
+ "205 RESET_CONTENT",
+ "206 PARTIAL_CONTENT",
+ "207 MULTI_STATUS",
+ "208 ALREADY_REPORTED",
+ "226 IM_USED",
+ "300 MULTIPLE_CHOICES",
+ "301 MOVED_PERMANENTLY",
+ "302 FOUND",
+ "302 MOVED_TEMPORARILY",
+ "303 SEE_OTHER",
+ "304 NOT_MODIFIED",
+ "305 USE_PROXY",
+ "307 TEMPORARY_REDIRECT",
+ "308 PERMANENT_REDIRECT",
+ "400 BAD_REQUEST",
+ "401 UNAUTHORIZED",
+ "402 PAYMENT_REQUIRED",
+ "403 FORBIDDEN",
+ "404 NOT_FOUND",
+ "405 METHOD_NOT_ALLOWED",
+ "406 NOT_ACCEPTABLE",
+ "407 PROXY_AUTHENTICATION_REQUIRED",
+ "408 REQUEST_TIMEOUT",
+ "409 CONFLICT",
+ "410 GONE",
+ "411 LENGTH_REQUIRED",
+ "412 PRECONDITION_FAILED",
+ "413 PAYLOAD_TOO_LARGE",
+ "413 REQUEST_ENTITY_TOO_LARGE",
+ "414 URI_TOO_LONG",
+ "414 REQUEST_URI_TOO_LONG",
+ "415 UNSUPPORTED_MEDIA_TYPE",
+ "416 REQUESTED_RANGE_NOT_SATISFIABLE",
+ "417 EXPECTATION_FAILED",
+ "418 I_AM_A_TEAPOT",
+ "419 INSUFFICIENT_SPACE_ON_RESOURCE",
+ "420 METHOD_FAILURE",
+ "421 DESTINATION_LOCKED",
+ "422 UNPROCESSABLE_ENTITY",
+ "423 LOCKED",
+ "424 FAILED_DEPENDENCY",
+ "425 TOO_EARLY",
+ "426 UPGRADE_REQUIRED",
+ "428 PRECONDITION_REQUIRED",
+ "429 TOO_MANY_REQUESTS",
+ "431 REQUEST_HEADER_FIELDS_TOO_LARGE",
+ "451 UNAVAILABLE_FOR_LEGAL_REASONS",
+ "500 INTERNAL_SERVER_ERROR",
+ "501 NOT_IMPLEMENTED",
+ "502 BAD_GATEWAY",
+ "503 SERVICE_UNAVAILABLE",
+ "504 GATEWAY_TIMEOUT",
+ "505 HTTP_VERSION_NOT_SUPPORTED",
+ "506 VARIANT_ALSO_NEGOTIATES",
+ "507 INSUFFICIENT_STORAGE",
+ "508 LOOP_DETECTED",
+ "509 BANDWIDTH_LIMIT_EXCEEDED",
+ "510 NOT_EXTENDED",
+ "511 NETWORK_AUTHENTICATION_REQUIRED"
+ ]
+ },
+ "isSuccess": {
+ "type": "boolean"
+ },
+ "response": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ },
+ "TokenResponse": {
+ "type": "object",
+ "properties": {
+ "accessToken": {
+ "type": "string"
+ },
+ "accessTokenExpiresAt": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "refreshToken": {
+ "type": "string"
+ }
+ }
+ },
+ "TokenInvalidateRequest": {
+ "required": [
+ "accessToken",
+ "refreshToken"
+ ],
+ "type": "object",
+ "properties": {
+ "accessToken": {
+ "type": "string"
+ },
+ "refreshToken": {
+ "type": "string"
+ }
+ }
+ },
+ "LoginRequest": {
+ "required": [
+ "email",
+ "password"
+ ],
+ "type": "object",
+ "properties": {
+ "email": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ }
+ }
+ },
+ "CreateAirportRequest": {
+ "required": [
+ "cityName",
+ "name"
+ ],
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "cityName": {
+ "type": "string"
+ }
+ }
+ },
+ "AirportPagingRequest": {
+ "type": "object",
+ "properties": {
+ "pagination": {
+ "$ref": "#/components/schemas/CustomPaging"
+ }
+ }
+ },
+ "CustomPagingResponseAirportResponse": {
+ "type": "object",
+ "properties": {
+ "content": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/AirportResponse"
+ }
+ },
+ "pageNumber": {
+ "type": "integer",
+ "format": "int32"
+ },
+ "pageSize": {
+ "type": "integer",
+ "format": "int32"
+ },
+ "totalElementCount": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "totalPageCount": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ },
+ "CustomResponseCustomPagingResponseAirportResponse": {
+ "type": "object",
+ "properties": {
+ "time": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "httpStatus": {
+ "type": "string",
+ "enum": [
+ "100 CONTINUE",
+ "101 SWITCHING_PROTOCOLS",
+ "102 PROCESSING",
+ "103 EARLY_HINTS",
+ "103 CHECKPOINT",
+ "200 OK",
+ "201 CREATED",
+ "202 ACCEPTED",
+ "203 NON_AUTHORITATIVE_INFORMATION",
+ "204 NO_CONTENT",
+ "205 RESET_CONTENT",
+ "206 PARTIAL_CONTENT",
+ "207 MULTI_STATUS",
+ "208 ALREADY_REPORTED",
+ "226 IM_USED",
+ "300 MULTIPLE_CHOICES",
+ "301 MOVED_PERMANENTLY",
+ "302 FOUND",
+ "302 MOVED_TEMPORARILY",
+ "303 SEE_OTHER",
+ "304 NOT_MODIFIED",
+ "305 USE_PROXY",
+ "307 TEMPORARY_REDIRECT",
+ "308 PERMANENT_REDIRECT",
+ "400 BAD_REQUEST",
+ "401 UNAUTHORIZED",
+ "402 PAYMENT_REQUIRED",
+ "403 FORBIDDEN",
+ "404 NOT_FOUND",
+ "405 METHOD_NOT_ALLOWED",
+ "406 NOT_ACCEPTABLE",
+ "407 PROXY_AUTHENTICATION_REQUIRED",
+ "408 REQUEST_TIMEOUT",
+ "409 CONFLICT",
+ "410 GONE",
+ "411 LENGTH_REQUIRED",
+ "412 PRECONDITION_FAILED",
+ "413 PAYLOAD_TOO_LARGE",
+ "413 REQUEST_ENTITY_TOO_LARGE",
+ "414 URI_TOO_LONG",
+ "414 REQUEST_URI_TOO_LONG",
+ "415 UNSUPPORTED_MEDIA_TYPE",
+ "416 REQUESTED_RANGE_NOT_SATISFIABLE",
+ "417 EXPECTATION_FAILED",
+ "418 I_AM_A_TEAPOT",
+ "419 INSUFFICIENT_SPACE_ON_RESOURCE",
+ "420 METHOD_FAILURE",
+ "421 DESTINATION_LOCKED",
+ "422 UNPROCESSABLE_ENTITY",
+ "423 LOCKED",
+ "424 FAILED_DEPENDENCY",
+ "425 TOO_EARLY",
+ "426 UPGRADE_REQUIRED",
+ "428 PRECONDITION_REQUIRED",
+ "429 TOO_MANY_REQUESTS",
+ "431 REQUEST_HEADER_FIELDS_TOO_LARGE",
+ "451 UNAVAILABLE_FOR_LEGAL_REASONS",
+ "500 INTERNAL_SERVER_ERROR",
+ "501 NOT_IMPLEMENTED",
+ "502 BAD_GATEWAY",
+ "503 SERVICE_UNAVAILABLE",
+ "504 GATEWAY_TIMEOUT",
+ "505 HTTP_VERSION_NOT_SUPPORTED",
+ "506 VARIANT_ALSO_NEGOTIATES",
+ "507 INSUFFICIENT_STORAGE",
+ "508 LOOP_DETECTED",
+ "509 BANDWIDTH_LIMIT_EXCEEDED",
+ "510 NOT_EXTENDED",
+ "511 NETWORK_AUTHENTICATION_REQUIRED"
+ ]
+ },
+ "isSuccess": {
+ "type": "boolean"
+ },
+ "response": {
+ "$ref": "#/components/schemas/CustomPagingResponseAirportResponse"
+ }
+ }
+ },
+ "Link": {
+ "type": "object",
+ "properties": {
+ "href": {
+ "type": "string"
+ },
+ "templated": {
+ "type": "boolean"
+ }
+ }
+ }
+ },
+ "securitySchemes": {
+ "bearerAuth": {
+ "type": "http",
+ "description": "JWT Token",
+ "in": "header",
+ "scheme": "bearer",
+ "bearerFormat": "JWT"
+ }
+ }
+ }
+}
diff --git a/scripts/build/docker-compose.build.yml b/scripts/build/docker-compose.build.yml
index e31268086..9d1936296 100644
--- a/scripts/build/docker-compose.build.yml
+++ b/scripts/build/docker-compose.build.yml
@@ -272,6 +272,7 @@ services:
cp cs/rest/lovemining/target/lovemining-sut.jar /dist/
cp cs/rest/movies-xml/target/movies-xml-sut.jar /dist/
cp cs/rest/testing-system/target/testing-system-sut.jar /dist/
+ cp cs/rest/flight-search-api/target/flight-search-api-sut.jar /dist/
cp cs/rest-gui/webgoat/target/webgoat-sut.jar /dist/
cp cs/rest-gui/microcks/webapp/target/microcks-sut.jar /dist/
if [ "$${BUILD_EVOMASTER:-false}" = "true" ]; then
@@ -283,6 +284,7 @@ services:
cp em/external/rest/lovemining/target/lovemining-evomaster-runner.jar /dist/
cp em/external/rest/movies-xml/target/movies-xml-evomaster-runner.jar /dist/
cp em/external/rest/testing-system/target/testing-system-evomaster-runner.jar /dist/
+ cp em/external/rest/flight-search-api/target/flight-search-api-evomaster-runner.jar /dist/
cp em/external/rest-gui/webgoat/target/webgoat-evomaster-runner.jar /dist/
cp em/external/rest-gui/microcks/target/microcks-evomaster-runner.jar /dist/
fi
diff --git a/scripts/dist-wb.py b/scripts/dist-wb.py
index f99c38d09..9f882f45e 100644
--- a/scripts/dist-wb.py
+++ b/scripts/dist-wb.py
@@ -322,6 +322,8 @@ def build_jdk_21_maven():
copy(folder + "/em/external/rest/movies-xml/target/movies-xml-evomaster-runner.jar", DIST)
copy(folder + "/cs/rest/testing-system/target/testing-system-sut.jar", DIST)
copy(folder + "/em/external/rest/testing-system/target/testing-system-evomaster-runner.jar", DIST)
+ copy(folder + "/cs/rest/flight-search-api/target/flight-search-api-sut.jar", DIST)
+ copy(folder + "/em/external/rest/flight-search-api/target/flight-search-api-evomaster-runner.jar", DIST)
copy(folder + "/cs/rest-gui/webgoat/target/webgoat-sut.jar", DIST)
copy(folder + "/em/external/rest-gui/webgoat/target/webgoat-evomaster-runner.jar", DIST)
diff --git a/scripts/dockerize/data/sut.csv b/scripts/dockerize/data/sut.csv
index 889068631..496c0f728 100644
--- a/scripts/dockerize/data/sut.csv
+++ b/scripts/dockerize/data/sut.csv
@@ -51,3 +51,4 @@ kafka-rest,TRUE,-Dorg.apache.logging.log4j.level=INFO,kafka-rest.properties,,htt
management-cassandra,TRUE,-Dmgmtapi.cql.tcp=cassandra:9999,-K true -H tcp://0.0.0.0:8080 -S mgmtapi.sock,http://localhost:8080/openapi.json,http://localhost:8080,FALSE,cassandra,"[{""name"": ""cassandra"", ""image_name"": ""k8ssandra/cass-management-api:4.1.12-v0.1.126"", ""tmp_fs"": """", ""environment"": ""HEAP_NEWSIZE: 128M;MAX_HEAP_SIZE: 512M;JVM_EXTRA_OPTS: -Ddb.unix_socket_file=/tmp/mgmtapi.sock"", ""volume"": ""./additional_files/management-cassandra/mgmtapi-bridge.py:/mgmtapi-bridge.py"", ""health_check_command"": ""test -S /tmp/mgmtapi.sock && cqlsh -e \""SELECT now() FROM system.local\"""", ""command"": ""[\""bash\"", \""-c\"", 'python3 /mgmtapi-bridge.py /tmp/mgmtapi.sock 9999 & exec cassandra -f']""}]"
petclinic-rest,TRUE,,--server.port=8080 --spring.jpa.show-sql=false,http://localhost:8080/petclinic/v3/api-docs,http://localhost:8080,FALSE,,
traccar,TRUE,,traccar.xml,,http://localhost:8080,TRUE,,
+flight-search-api,TRUE,,--server.port=8080 --spring.data.mongodb.host=db --spring.data.mongodb.port=27017 --spring.data.mongodb.database=flightdatabase,http://localhost:8080/v3/api-docs,http://localhost:8080,FALSE,db,"[{""image_name"": ""mongo:7"", ""tmp_fs"": """", ""environment"": """", ""volume"": ""./additional_files/flight-search-api/flight-search-api-mongo-seed.js:/docker-entrypoint-initdb.d/flight-search-api-mongo-seed.js"", ""health_check_command"": ""mongosh --quiet --eval \""db.adminCommand('ping')\""""}]"
diff --git a/statistics/data.csv b/statistics/data.csv
index aeae1ea57..c355ee423 100644
--- a/statistics/data.csv
+++ b/statistics/data.csv
@@ -63,4 +63,5 @@ TRUE,kafka-rest,REST,Java,JDK 17,Maven,475,81418,Kafka,Confluent,50,FALSE,https:
TRUE,management-cassandra,REST,Java,JDK 11,Maven,225,35096,Cassandra,Apache,63,FALSE,https://github.com/k8ssandra/management-api-for-apache-cassandra
TRUE,petclinic-rest,REST,Java,JDK 17,Maven,109,8675,H2,Apache,43,FALSE,https://github.com/spring-petclinic/spring-petclinic-rest
TRUE,traccar,REST,Java,JDK 21,Gradle,1478,141962,H2,Apache,117,TRUE,https://github.com/traccar/traccar
+TRUE,flight-search-api,REST,Java,JDK 21,Maven,194,14440,MongoDB,MIT,40,TRUE,https://github.com/Rapter1990/flightsearchapi
diff --git a/statistics/http-verbs.csv b/statistics/http-verbs.csv
index 449a732fd..de086bdf9 100644
--- a/statistics/http-verbs.csv
+++ b/statistics/http-verbs.csv
@@ -10,6 +10,7 @@ digitalbanking,28,7,6,4,3,3,4,0,0,0
erc20-rest-service,8,0,5,0,0,0,0,0,0,0
familie-ba-sak,66,23,82,10,0,0,2,0,0,0
features-service,6,1,6,5,0,0,0,0,0,0
+flight-search-api,26,2,8,4,0,0,0,0,0,0
gdpr-kv,3,2,0,2,0,0,0,0,0,0
genome-nexus,13,0,10,0,0,0,0,0,0,0
gestaohospital,10,3,5,2,0,0,0,0,0,0
diff --git a/statistics/http-verbs.md b/statistics/http-verbs.md
index 1f0dede4e..e68c1e34c 100644
--- a/statistics/http-verbs.md
+++ b/statistics/http-verbs.md
@@ -11,6 +11,7 @@
| erc20-rest-service | 8 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 13 |
| familie-ba-sak | 66 | 23 | 82 | 10 | 0 | 0 | 2 | 0 | 0 | 0 | 183 |
| features-service | 6 | 1 | 6 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 18 |
+| flight-search-api | 26 | 2 | 8 | 4 | 0 | 0 | 0 | 0 | 0 | 0 | 40 |
| gdpr-kv | 3 | 2 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 7 |
| genome-nexus | 13 | 0 | 10 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 23 |
| gestaohospital | 10 | 3 | 5 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 20 |
@@ -52,4 +53,4 @@
| user-management | 7 | 2 | 7 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 21 |
| webgoat | 50 | 10 | 112 | 8 | 8 | 8 | 8 | 0 | 0 | 0 | 204 |
| youtube-mock | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
-| Total | 1027 | 174 | 755 | 171 | 21 | 20 | 53 | 0 | 0 | 0 | 2221 |
+| Total | 1053 | 176 | 763 | 175 | 21 | 20 | 53 | 0 | 0 | 0 | 2261 |
diff --git a/statistics/table_wfd.md b/statistics/table_wfd.md
index 1e4540669..3da16b539 100644
--- a/statistics/table_wfd.md
+++ b/statistics/table_wfd.md
@@ -19,6 +19,7 @@
|REST|__erc20-rest-service__|1378|7|13|Java|JDK 8|Gradle|||
|REST|__familie-ba-sak__|143556|1089|183|Kotlin|JDK 17|Maven|PostgreSQL|✓|
|REST|__features-service__|2275|39|18|Java|JDK 8|Maven|H2||
+|REST|__flight-search-api__|14440|194|40|Java|JDK 21|Maven|MongoDB|✓|
|REST|__gdpr-kv__|6399|62|7|Java|JDK 21|Gradle|DynamoDB||
|REST|__genome-nexus__|30004|405|23|Java|JDK 8|Maven|MongoDB||
|REST|__gestaohospital__|3506|33|20|Java|JDK 8|Maven|MongoDB||