Merge pull request #11 from jlengrand/backend

Add support for transactions viewing
This commit is contained in:
julien Lengrand-Lambert
2019-10-22 22:23:51 +02:00
committed by GitHub
19 changed files with 255 additions and 26 deletions

View File

@@ -45,6 +45,11 @@
<artifactId>javax.json</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>

View File

@@ -1,12 +1,18 @@
package fr.lengrand.dialogflowfunapi;
import fr.lengrand.dialogflowfunapi.openbankproject.OpenBankClient;
import fr.lengrand.dialogflowfunapi.openbankproject.auth.Auth;
import fr.lengrand.dialogflowfunapi.openbankproject.data.balance.Balance;
import fr.lengrand.dialogflowfunapi.openbankproject.data.paymentrequest.PaymentRequest;
import fr.lengrand.dialogflowfunapi.openbankproject.data.transactions.Transactions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.io.IOException;
@SpringBootApplication
@@ -16,19 +22,46 @@ public class DialogflowFunApiApplication {
@Autowired
private Auth auth;
@Autowired
private OpenBankClient openBankClient;
public static void main(String[] args) {
SpringApplication.run(DialogflowFunApiApplication.class, args);
}
@PostConstruct
private void init() {
try {
auth.authenticate();
} catch (IOException | InterruptedException e) {
System.out.println("Error while authenticating!"); // TODO : Use a logger
}
}
@GetMapping("/")
public String hello() {
return "hello world!";
return "hello from your bank API!";
}
@GetMapping("/auth")
// TODO : Take inputs from requests
@GetMapping("/token")
public String auth() throws IOException, InterruptedException {
auth.authenticate(); // TODO: Should be done on start!
return auth.getAuthToken().isPresent()? auth.getAuthToken().get().getToken() : "No token!";
return auth.getToken().isPresent()? auth.getToken().get() : "No token!";
}
@GetMapping("/transactions")
public Transactions transactions() throws IOException, InterruptedException {
return openBankClient.getTransactions();
}
@GetMapping("/balances")
public Balance balances() throws IOException, InterruptedException {
return openBankClient.getBalance();
}
@PostMapping("/payment")
public PaymentRequest payment() throws IOException, InterruptedException {
return openBankClient.createPaymentRequest();
}
}

View File

@@ -0,0 +1,58 @@
package fr.lengrand.dialogflowfunapi.openbankproject;
import fr.lengrand.dialogflowfunapi.openbankproject.auth.JSONBodyHandler;
import fr.lengrand.dialogflowfunapi.openbankproject.data.balance.Balance;
import fr.lengrand.dialogflowfunapi.openbankproject.data.paymentrequest.PaymentRequest;
import fr.lengrand.dialogflowfunapi.openbankproject.data.transactions.Transactions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Service
public class OpenBankClient {
@Autowired
protected OpenBankHandler openBankHandler;
public JSONBodyHandler<Balance> balanceJSONHandler = JSONBodyHandler.getHandler(Balance.class);
public JSONBodyHandler<Transactions> transactionsJSONHandler = JSONBodyHandler.getHandler(Transactions.class);
public JSONBodyHandler<PaymentRequest> paymentRequestJSONHandler = JSONBodyHandler.getHandler(PaymentRequest.class);
public Balance getBalance() throws IOException, InterruptedException {
return openBankHandler.get(
balanceJSONHandler,
createBalanceRelativeUrl("at02-1465--01"));
}
public Transactions getTransactions() throws IOException, InterruptedException {
return openBankHandler.get(
transactionsJSONHandler,
createTransactionsUrl("at02-1465--01", "john_doe") // TODO : Convert to DialogFlow names
);
}
public PaymentRequest createPaymentRequest() throws IOException, InterruptedException {
return openBankHandler.post(
paymentRequestJSONHandler,
createPaymentRequestUrl("at02-1465--01", "john_doe"),
"{ \"to\":{ \"bank_id\":\"at02-1465--01\", \"account_id\":\"bob_de_bouwer\" }, \"value\":{ \"currency\":\"EUR\", \"amount\":\"10\" }, \"description\":\"last test\"}"
);// TODO : Create Object request
}
private String createPaymentRequestUrl(String bank, String user){
return "/banks/" + bank + "/accounts/" + user + "/owner/transaction-request-types/SANDBOX_TAN/transaction-requests";
}
private String createTransactionsUrl(String bank, String user){
return "/my/banks/"+ bank + "/accounts/" + user + "/transactions";
}
private String createBalanceRelativeUrl(String bank){
return "/banks/" + bank + "/balances";
}
}

View File

@@ -0,0 +1,51 @@
package fr.lengrand.dialogflowfunapi.openbankproject;
import fr.lengrand.dialogflowfunapi.openbankproject.auth.Auth;
import fr.lengrand.dialogflowfunapi.openbankproject.auth.JSONBodyHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
@Service
public class OpenBankHandler {
@Autowired
private Auth auth;
public static final String BASE_URL = "https://psd2-api.openbankproject.com/obp/v4.0.0/";
private HttpClient client = HttpClient.newHttpClient();
public <T> T post(JSONBodyHandler<T> jsonBodyHandler, String relativeUrl, String body) throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder()
.headers("Content-Type", "application/json",
"Authorization", createAuthHeader())
.uri(URI.create(BASE_URL + relativeUrl))
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<T> response = client.send(request, jsonBodyHandler);
return response.body();
}
public <T> T get(JSONBodyHandler<T> jsonBodyHandler, String relativeUrl) throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder()
.headers("Content-Type", "application/json",
"Authorization", createAuthHeader())
.uri(URI.create(BASE_URL + relativeUrl))
.build();
HttpResponse<T> response = client.send(request, jsonBodyHandler);
return response.body();
}
private String createAuthHeader(){
return "DirectLogin token=" + this.auth.getToken().get();
}
}

