diff --git a/.jpb/persistence-units.xml b/.jpb/persistence-units.xml deleted file mode 100644 index 06f3b15..0000000 --- a/.jpb/persistence-units.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index 2836e54..2f2accf 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -# Flight Advisor Service ![GitHub release (latest by date)](https://img.shields.io/github/v/release/mohamed-taman/Flight-Advisor) [![Release Codename](https://img.shields.io/badge/codename-Advisor_Enhanced_5.1-yellow.svg)](https://github.com/mohamed-taman/Flight-Advisor/releases) [![Twitter Follow](https://img.shields.io/twitter/follow/_tamanm?label=follow%20me&style=social)](https://twitter.com/_tamanm) Flight Advisor Service is a set of APIs for primarily finding the cheapest flight from city A to City B is based on price, and as a result, it returns all the trip information alongside the distance(s). > This service is a great example of migrating spring boot from the older version **2.7.x** to **3.1.x**. You can check the changes from commit changes of each version release (as code) or release notes as information. And the [**Spring Boot 2.5.x to 3.1.x migration Guide**](https://medium.com/@tamanm/spring-boot-2-x-to-3-1-x-migration-guides-e83380dbc470) would help you in your migration journey. ## System Functionality - This project is developing a layered monolith **Spring Boot** based project (with the latest version **3.1.0-RC1**), on **Java 20**, and with an embedded database mode. - This OAuth2-based project uses a JWT token to secure endpoints and a refresh token to get a new JWT token without login. - Therefore, you need to register first to continue using the system. - The functionality is reached based on user roles, and the system has three roles. - **Admin**: user is a predefined user (*admin@traveladvisor.com/Admin1234*). - Admin needs to log-in first through `/signin` API to get their token to contact the system. - This user can upload airports and flight routes. - Admin manages cities by adding, updating, or deleting them. - Actually, the admin can do anything in the system. - **Client**: Clients should register before using the system through `/signup` public API. - After successful registration, they can use the public `/signin` API to get a token to contact the system successfully. - Client can use all read API calls. - Clients can add, manage their comments for a city, add, update, delete their comments, and see other comments. - Client can get the cheapest flight by calling `/cities/travel` API and providing airport codes for [**from the city**] and [**to the city**]. - **Public**: it is not a role, but anonymous users use APIs under public (*some APIs need access and will be marked as ACCESS REQUIRED*). - Use `/signin` API call to log-in to the system, supplying the username and password. Then you will get a valid JWT token with a longer living refresh token. - Use `/signout` to logout from the system. (**ACCESS REQUIRED**) - Use `/change_password` to change your current password so you will be logged-out, and you need to log-in again to access the system. (**ACCESS REQUIRED**) - Use `/refresh_token` when your access token is expired to get new JWT access and refresh the token with the previous not expired refresh token without login into the system again. (**ACCESS REQUIRED**) - Use `/signup` API call to register as a client to use the system functionalities related to the client; otherwise, the client will receive *Not Authorized*. ## Getting started ### Project Management 1. I have used GitHub projects to manage my tasks in the **Flight-Advisor** project. [Project Link](https://github.com/mohamed-taman/Flight-Advisor/projects/1). 2. All MVP tasks are assigned to the **Flight Advisor API MVP** Milestone. [Milestone Link](https://github.com/mohamed-taman/Flight-Advisor/milestone/1?closed=1). 3. I used pull requests to manage and close assigned tasks. [Tasks Link](https://github.com/mohamed-taman/Flight-Advisor/issues?q=is%3Aclosed). 4. Finally, I have added releases to manage small feature sprints until the final release, v1.0. [Releases Link](https://github.com/mohamed-taman/Flight-Advisor/releases). 5. Have a look at open issues for future enhancements. [Opened Issues](https://github.com/mohamed-taman/Flight-Advisor/issues?q=is%3Aopen). ### System components Structure Let's first explain the system layers structure to understand its components: ``` Flight-Advisor --> Parent folder. |- docs --> Contains system images. |- data --> Contains Airports and routes files. |- frontend --> Contains the frontend UI project. |- src/main/java - org.siriusxi.fa (package) |- FlightAdvisorApplication.java --> The main starting point of the application. |- api --> Contains All REST API controllers that receive requests from the client to process that request and, finally, return appropriate responses. It contains all request and response DTOs. |- repository --> All the database entities CRUD management services. |- domain --> Domain contains all the database-modeled entities. |- infra --> Contains all the configurations, exceptions, security management, support utilities, and dto <--> entities mappers for the system support. |- service --> Contains all the system business login, receives calls from Controllers, calls the repository to retrieve and manage data, then processes them to return to the controllers. ``` Now, as we have learned about different system layers and components, so it is time then to play, let's play. ## Playing With Flight Advisor Service First things first, you need to download the following pieces of software to have fun with the project: ### Required software The following are the initially required software pieces: 1. **Maven**: it can be downloaded from https://maven.apache.org/download.cgi#. 2. **Git**: it can be downloaded from https://git-scm.com/downloads. 3. **Java 20.0.1**: it can be downloaded from https://www.oracle.com/java/technologies/downloads/#java20. 4. **Node.js 17.8+**: Latest features, can be downloaded from https://nodejs.org/en/download/current/. 5. **Angular CLI 12.2+**: Install it with the following command: `npm install -g @angular/cli@latest` Follow the installation guide for each software on provided website link and check your software versions from the command line to verify that they are all installed correctly. ### Cloning It Now it is the time to open **terminal** or **git bash** command line, and then clone the project under any of your favorite places with the following command: ```bash > git clone https://github.com/mohamed-taman/Flight-Advisor.git ``` ### Using an IDE I recommend that you work with your Java code using an IDE that supports the development of Spring Boot applications such as **Spring Tool Suite** or **IntelliJ IDEA Community | Ultimate Edition**. All you have to do is fire up your favorite IDE **->** open or import the parent folder `Flight-Advisor,` everything will be ready for you. ### Building & Running The System To build and run Flight Advisor (FA) system components, run the following command: #### Building FA Components ##### FA backend ```bash 👻 [mtaman]:Flight-Advisor ~~ ./mvnw clean package ``` Now you should expect output like this: ```JavaScript [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] [INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ flight-advisor --- [INFO] Building jar: /Flight-Advisor/target/flight-advisor-3.0.jar [INFO] [INFO] --- spring-boot-maven-plugin:2.4.0:repackage (repackage) @ flight-advisor --- [INFO] Replacing main artifact with repackaged archive [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 14.620 s [INFO] Finished at: 2022-04-13T13:40:50+01:00 [INFO] ----------------------------------------------------------------------- ``` ##### FA frontend ```bash 👻 [mtaman]:Flight-Advisor ~~ cd frontend 👻 [mtaman]:frontend ~~ npm install && ng build ``` Now you should expect output like this: ```JavaScript removed 1 package and audited 1521 packages in 6.658s 85 packages are looking for funding run `npm fund` for details found 6 vulnerabilities (3 low, 1 moderate, 1 high, 1 critical) run `npm audit fix` to fix them, or `npm audit` for details ✔ Browser application bundle generation complete. ✔ Copying assets complete. ✔ Index html generation complete. Initial Chunk Files | Names | Size vendor.js | vendor | 4.37 MB scripts.js | scripts | 153.22 kB polyfills.js | polyfills | 149.77 kB styles.css | styles | 142.28 kB main.js | main | 13.32 kB runtime.js | runtime | 6.15 kB | Initial Total | 4.83 MB Build at: 2022-04-13T18:30:00.555Z - Hash: ccf039ad034c30696fdb - Time: 8608ms ``` #### Running the System Now it's the time to run the system, and it's straightforward, just hit the following commands: ##### FA backend ```bash 👻 [mtaman]:Flight-Advisor ~~ java --enable-preview -jar ./target/*.jar \ 👻 [mtaman]:Flight-Advisor ~+ --spring.profiles.active=prod ``` Or ```bash 👻 [mtaman]:Flight-Advisor ~~ ./mvnw spring-boot:run \ 👻 [mtaman]:Flight-Advisor ~+ -Dspring-boot.run.jvmArguments="--enable-preview" \ 👻 [mtaman]:Flight-Advisor ~+ -Dspring-boot.run.arguments="--spring.profiles.active=prod" ``` **Flight Advisor backend service** will run, with embedded H2 **database** that will be created under `db` folder and then the `flightDB.mv.db` file, and you should expect an output like this: ```javascript 2022-04-13 13:56:16.587 INFO 2981 --- [ restartedMain] o.s.b.a.h2.H2ConsoleAutoConfiguration: H2 console available at '/db-console'. Database available at 'jdbc:h2:./db/flightDB' 2022-04-13 13:56:18.081 INFO 2981 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer: Tomcat started on port(s): 8090 (http) with context path 'api/v1/flight/service' 2022-04-13 13:56:18.581 INFO 2981 --- [ restartedMain] o.s.h.f.F.AppStartupRunner: Congratulations, Flight Advisor Application, is Up & Running :) ``` ##### FA frontend ```bash 👻 [mtaman]:frontend ~~ npm start ``` **Flight Advisor UI** will run, and you should expect an output like this: ```javascript ** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ ** ✔ Compiled successfully. ``` ### Access Flight Advisor System APIs You can play and test `Flight Advisor` APIs throughout its **OpenAPI** interface. 1. Go to the landing page at the following URL [http://localhost:8090/api/v1/flight/service/] (http://localhost:8090/api/v1/flight/service/). 2. Follow the link on the page, and you should see the following: ![System APIs](docs/images/SystemAPI.png) 3. More beautifully with its UI at [http://localhost:4200/](http://localhost:4200/), and you expect this view for login: ![ClientLogin page](docs/images/FA-Login.png) And this view after login, to travel: ![System APIs](docs/images/FA-Travel.png) #### System Behaviour 1. First, if you want to upload airports or routes (in the data folder) using the **Files upload Management** section: 1. Log-in with the provided admin username/password to the `auth/signin` endpoint. 2. On successful login, the response will contain an authorization token; copy it. 3. Click on the Authorize button and paste it into the only field out there, `value,` then click the `Authorize` button. 4. All locks are closed, and you can use the secured APIs. 2. If you are a new client and want to access the system, you must first register through the `/auth/signup` endpoint. Then follow the previous point **1.1**. 3. When uploading the Airports file, countries and cities will be created automatically. 4. All search parameters are case-insensitive, and the system uses a `like` search by default. 5. To add a city, you need a country, so from the **country management** section, you can search for the country you want. 6. To manage comments, you need a city, so from the **city management** section, you can get all cities or search for a specific city. 7. You can search for all airports in a specific city to know their codes so that you can use travel services. 8. Use a travel service to search for the cheapest flight from city to city, for example traveling from **CAI** (*Cairo International Airport, Egypt*) to **LAX** (*Los Angeles, USA*); the following results will be returned: ```JSON [ { "start": { "airport": "Cairo International Airport", "city": "Cairo", "country": "Egypt", "iata": "CAI" }, "through": [ { "airport": "Lester B. Pearson International Airport", "city": "Toronto", "country": "Canada", "iata": "YYZ" } ], "end": { "airport": "Los Angeles International Airport", "city": "Los Angeles", "country": "United States", "iata": "LAX" }, "price": { "total": 62.17, "currency": "US" }, "distance": { "total": 12722.2, "in": "KM" } } ] ``` ### Access Flight Advisor System Database You can access the database through its online console from the following URL [http://localhost:8090/api/v1/flight/service/db-console/] (http://localhost:8090/api/v1/flight/service/db-console/) with the following properties: - Driver class: `org.h2.Driver` - JDBC URL: `jdbc:h2:./db/flightDB` - user: `sa` - password: `Admin1234` ![System DB](docs/images/SystemDB.png) Hit test, and it should show a green bar for successful settings. So hit the **Connect** button and explore all data. ### Stopping The System Just press the `CTRL+C` keys on the terminal. ### Closing The Story Finally, I hope you enjoyed the application and found it useful. If you would like to enhance it, please open **PR**, and yet give it a 🌟. ## The End Happy Coding 😊 ## License Copyright (C) 2023 Mohamed Taman, Licensed under the **MIT License**. \ No newline at end of file +# Flight Advisor Service ![GitHub release (latest by date)](https://img.shields.io/github/v/release/mohamed-taman/Flight-Advisor) [![Release Codename](https://img.shields.io/badge/codename-Advisor_Enhanced_5.1-yellow.svg)](https://github.com/mohamed-taman/Flight-Advisor/releases) [![Twitter Follow](https://img.shields.io/twitter/follow/_tamanm?label=follow%20me&style=social)](https://twitter.com/_tamanm) Flight Advisor Service is a set of APIs for primarily finding the cheapest flight from city A to City B is based on price, and as a result, it returns all the trip information alongside the distance(s). > This service is a great example of migrating spring boot from the older version **2.7.x** to **3.1.x**. You can check the changes from commit changes of each version release (as code) or release notes as information. And the [**Spring Boot 2.5.x to 3.1.x migration Guide**](https://medium.com/@tamanm/spring-boot-2-x-to-3-1-x-migration-guides-e83380dbc470) would help you in your migration journey. ## System Functionality - This project is developing a layered monolith **Spring Boot** based project (with the latest version **3.4.0-M1**), on **Java 22**, and with an embedded database mode. - This OAuth2-based project uses a JWT token to secure endpoints and a refresh token to get a new JWT token without login. - Therefore, you need to register first to continue using the system. - The functionality is reached based on user roles, and the system has three roles. - **Admin**: user is a predefined user (*admin@traveladvisor.com/Admin1234*). - Admin needs to log-in first through `/signin` API to get their token to contact the system. - This user can upload airports and flight routes. - Admin manages cities by adding, updating, or deleting them. - Actually, the admin can do anything in the system. - **Client**: Clients should register before using the system through `/signup` public API. - After successful registration, they can use the public `/signin` API to get a token to contact the system successfully. - Client can use all read API calls. - Clients can add, manage their comments for a city, add, update, delete their comments, and see other comments. - Client can get the cheapest flight by calling `/cities/travel` API and providing airport codes for [**from the city**] and [**to the city**]. - **Public**: it is not a role, but anonymous users use APIs under public (*some APIs need access and will be marked as ACCESS REQUIRED*). - Use `/signin` API call to log-in to the system, supplying the username and password. Then you will get a valid JWT token with a longer living refresh token. - Use `/signout` to logout from the system. (**ACCESS REQUIRED**) - Use `/change_password` to change your current password so you will be logged-out, and you need to log-in again to access the system. (**ACCESS REQUIRED**) - Use `/refresh_token` when your access token is expired to get new JWT access and refresh the token with the previous not expired refresh token without login into the system again. (**ACCESS REQUIRED**) - Use `/signup` API call to register as a client to use the system functionalities related to the client; otherwise, the client will receive *Not Authorized*. ## Getting started ### Project Management 1. I have used GitHub projects to manage my tasks in the **Flight-Advisor** project. [Project Link](https://github.com/mohamed-taman/Flight-Advisor/projects/1). 2. All MVP tasks are assigned to the **Flight Advisor API MVP** Milestone. [Milestone Link](https://github.com/mohamed-taman/Flight-Advisor/milestone/1?closed=1). 3. I used pull requests to manage and close assigned tasks. [Tasks Link](https://github.com/mohamed-taman/Flight-Advisor/issues?q=is%3Aclosed). 4. Finally, I have added releases to manage small feature sprints until the final release, v1.0. [Releases Link](https://github.com/mohamed-taman/Flight-Advisor/releases). 5. Have a look at open issues for future enhancements. [Opened Issues](https://github.com/mohamed-taman/Flight-Advisor/issues?q=is%3Aopen). ### System components Structure Let's first explain the system layers structure to understand its components: ``` Flight-Advisor --> Parent folder. |- docs --> Contains system images. |- data --> Contains Airports and routes files. |- frontend --> Contains the frontend UI project. |- src/main/java - org.siriusxi.fa (package) |- FlightAdvisorApplication.java --> The main starting point of the application. |- api --> Contains All REST API controllers that receive requests from the client to process that request and, finally, return appropriate responses. It contains all request and response DTOs. |- repository --> All the database entities CRUD management services. |- domain --> Domain contains all the database-modeled entities. |- infra --> Contains all the configurations, exceptions, security management, support utilities, and dto <--> entities mappers for the system support. |- service --> Contains all the system business login, receives calls from Controllers, calls the repository to retrieve and manage data, then processes them to return to the controllers. ``` Now, as we have learned about different system layers and components, so it is time then to play, let's play. ## Playing With Flight Advisor Service First things first, you need to download the following pieces of software to have fun with the project: ### Required software The following are the initially required software pieces: 1. **Maven**: it can be downloaded from https://maven.apache.org/download.cgi#. 2. **Git**: it can be downloaded from https://git-scm.com/downloads. 3. **Java 20.0.1**: it can be downloaded from https://www.oracle.com/java/technologies/downloads/#java20. 4. **Node.js 17.8+**: Latest features, can be downloaded from https://nodejs.org/en/download/current/. 5. **Angular CLI 12.2+**: Install it with the following command: `npm install -g @angular/cli@latest` Follow the installation guide for each software on provided website link and check your software versions from the command line to verify that they are all installed correctly. ### Cloning It Now it is the time to open **terminal** or **git bash** command line, and then clone the project under any of your favorite places with the following command: ```bash > git clone https://github.com/mohamed-taman/Flight-Advisor.git ``` ### Using an IDE I recommend that you work with your Java code using an IDE that supports the development of Spring Boot applications such as **Spring Tool Suite** or **IntelliJ IDEA Community | Ultimate Edition**. All you have to do is fire up your favorite IDE **->** open or import the parent folder `Flight-Advisor,` everything will be ready for you. ### Building & Running The System To build and run Flight Advisor (FA) system components, run the following command: #### Building FA Components ##### FA backend ```bash 👻 [mtaman]:Flight-Advisor ~~ ./mvnw clean package ``` Now you should expect output like this: ```JavaScript [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] [INFO] --- maven-jar-plugin:3.4.2:jar (default-jar) @ flight-advisor --- [INFO] Building jar: C:\Users\...\Projects\java\Flight-Advisor\target\flight-advisor-6.0.jar [INFO] [INFO] --- spring-boot-maven-plugin:3.4.0-M1:repackage (repackage) @ flight-advisor --- [INFO] Replacing main artifact C:\Users\...\Projects\java\Flight-Advisor\target\flight-advisor-6.0.jar with repackaged archive, adding nested dependencies in BOOT-INF/. [INFO] The original artifact has been renamed to C:\Users\...\Projects\java\Flight-Advisor\target\flight-advisor-6.0.jar.original [INFO] [INFO] --- maven-failsafe-plugin:3.5.0:integration-test (default) @ flight-advisor --- [INFO] --- maven-failsafe-plugin:3.5.0:verify (default) @ flight-advisor --- [INFO] No tests to run. [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 25.658 s [INFO] Finished at: 2024-09-02T14:16:57+02:00 [INFO] ------------------------------------------------------------------------ ``` ##### FA frontend ```bash 👻 [mtaman]:Flight-Advisor ~~ cd frontend 👻 [mtaman]:frontend ~~ npm install && ng build ``` Now you should expect output like this: ```JavaScript removed 1 package and audited 1521 packages in 6.658s 85 packages are looking for funding run `npm fund` for details found 6 vulnerabilities (3 low, 1 moderate, 1 high, 1 critical) run `npm audit fix` to fix them, or `npm audit` for details ✔ Browser application bundle generation complete. ✔ Copying assets complete. ✔ Index html generation complete. Initial Chunk Files | Names | Size vendor.js | vendor | 4.37 MB scripts.js | scripts | 153.22 kB polyfills.js | polyfills | 149.77 kB styles.css | styles | 142.28 kB main.js | main | 13.32 kB runtime.js | runtime | 6.15 kB | Initial Total | 4.83 MB Build at: 2022-04-13T18:30:00.555Z - Hash: ccf039ad034c30696fdb - Time: 8608ms ``` #### Running the System Now it's the time to run the system, and it's straightforward, just hit the following commands: ##### FA backend ```bash 👻 [mtaman]:Flight-Advisor ~~ java --enable-preview -jar ./target/*.jar \ 👻 [mtaman]:Flight-Advisor ~+ --spring.profiles.active=prod ``` Or ```bash 👻 [mtaman]:Flight-Advisor ~~ ./mvnw spring-boot:run \ 👻 [mtaman]:Flight-Advisor ~+ -Dspring-boot.run.jvmArguments="--enable-preview" \ 👻 [mtaman]:Flight-Advisor ~+ -Dspring-boot.run.arguments="--spring.profiles.active=prod" ``` **Flight Advisor backend service** will run, with embedded H2 **database** that will be created under `db` folder and then the `flightDB.mv.db` file, and you should expect an output like this: ```javascript 2022-04-13 13:56:16.587 INFO 2981 --- [ restartedMain] o.s.b.a.h2.H2ConsoleAutoConfiguration: H2 console available at '/db-console'. Database available at 'jdbc:h2:./db/flightDB' 2022-04-13 13:56:18.081 INFO 2981 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer: Tomcat started on port(s): 8090 (http) with context path 'api/v1/flight/service' 2022-04-13 13:56:18.581 INFO 2981 --- [ restartedMain] o.s.h.f.F.AppStartupRunner: Congratulations, Flight Advisor Application, is Up & Running :) ``` ##### FA frontend ```bash 👻 [mtaman]:frontend ~~ npm start ``` **Flight Advisor UI** will run, and you should expect an output like this: ```javascript ** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ ** ✔ Compiled successfully. ``` ### Access Flight Advisor System APIs You can play and test `Flight Advisor` APIs throughout its **OpenAPI** interface. 1. Go to the landing page at the following URL [http://localhost:8090/api/v1/flight/service/] (http://localhost:8090/api/v1/flight/service/). 2. Follow the link on the page, and you should see the following: ![System APIs](docs/images/SystemAPI.png) 3. More beautifully with its UI at [http://localhost:4200/](http://localhost:4200/), and you expect this view for login: ![ClientLogin page](docs/images/FA-Login.png) And this view after login, to travel: ![System APIs](docs/images/FA-Travel.png) #### System Behaviour 1. First, if you want to upload airports or routes (in the data folder) using the **Files upload Management** section: 1. Log-in with the provided admin username/password to the `auth/signin` endpoint. 2. On successful login, the response will contain an authorization token; copy it. 3. Click on the Authorize button and paste it into the only field out there, `value,` then click the `Authorize` button. 4. All locks are closed, and you can use the secured APIs. 2. If you are a new client and want to access the system, you must first register through the `/auth/signup` endpoint. Then follow the previous point **1.1**. 3. When uploading the Airports file, countries and cities will be created automatically. 4. All search parameters are case-insensitive, and the system uses a `like` search by default. 5. To add a city, you need a country, so from the **country management** section, you can search for the country you want. 6. To manage comments, you need a city, so from the **city management** section, you can get all cities or search for a specific city. 7. You can search for all airports in a specific city to know their codes so that you can use travel services. 8. Use a travel service to search for the cheapest flight from city to city, for example traveling from **CAI** (*Cairo International Airport, Egypt*) to **LAX** (*Los Angeles, USA*); the following results will be returned: ```JSON [ { "start": { "airport": "Cairo International Airport", "city": "Cairo", "country": "Egypt", "iata": "CAI" }, "through": [ { "airport": "Lester B. Pearson International Airport", "city": "Toronto", "country": "Canada", "iata": "YYZ" } ], "end": { "airport": "Los Angeles International Airport", "city": "Los Angeles", "country": "United States", "iata": "LAX" }, "price": { "total": 62.17, "currency": "US" }, "distance": { "total": 12722.2, "in": "KM" } } ] ``` ### Access Flight Advisor System Database You can access the database through its online console from the following URL [http://localhost:8090/api/v1/flight/service/db-console/] (http://localhost:8090/api/v1/flight/service/db-console/) with the following properties: - Driver class: `org.h2.Driver` - JDBC URL: `jdbc:h2:./db/flightDB` - user: `sa` - password: `Admin1234` ![System DB](docs/images/SystemDB.png) Hit test, and it should show a green bar for successful settings. So hit the **Connect** button and explore all data. ### Stopping The System Just press the `CTRL+C` keys on the terminal. ### Closing The Story Finally, I hope you enjoyed the application and found it useful. If you would like to enhance it, please open **PR**, and yet give it a 🌟. ## The End Happy Coding 😊 ## License Copyright (C) 2023 Mohamed Taman, Licensed under the **MIT License**. \ No newline at end of file diff --git a/pom.xml b/pom.xml index 3b60d8c..d5c6457 100644 --- a/pom.xml +++ b/pom.xml @@ -6,13 +6,13 @@ org.springframework.boot spring-boot-starter-parent - 3.1.0 + 3.4.0-M1 org.siriusxi.fa flight-advisor - 5.0 + 6.0 Flight Advisor API Flight Advisor API Spring Boot based Application. jar @@ -25,10 +25,10 @@ mohamed.taman@gmail.com - Sr. Enterprise Architect + Solutions Architect - Lead Software Architect + Java Lead Software Architect @@ -58,7 +58,7 @@ - 21 + 22 ${java.version} ${java.version} ${java.version} @@ -66,15 +66,15 @@ UTF-8 - 3.0.0 - 3.0.0 - 0.11.5 - 1.5.4.Final - 2.1.0 - 5.7.1 + 3.5.0 + 3.5.0 + 0.12.6 + 1.6.0 + 2.6.0 + 5.9 1.0.1 - 1.8.1 - 4.4 + 1.9.1 + 4.5.0-M2 diff --git a/src/main/java/org/siriusxi/fa/api/model/response/TripResponse.java b/src/main/java/org/siriusxi/fa/api/model/response/TripResponse.java index fd955c4..a92f401 100644 --- a/src/main/java/org/siriusxi/fa/api/model/response/TripResponse.java +++ b/src/main/java/org/siriusxi/fa/api/model/response/TripResponse.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; import java.util.List; import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; @@ -16,7 +17,7 @@ public record TripResponse( @JsonProperty Distance distance) { public record Price( - @JsonProperty double total, + @JsonProperty BigDecimal total, @JsonProperty String currency) { } diff --git a/src/main/java/org/siriusxi/fa/domain/Role.java b/src/main/java/org/siriusxi/fa/domain/Role.java index 86a93e2..b42af37 100644 --- a/src/main/java/org/siriusxi/fa/domain/Role.java +++ b/src/main/java/org/siriusxi/fa/domain/Role.java @@ -41,7 +41,7 @@ public class Role implements GrantedAuthority { private String authority; public Role(RolePK rolePK) { - setRolePK(rolePK); + this.setRolePK(rolePK); this.authority = rolePK.getAuthority(); } diff --git a/src/main/java/org/siriusxi/fa/domain/Route.java b/src/main/java/org/siriusxi/fa/domain/Route.java index 4e871ed..2ef3b0f 100644 --- a/src/main/java/org/siriusxi/fa/domain/Route.java +++ b/src/main/java/org/siriusxi/fa/domain/Route.java @@ -16,6 +16,7 @@ import java.io.Serial; import java.io.Serializable; +import java.math.BigDecimal; import java.util.Objects; import static jakarta.persistence.FetchType.LAZY; @@ -55,7 +56,7 @@ public class Route implements Serializable { @Max(value = 99999) @Min(value = 5) @Column(precision = 6, scale = 3) - private double price; + private BigDecimal price; @JoinColumn(name = "DESTINATION_AIRPORT_ID", referencedColumnName = "AIRPORT_ID") @ManyToOne(fetch = LAZY) diff --git a/src/main/java/org/siriusxi/fa/domain/vo/RouteView.java b/src/main/java/org/siriusxi/fa/domain/vo/RouteView.java index f0f04d7..f4a4f4d 100644 --- a/src/main/java/org/siriusxi/fa/domain/vo/RouteView.java +++ b/src/main/java/org/siriusxi/fa/domain/vo/RouteView.java @@ -1,4 +1,6 @@ package org.siriusxi.fa.domain.vo; -public record RouteView(String source, String destination, double price) { +import java.math.BigDecimal; + +public record RouteView(String source, String destination, BigDecimal price) { } diff --git a/src/main/java/org/siriusxi/fa/infra/security/jwt/JwtTokenHelper.java b/src/main/java/org/siriusxi/fa/infra/security/jwt/JwtTokenHelper.java index 54d194f..5de50b8 100644 --- a/src/main/java/org/siriusxi/fa/infra/security/jwt/JwtTokenHelper.java +++ b/src/main/java/org/siriusxi/fa/infra/security/jwt/JwtTokenHelper.java @@ -4,7 +4,6 @@ import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.MalformedJwtException; -import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.UnsupportedJwtException; import io.jsonwebtoken.security.Keys; import lombok.extern.log4j.Log4j2; @@ -24,10 +23,10 @@ @Log4j2 public final class JwtTokenHelper { - + private JwtTokenHelper() { } - + /** * Generates a token fot the user. * @@ -37,18 +36,19 @@ private JwtTokenHelper() { */ public static String generateJwtToken(int id, String username) { return Jwts - .builder() - .setId(String.valueOf(id)) - .setSubject(format("%d,%s", id, username)) - .setIssuer(JwtConfig.ISSUER) - .setIssuedAt(new Date(System.currentTimeMillis())) - .setExpiration(Date.from(ZonedDateTime.now() - .plusDays(JwtConfig.TOKEN_EXPIRY_DURATION) - .toInstant())) - .signWith(JwtConfig.key(), JwtConfig.SIGNATURE_ALGORITHM) - .compact(); + .builder() + .id(String.valueOf(id)) + .subject(format("%d,%s", id, username)) + .audience().add("you").and() + .issuer(JwtConfig.ISSUER) + .issuedAt(new Date(System.currentTimeMillis())) + .expiration(Date.from(ZonedDateTime.now() + .plusDays(JwtConfig.TOKEN_EXPIRY_DURATION) + .toInstant())) + .signWith(JwtConfig.key()) + .compact(); } - + /** * Extracts the User id claim from the JWT token * @@ -57,10 +57,10 @@ public static String generateJwtToken(int id, String username) { */ public static int getUserIdFrom(String jwtToken) { return Integer.parseInt(getClaims(jwtToken) - .getSubject() - .split(",")[0]); + .getSubject() + .split(",")[0]); } - + /** * Extracts the username claim from the JWT token * @@ -69,10 +69,10 @@ public static int getUserIdFrom(String jwtToken) { */ public static String getUsernameFrom(String jwtToken) { return getClaims(jwtToken) - .getSubject() - .split(",")[1]; + .getSubject() + .split(",")[1]; } - + /** * Extracts the expiration date claim from the JWT token * @@ -81,9 +81,9 @@ public static String getUsernameFrom(String jwtToken) { */ public static Date getTokenExpiration(String token) { return getClaims(token) - .getExpiration(); + .getExpiration(); } - + /** * Extracts the claims from the JWT token * @@ -91,14 +91,13 @@ public static Date getTokenExpiration(String token) { * @return the all claims contained in the token */ private static Claims getClaims(String token) { - return Jwts - .parserBuilder() - .setSigningKey(JwtConfig.key()) - .build() - .parseClaimsJws(token.replace(JwtConfig.TOKEN_PREFIX, "")) - .getBody(); + return Jwts.parser() + .verifyWith(JwtConfig.key()) + .build() + .parseSignedClaims(token.replace(JwtConfig.TOKEN_PREFIX, "")) + .getPayload(); } - + /** * Extracts the claim from the JWT token * @@ -122,48 +121,33 @@ public static boolean validate(String token) { } return false; } - - /** - * Allows generating a real base64 encoded secret key. - */ - public static String getRealBase64EncodedSecret() { - return Base64.getEncoder().encodeToString(getRealSecret()); - } - - /** - * Allows generating a real secret key. - */ - public static byte[] getRealSecret() { - return Keys.secretKeyFor(JwtConfig.SIGNATURE_ALGORITHM).getEncoded(); - } - public static String tokenPrefix(){ + public static String tokenPrefix() { return JwtConfig.TOKEN_PREFIX; } - public static int refreshTokenExpiration(){ + public static int refreshTokenExpiration() { return JwtConfig.REFRESH_TOKEN_EXPIRATION; } - + /** * jwt configurations. * TODO add all config in application.yaml */ private static class JwtConfig { - static final SignatureAlgorithm SIGNATURE_ALGORITHM = SignatureAlgorithm.HS512; // It should be kept encoded in an environment variable static final String SECRET = - """ - 5s2BCxpNxdI58mAaAllBr/psyu91aCusvXy+kew9ytxQ/zh\ - RtvcZMxVAjmkq8pVkSMA81+9Y0D4W06qGre+hYg=="""; + """ + 5s2BCxpNxdI58mAaAllBr/psyu91aCusvXy+kew9ytxQ/zh\ + RtvcZMxVAjmkq8pVkSMA81+9Y0D4W06qGre+hYg=="""; static final String TOKEN_PREFIX = "Bearer "; - static final String ISSUER = "siriusx.io"; + static final String ISSUER = "tamanm.io"; static final int TOKEN_EXPIRY_DURATION = 7; // In days static final int REFRESH_TOKEN_EXPIRATION = 14; // In days - + private JwtConfig() { } - + static SecretKey key() { return Keys.hmacShaKeyFor(Base64.getDecoder().decode(SECRET)); } diff --git a/src/main/java/org/siriusxi/fa/repository/RouteRepository.java b/src/main/java/org/siriusxi/fa/repository/RouteRepository.java index c5eecc8..587bf79 100644 --- a/src/main/java/org/siriusxi/fa/repository/RouteRepository.java +++ b/src/main/java/org/siriusxi/fa/repository/RouteRepository.java @@ -10,6 +10,7 @@ import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; +import java.math.BigDecimal; import java.util.Collection; import java.util.List; import java.util.Set; @@ -31,7 +32,7 @@ SELECT sum(price) FROM Route WHERE routePK IN (:routePKs) """) - double getTripCost(Iterable routePKs); + BigDecimal getTripCost(Iterable routePKs); List findAllByRoutePKIn(Collection routePK); diff --git a/src/main/java/org/siriusxi/fa/service/TravelService.java b/src/main/java/org/siriusxi/fa/service/TravelService.java index af60012..75fe84a 100644 --- a/src/main/java/org/siriusxi/fa/service/TravelService.java +++ b/src/main/java/org/siriusxi/fa/service/TravelService.java @@ -22,6 +22,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.math.BigDecimal; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; @@ -160,7 +161,7 @@ private double calculateDistance(Route route) { private TripResponse newTripView(Airport src, Airport dest, List through, - double cost, double distance) { + BigDecimal cost, double distance) { return new TripResponse( this.airportMapper.toTripView(src, 0), through, this.airportMapper.toTripView(dest, 0), @@ -203,7 +204,7 @@ private GraphBuilder buildGraph(GraphBuilder gra graph .connect(route.source()) .to(route.destination()) - .withEdge(route.price())); + .withEdge(route.price().doubleValue())); return graph; } diff --git a/src/main/java/org/siriusxi/fa/service/UserService.java b/src/main/java/org/siriusxi/fa/service/UserService.java index d37f386..dd69465 100644 --- a/src/main/java/org/siriusxi/fa/service/UserService.java +++ b/src/main/java/org/siriusxi/fa/service/UserService.java @@ -53,7 +53,7 @@ public UserResponse create(CreateUserRequest request) { // Update user to add authorities this.repository.save(user); - System.out.println("Saved User: "+ user.toString()); + System.out.println("Saved User: "+ user); // Return user view return this.userMapper.toView(user); diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index eecb581..a2302f4 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -35,10 +35,15 @@ spring: open-in-view: false hibernate: ddl-auto: none - # The SQL dialect makes Hibernate generate better SQL for the chosen database properties: - hibernate: - dialect: org.hibernate.dialect.H2Dialect + hibernate: + # The SQL dialect makes Hibernate generate better SQL for the chosen database + dialect: org.hibernate.dialect.H2Dialect + format_sql: true + use_sql_comments: true + # Generate statistics for Hibernate's performance monitoring + # This will provide additional information about your database usage. + # Uncomment the following line to generate statistics. generate_statistics: true # Switching on batch insert # Take the time to group inserts by entity, creating larger batches.