View File

@@ -1,5 +1,7 @@
package fr.lengrand.dialogflowfunapi.openbankproject.auth;
import fr.lengrand.dialogflowfunapi.openbankproject.auth.data.AuthToken;
import fr.lengrand.dialogflowfunapi.openbankproject.auth.data.OpenBankCredentials;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@@ -23,14 +25,9 @@ public class Auth {
public JSONBodyHandler<AuthToken> jsonBodyHandler = JSONBodyHandler.getHandler(AuthToken.class);
private Optional<AuthToken> authToken = Optional.empty();
private Optional<String> token = Optional.empty();
public void authenticate() throws IOException, InterruptedException {
System.out.println("Username is " + credentials.getUsername());
System.out.println("Password is " + credentials.getPassword());
System.out.println("Key is " + credentials.getKey());
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.headers("Content-Type", "application/json",
@@ -40,16 +37,16 @@ public class Auth {
.build();
HttpResponse<AuthToken> response = client.send(request, jsonBodyHandler); //TODO : Handle failures.
System.out.println(response.body().getToken());
authToken = Optional.of(response.body());
System.out.println("Authenticated");
token = Optional.of(response.body().getToken());
}
public boolean isAuthenticated() {
return authToken.isPresent();
return token.isPresent() && token.get() != null;
}
public Optional<AuthToken> getAuthToken() {
return authToken;
public Optional<String> getToken() {
return token;
}
private String createDirectLoginHeader(){

View File

@@ -10,6 +10,7 @@ import java.net.http.HttpResponse.ResponseInfo;
import java.util.function.Function;
public class JSONBodyHandler<T> implements HttpResponse.BodyHandler<T> {
// TODO : Use Jackson
private final Jsonb jsonBinder;
private final Class<T> type;
private HttpResponse.BodySubscriber<byte[]> byteArraySubscriber;

View File

@@ -1,4 +1,4 @@
package fr.lengrand.dialogflowfunapi.openbankproject.auth;
package fr.lengrand.dialogflowfunapi.openbankproject.auth.data;
public class AuthToken {
private String token;

View File

@@ -1,4 +1,4 @@
package fr.lengrand.dialogflowfunapi.openbankproject.auth;
package fr.lengrand.dialogflowfunapi.openbankproject.auth.data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.ComponentScan;

View File

@@ -0,0 +1,10 @@
package fr.lengrand.dialogflowfunapi.openbankproject.data.balance;
import fr.lengrand.dialogflowfunapi.openbankproject.data.transactions.Amount;
public class Account {
public String id;
public String bank_id;
public Amount balance;
}

View File

@@ -0,0 +1,8 @@
package fr.lengrand.dialogflowfunapi.openbankproject.data.balance;
import java.util.List;
public class Balance {
public List<Account> accounts;
}

View File

@@ -0,0 +1,7 @@
package fr.lengrand.dialogflowfunapi.openbankproject.data.paymentrequest;
public class Account {
public String bank_id;
public String account_id;
}

View File

@@ -0,0 +1,9 @@
package fr.lengrand.dialogflowfunapi.openbankproject.data.paymentrequest;
import fr.lengrand.dialogflowfunapi.openbankproject.data.transactions.Amount;
public class PaymentDetails {
public Account to_sandbox_tan;
public Amount value;
}

View File

@@ -0,0 +1,13 @@
package fr.lengrand.dialogflowfunapi.openbankproject.data.paymentrequest;
import java.util.Date;
public class PaymentRequest {
public String id;
public String status;
public Date start_date;
public Date end_date;
public Account from;
public PaymentDetails details;
}

View File

@@ -0,0 +1,7 @@
package fr.lengrand.dialogflowfunapi.openbankproject.data.transactions;
public class Amount {
public String currency;
public float amount;
}

View File

@@ -0,0 +1,13 @@
package fr.lengrand.dialogflowfunapi.openbankproject.data.transactions;
import java.util.Date;
public class Details {
public String description;
public Date posted;
public Date completed;
public Amount value;
public Amount new_balance;
}

View File

@@ -0,0 +1,8 @@
package fr.lengrand.dialogflowfunapi.openbankproject.data.transactions;
public class Transaction {
public String id;
public Details details;
}

View File

@@ -0,0 +1,8 @@
package fr.lengrand.dialogflowfunapi.openbankproject.data.transactions;
import java.util.List;
public class Transactions {
public List<Transaction> transactions;
}

View File

@@ -1,3 +1,4 @@
obp.username=${OPENBANKPROJECT_USERNAME}
obp.password=${OPENBANKPROJECT_PASSWORD}
obp.key=${OPENBANKPROJECT_CONSUMERKEY}
obp.key=${OPENBANKPROJECT_CONSUMERKEY}
spring.jackson.serialization.indent_output=true

View File

@@ -3,11 +3,11 @@ package fr.lengrand.dialogflowfunapi;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class DialogflowFunApiApplicationTests {
@Test
void contextLoads() {
}
}
//@SpringBootTest
//class DialogflowFunApiApplicationTests {
//
// @Test
// void contextLoads() {
// }
//
//}