Merge pull request #36 from dartpopikyardo/wip-customer

UI updates, backend transaction history fixes
This commit is contained in:
Chris Richardson
2016-09-06 20:49:04 -07:00
committed by GitHub
67 changed files with 898 additions and 563 deletions

View File

@@ -25,7 +25,7 @@ public class AccountsCommandSideServiceIntegrationTest {
private int port; private int port;
private String baseUrl(String path) { private String baseUrl(String path) {
return "http://localhost:" + port + "/" + path; return "http://localhost:" + port + "/api" + path;
} }
@Autowired @Autowired

View File

@@ -13,7 +13,7 @@ import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@RestController @RestController
@RequestMapping("/accounts") @RequestMapping("/api/accounts")
public class AccountController { public class AccountController {
private AccountService accountService; private AccountService accountService;

View File

@@ -35,7 +35,7 @@ public class AccountControllerIntegrationTest {
@Test @Test
public void shouldCreateAccount() throws Exception { public void shouldCreateAccount() throws Exception {
mockMvc.perform(post("/accounts") mockMvc.perform(post("/api/accounts")
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content("{\"customerId\" : \"00000000-00000000\", \"initialBalance\" : 500}") .content("{\"customerId\" : \"00000000-00000000\", \"initialBalance\" : 500}")
.accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
@@ -44,7 +44,7 @@ public class AccountControllerIntegrationTest {
@Test @Test
public void shouldRejectBadRequest() throws Exception { public void shouldRejectBadRequest() throws Exception {
mockMvc.perform(post("/accounts") mockMvc.perform(post("/api/accounts")
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content("{\"initialBalanceXXX\" : 500}") .content("{\"initialBalanceXXX\" : 500}")
.accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))

View File

@@ -1,31 +0,0 @@
package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
public class AccountChangeInfo {
private String changeId;
private String transactionId;
private String transactionType;
private long amount;
private long balanceDelta;
public AccountChangeInfo(String changeId, String transactionId, String transactionType, long amount, long balanceDelta) {
this.changeId = changeId;
this.transactionId = transactionId;
this.transactionType = transactionType;
this.amount = amount;
this.balanceDelta = balanceDelta;
}
@Override
public boolean equals(Object o) {
return EqualsBuilder.reflectionEquals(this, o);
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
}

View File

@@ -1,11 +1,10 @@
package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts; package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountChangeInfo;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountTransactionInfo; import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountTransactionInfo;
import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.TransferState;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/** /**
* Created by cer on 11/21/14. * Created by cer on 11/21/14.
@@ -18,13 +17,19 @@ public class AccountInfo {
private String description; private String description;
private long balance; private long balance;
private List<AccountChangeInfo> changes; private List<AccountChangeInfo> changes;
private List<AccountTransactionInfo> transactions; private Map<String, AccountTransactionInfo> transactions;
private Map<String, TransferState> transferStates;
private String version; private String version;
private Date date;
private AccountInfo() { private AccountInfo() {
} }
public AccountInfo(String id, String customerId, String title, String description, long balance, List<AccountChangeInfo> changes, List<AccountTransactionInfo> transactions, String version) { public AccountInfo(String id, String customerId, String title, String description, long balance, List<AccountChangeInfo> changes, Map<String, AccountTransactionInfo> transactions, String version) {
this(id, customerId, title, description, balance, changes, transactions, version, new Date());
}
public AccountInfo(String id, String customerId, String title, String description, long balance, List<AccountChangeInfo> changes, Map<String, AccountTransactionInfo> transactions, String version, Date date) {
this.id = id; this.id = id;
this.customerId = customerId; this.customerId = customerId;
@@ -34,6 +39,7 @@ public class AccountInfo {
this.changes = changes; this.changes = changes;
this.transactions = transactions; this.transactions = transactions;
this.version = version; this.version = version;
this.date = date;
} }
public String getId() { public String getId() {
@@ -57,14 +63,26 @@ public class AccountInfo {
} }
public List<AccountChangeInfo> getChanges() { public List<AccountChangeInfo> getChanges() {
return changes; return changes == null ? Collections.EMPTY_LIST : changes;
} }
public List<AccountTransactionInfo> getTransactions() { public List<AccountTransactionInfo> getTransactions() {
return transactions; return transactions == null ? Collections.EMPTY_LIST : new ArrayList<>(transactions.values());
} }
public String getVersion() { public String getVersion() {
return version; return version;
} }
public Date getDate() {
return date;
}
public Map<String, TransferState> getTransferStates() {
return transferStates;
}
public void setTransferStates(Map<String, TransferState> transferStates) {
this.transferStates = transferStates;
}
} }

View File

@@ -1,15 +1,18 @@
package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts; package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts;
import com.mongodb.WriteResult; import com.mongodb.WriteResult;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountChangeInfo;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountTransactionInfo; import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountTransactionInfo;
import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.TransferState;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update; import org.springframework.data.mongodb.core.query.Update;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Collections; import java.util.Date;
import static net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts.MoneyUtil.toIntegerRepr; import static net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts.MoneyUtil.toIntegerRepr;
import static org.springframework.data.mongodb.core.query.Criteria.where; import static org.springframework.data.mongodb.core.query.Criteria.where;
@@ -28,29 +31,33 @@ public class AccountInfoUpdateService {
public void create(String accountId, String customerId, String title, BigDecimal initialBalance, String description, String version) { public void create(String accountId, String customerId, String title, BigDecimal initialBalance, String description, String version) {
try { try {
accountInfoRepository.save(new AccountInfo( AccountChangeInfo ci = new AccountChangeInfo();
accountId, ci.setAmount(toIntegerRepr(initialBalance));
customerId, WriteResult x = mongoTemplate.upsert(new Query(where("id").is(accountId).and("version").exists(false)),
title, new Update()
description, .set("customerId", customerId)
toIntegerRepr(initialBalance), .set("title", title)
Collections.<AccountChangeInfo>emptyList(), .set("description", description)
Collections.<AccountTransactionInfo>emptyList(), .set("balance", toIntegerRepr(initialBalance))
version)); .push("changes", ci)
.set("date", new Date())
.set("version", version),
AccountInfo.class);
logger.info("Saved in mongo"); logger.info("Saved in mongo");
} catch (DuplicateKeyException t) {
logger.warn("When saving ", t);
} catch (Throwable t) { } catch (Throwable t) {
logger.error("Error during saving: ");
logger.error("Error during saving: ", t); logger.error("Error during saving: ", t);
throw new RuntimeException(t); throw new RuntimeException(t);
} }
} }
public void addTransaction(String eventId, String fromAccountId, AccountTransactionInfo ti) { public void addTransaction(String accountId, AccountTransactionInfo ti) {
mongoTemplate.updateMulti(new Query(where("id").is(fromAccountId)), /* wrong .and("version").lt(eventId) */ mongoTemplate.upsert(new Query(where("id").is(accountId)),
new Update(). new Update().
push("transactions", ti). set("transactions." + ti.getTransactionId(), ti),
set("version", eventId),
AccountInfo.class); AccountInfo.class);
} }
@@ -64,5 +71,10 @@ public class AccountInfoUpdateService {
AccountInfo.class); AccountInfo.class);
} }
public void updateTransactionStatus(String accountId, String transactionId, TransferState status) {
mongoTemplate.upsert(new Query(where("id").is(accountId)),
new Update().
set("transferStates." + transactionId, status),
AccountInfo.class);
}
} }

View File

@@ -1,9 +1,6 @@
package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts; package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts;
import io.eventuate.CompletableFutureUtil;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
public class AccountQueryService { public class AccountQueryService {
@@ -13,15 +10,17 @@ public class AccountQueryService {
this.accountInfoRepository = accountInfoRepository; this.accountInfoRepository = accountInfoRepository;
} }
public CompletableFuture<AccountInfo> findByAccountId(String accountId) { public AccountInfo findByAccountId(String accountId) {
AccountInfo account = accountInfoRepository.findOne(accountId); AccountInfo account = accountInfoRepository.findOne(accountId);
if (account == null) if (account == null)
return CompletableFutureUtil.failedFuture(new AccountNotFoundException(accountId)); throw new AccountNotFoundException(accountId);
else else
return CompletableFuture.completedFuture(account); if(account.getTransferStates()!=null)
account.getTransactions().stream().forEach(ati -> ati.setStatus(account.getTransferStates().get(ati.getTransactionId())));
return account;
} }
public CompletableFuture<List<AccountInfo>> findByCustomerId(String customerId) { public List<AccountInfo> findByCustomerId(String customerId) {
return CompletableFuture.completedFuture(accountInfoRepository.findByCustomerId(customerId)); return accountInfoRepository.findByCustomerId(customerId);
} }
} }

View File

@@ -3,12 +3,14 @@ package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.ac
import io.eventuate.DispatchedEvent; import io.eventuate.DispatchedEvent;
import io.eventuate.EventHandlerMethod; import io.eventuate.EventHandlerMethod;
import io.eventuate.EventSubscriber; import io.eventuate.EventSubscriber;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountChangedEvent; import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.*;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountCreditedEvent; import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.CreditRecordedEvent;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountDebitedEvent; import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.DebitRecordedEvent;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountOpenedEvent; import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.FailedDebitRecordedEvent;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.MoneyTransferCreatedEvent; import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.MoneyTransferCreatedEvent;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountChangeInfo;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountTransactionInfo; import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountTransactionInfo;
import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.TransferState;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -57,20 +59,36 @@ public class AccountQueryWorkflow {
de.getEvent().getDetails().getDate(), de.getEvent().getDetails().getDate(),
de.getEvent().getDetails().getDescription()); de.getEvent().getDetails().getDescription());
accountInfoUpdateService.addTransaction(eventId, fromAccountId, ti); accountInfoUpdateService.addTransaction(fromAccountId, ti);
accountInfoUpdateService.addTransaction(eventId, toAccountId, ti); accountInfoUpdateService.addTransaction(toAccountId, ti);
} }
@EventHandlerMethod @EventHandlerMethod
public void recordDebit(DispatchedEvent<AccountDebitedEvent> de) { public void recordDebit(DispatchedEvent<AccountDebitedEvent> de) {
String accountId = de.getEntityId();
String transactionId = de.getEvent().getTransactionId();
accountInfoUpdateService.updateTransactionStatus(accountId, transactionId, TransferState.DEBITED);
saveChange(de, -1); saveChange(de, -1);
} }
@EventHandlerMethod @EventHandlerMethod
public void recordCredit(DispatchedEvent<AccountCreditedEvent> de) { public void recordCredit(DispatchedEvent<AccountCreditedEvent> de) {
String accountId = de.getEntityId();
String transactionId = de.getEvent().getTransactionId();
accountInfoUpdateService.updateTransactionStatus(accountId, transactionId, TransferState.COMPLETED);
saveChange(de, +1); saveChange(de, +1);
} }
@EventHandlerMethod
public void recordFailed(DispatchedEvent<AccountDebitFailedDueToInsufficientFundsEvent> de) {
String accountId = de.getEntityId();
String transactionId = de.getEvent().getTransactionId();
accountInfoUpdateService.updateTransactionStatus(accountId, transactionId, TransferState.FAILED_DUE_TO_INSUFFICIENT_FUNDS);
}
public <T extends AccountChangedEvent> void saveChange(DispatchedEvent<T> de, int delta) { public <T extends AccountChangedEvent> void saveChange(DispatchedEvent<T> de, int delta) {
String changeId = de.getEventId().asString(); String changeId = de.getEventId().asString();
String transactionId = de.getEvent().getTransactionId(); String transactionId = de.getEvent().getTransactionId();

View File

@@ -4,7 +4,9 @@ import io.eventuate.javaclient.spring.jdbc.EventuateJdbcEventStoreConfiguration;
import io.eventuate.javaclient.spring.jdbc.IdGenerator; import io.eventuate.javaclient.spring.jdbc.IdGenerator;
import io.eventuate.javaclient.spring.jdbc.IdGeneratorImpl; import io.eventuate.javaclient.spring.jdbc.IdGeneratorImpl;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountCreditedEvent; import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountCreditedEvent;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountChangeInfo;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountTransactionInfo; import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountTransactionInfo;
import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.TransferState;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -14,11 +16,9 @@ import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@@ -54,14 +54,14 @@ public class AccountInfoUpdateServiceTest {
accountInfoUpdateService.create(accountId, customerId, title, initialBalance, description, version); accountInfoUpdateService.create(accountId, customerId, title, initialBalance, description, version);
AccountInfo accountInfo = accountQueryService.findByAccountId(accountId).get(); AccountInfo accountInfo = accountQueryService.findByAccountId(accountId);
assertEquals(accountId, accountInfo.getId()); assertEquals(accountId, accountInfo.getId());
assertEquals(customerId, accountInfo.getCustomerId()); assertEquals(customerId, accountInfo.getCustomerId());
assertEquals(title, accountInfo.getTitle()); assertEquals(title, accountInfo.getTitle());
assertEquals(description, accountInfo.getDescription()); assertEquals(description, accountInfo.getDescription());
assertEquals(initialBalance.longValue() * 100, accountInfo.getBalance()); assertEquals(initialBalance.longValue() * 100, accountInfo.getBalance());
assertTrue(accountInfo.getChanges().isEmpty()); assertEquals(1, accountInfo.getChanges().size());
assertTrue(accountInfo.getTransactions().isEmpty()); assertTrue(accountInfo.getTransactions().isEmpty());
assertEquals(version, accountInfo.getVersion()); assertEquals(version, accountInfo.getVersion());
@@ -76,22 +76,74 @@ public class AccountInfoUpdateServiceTest {
accountInfoUpdateService.updateBalance(accountId, changeId, 500, accountInfoUpdateService.updateBalance(accountId, changeId, 500,
change); change);
accountInfo = accountQueryService.findByAccountId(accountId).get(); accountInfo = accountQueryService.findByAccountId(accountId);
assertEquals(initialBalance.add(new BigDecimal(5)).longValue() * 100, accountInfo.getBalance()); assertEquals(initialBalance.add(new BigDecimal(5)).longValue() * 100, accountInfo.getBalance());
assertFalse(accountInfo.getChanges().isEmpty()); assertFalse(accountInfo.getChanges().isEmpty());
assertEquals(change, accountInfo.getChanges().get(0)); assertEquals(change, accountInfo.getChanges().get(1));
String eventId = x.genId().asString(); String eventId = x.genId().asString();
AccountTransactionInfo ti = new AccountTransactionInfo(transactionId, accountId, accountId, 5, new Date(), "A transfer"); AccountTransactionInfo ti = new AccountTransactionInfo(transactionId, accountId, accountId, 5, new Date(), "A transfer");
accountInfoUpdateService.addTransaction(eventId, accountId, ti); accountInfoUpdateService.addTransaction(accountId, ti);
accountInfo = accountQueryService.findByAccountId(accountId).get(); accountInfo = accountQueryService.findByAccountId(accountId);
assertFalse(accountInfo.getTransactions().isEmpty()); assertFalse(accountInfo.getTransactions().isEmpty());
assertEquals(ti, accountInfo.getTransactions().get(0)); assertEquals(ti, accountInfo.getTransactions().get(0));
} }
@Test
public void shouldHandleDuplicateSaveAccountInfo() throws ExecutionException, InterruptedException {
IdGenerator x = new IdGeneratorImpl();
String accountId = x.genId().asString();
String customerId = x.genId().asString();
String version = x.genId().asString();
String title = "Checking account";
BigDecimal initialBalance = new BigDecimal("1345");
String description = "Some account";
accountInfoUpdateService.create(accountId, customerId, title, initialBalance, description, version);
accountInfoUpdateService.create(accountId, customerId, title, initialBalance, description, version);
}
@Test
public void shouldUpdateTransactionStatus() {
IdGenerator x = new IdGeneratorImpl();
String accountId = x.genId().asString();
String customerId = x.genId().asString();
String version = x.genId().asString();
String title = "Checking account";
BigDecimal initialBalance = new BigDecimal("1345");
String description = "Some account";
accountInfoUpdateService.create(accountId, customerId, title, initialBalance, description, version);
String transactionId = x.genId().asString();
AccountTransactionInfo transactionInfo = new AccountTransactionInfo();
transactionInfo.setTransactionId(transactionId);
transactionInfo.setStatus(TransferState.INITIAL);
accountInfoUpdateService.addTransaction(accountId, transactionInfo);
AccountInfo accountInfo = accountQueryService.findByAccountId(accountId);
assertEquals(accountId, accountInfo.getId());
assertFalse(accountInfo.getTransactions().isEmpty());
assertEquals(1, accountInfo.getTransactions().size());
assertEquals(TransferState.INITIAL, accountInfo.getTransactions().get(0).getStatus());
accountInfoUpdateService.updateTransactionStatus(accountId, transactionId, TransferState.COMPLETED);
accountInfo = accountQueryService.findByAccountId(accountId);
assertEquals(accountId, accountInfo.getId());
assertFalse(accountInfo.getTransactions().isEmpty());
assertEquals(1, accountInfo.getTransactions().size());
assertEquals(TransferState.COMPLETED, accountInfo.getTransactions().get(0).getStatus());
}
} }

View File

@@ -30,7 +30,7 @@ public class AccountsQuerySideServiceIntegrationTest {
private int port; private int port;
private String baseUrl(String path) { private String baseUrl(String path) {
return "http://localhost:" + port + "/" + path; return "http://localhost:" + port + "/api" + path;
} }
@Autowired @Autowired

View File

@@ -4,18 +4,19 @@ import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.acc
import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts.AccountNotFoundException; import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts.AccountNotFoundException;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts.AccountQueryService; import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts.AccountQueryService;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountTransactionInfo; import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.*;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.GetAccountResponse;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@RestController @RestController
@RequestMapping("/api")
public class AccountQueryController { public class AccountQueryController {
private AccountQueryService accountInfoQueryService; private AccountQueryService accountInfoQueryService;
@@ -26,21 +27,35 @@ public class AccountQueryController {
} }
@RequestMapping(value = "/accounts/{accountId}", method = RequestMethod.GET) @RequestMapping(value = "/accounts/{accountId}", method = RequestMethod.GET)
public CompletableFuture<GetAccountResponse> get(@PathVariable String accountId) { public ResponseEntity<GetAccountResponse> get(@PathVariable String accountId) {
return accountInfoQueryService.findByAccountId(accountId) AccountInfo accountInfo = accountInfoQueryService.findByAccountId(accountId);
.thenApply(accountInfo -> new GetAccountResponse(accountInfo.getId(), new BigDecimal(accountInfo.getBalance()), accountInfo.getTitle(), accountInfo.getDescription())); return ResponseEntity.ok().body(new GetAccountResponse(accountInfo.getId(), new BigDecimal(accountInfo.getBalance()), accountInfo.getTitle(), accountInfo.getDescription()));
} }
@RequestMapping(value = "/accounts", method = RequestMethod.GET) @RequestMapping(value = "/customers/{customerId}/accounts", method = RequestMethod.GET)
public CompletableFuture<List<GetAccountResponse>> getAccountsForCustomer(@RequestParam("customerId") String customerId) { public ResponseEntity<GetAccountsResponse> getAccountsForCustomer(@PathVariable("customerId") String customerId) {
return accountInfoQueryService.findByCustomerId(customerId) return ResponseEntity.ok().body(
.thenApply(accountInfoList -> accountInfoList.stream().map(accountInfo -> new GetAccountResponse(accountInfo.getId(), new BigDecimal(accountInfo.getBalance()), accountInfo.getTitle(), accountInfo.getDescription())).collect(Collectors.toList())); new GetAccountsResponse(
accountInfoQueryService.findByCustomerId(customerId)
.stream()
.map(accountInfo -> new GetAccountResponse(
accountInfo.getId(),
new BigDecimal(accountInfo.getBalance()),
accountInfo.getTitle(),
accountInfo.getDescription()))
.collect(Collectors.toList())
)
);
} }
@RequestMapping(value = "/accounts/{accountId}/history", method = RequestMethod.GET) @RequestMapping(value = "/accounts/{accountId}/history", method = RequestMethod.GET)
public CompletableFuture<List<AccountTransactionInfo>> getTransactionsHistory(@PathVariable String accountId) { public ResponseEntity<AccountHistoryResponse> getTransactionsHistory(@PathVariable String accountId) {
return accountInfoQueryService.findByAccountId(accountId) AccountInfo accountInfo = accountInfoQueryService.findByAccountId(accountId);
.thenApply(AccountInfo::getTransactions); List<AccountHistoryEntry> historyEntries = new ArrayList<>();
historyEntries.add(new AccountOpenInfo(accountInfo.getDate(), AccountHistoryEntry.EntryType.account, accountInfo.getChanges().get(0).getAmount()));
accountInfo.getTransactions().forEach(historyEntries::add);
return ResponseEntity.ok().body(new AccountHistoryResponse(historyEntries));
} }
@ResponseStatus(value= HttpStatus.NOT_FOUND, reason="account not found") @ResponseStatus(value= HttpStatus.NOT_FOUND, reason="account not found")

View File

@@ -4,6 +4,7 @@ import net.chrisrichardson.eventstore.javaexamples.banking.apigateway.ApiGateway
import net.chrisrichardson.eventstore.javaexamples.banking.apigateway.utils.ContentRequestTransformer; import net.chrisrichardson.eventstore.javaexamples.banking.apigateway.utils.ContentRequestTransformer;
import net.chrisrichardson.eventstore.javaexamples.banking.apigateway.utils.HeadersRequestTransformer; import net.chrisrichardson.eventstore.javaexamples.banking.apigateway.utils.HeadersRequestTransformer;
import net.chrisrichardson.eventstore.javaexamples.banking.apigateway.utils.URLRequestTransformer; import net.chrisrichardson.eventstore.javaexamples.banking.apigateway.utils.URLRequestTransformer;
import org.apache.http.Header;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient; import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.HttpUriRequest;
@@ -12,9 +13,12 @@ import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException; import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException;
@@ -26,6 +30,7 @@ import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.springframework.web.bind.annotation.RequestMethod.GET; import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST; import static org.springframework.web.bind.annotation.RequestMethod.POST;
@@ -52,13 +57,20 @@ public class GatewayController {
.build(); .build();
} }
@RequestMapping(value = "/**", method = {GET, POST}) @RequestMapping(value = "/api/**", method = {GET, POST})
@ResponseBody
public ResponseEntity<String> proxyRequest(HttpServletRequest request) throws NoSuchRequestHandlingMethodException, IOException, URISyntaxException { public ResponseEntity<String> proxyRequest(HttpServletRequest request) throws NoSuchRequestHandlingMethodException, IOException, URISyntaxException {
HttpUriRequest proxiedRequest = createHttpUriRequest(request); HttpUriRequest proxiedRequest = createHttpUriRequest(request);
logger.info("request: {}", proxiedRequest); logger.info("request: {}", proxiedRequest);
HttpResponse proxiedResponse = httpClient.execute(proxiedRequest); HttpResponse proxiedResponse = httpClient.execute(proxiedRequest);
logger.info("Response {}", proxiedResponse.getStatusLine().getStatusCode()); logger.info("Response {}", proxiedResponse.getStatusLine().getStatusCode());
return new ResponseEntity<>(read(proxiedResponse.getEntity().getContent()), HttpStatus.valueOf(proxiedResponse.getStatusLine().getStatusCode())); return new ResponseEntity<>(read(proxiedResponse.getEntity().getContent()), processHeaders(proxiedResponse.getAllHeaders()), HttpStatus.valueOf(proxiedResponse.getStatusLine().getStatusCode()));
}
private HttpHeaders processHeaders(Header[] headers) {
HttpHeaders result = new HttpHeaders();
Stream.of(headers).filter(h -> h.getName().equalsIgnoreCase("Content-Type")).forEach( h -> result.set(h.getName(), h.getValue()));
return result;
} }
private HttpUriRequest createHttpUriRequest(HttpServletRequest request) throws URISyntaxException, NoSuchRequestHandlingMethodException, IOException { private HttpUriRequest createHttpUriRequest(HttpServletRequest request) throws URISyntaxException, NoSuchRequestHandlingMethodException, IOException {

View File

@@ -5,18 +5,21 @@ customers.queryside.service.host=localhost
transfers.commandside.service.host=localhost transfers.commandside.service.host=localhost
api.gateway.endpoints[0].path=[/]*accounts.* api.gateway.endpoints[0].path=[/]*api/accounts.*
api.gateway.endpoints[0].method=GET api.gateway.endpoints[0].method=GET
api.gateway.endpoints[0].location=http://${accounts.queryside.service.host}:8080 api.gateway.endpoints[0].location=http://${accounts.queryside.service.host}:8080
api.gateway.endpoints[1].path=[/]*accounts.* api.gateway.endpoints[1].path=[/]*api/customers.*/accounts
api.gateway.endpoints[1].method=POST api.gateway.endpoints[1].method=GET
api.gateway.endpoints[1].location=http://${accounts.commandside.service.host}:8080 api.gateway.endpoints[1].location=http://${accounts.queryside.service.host}:8080
api.gateway.endpoints[2].path=[/]*customers.* api.gateway.endpoints[2].path=[/]*api/accounts.*
api.gateway.endpoints[2].method=GET api.gateway.endpoints[2].method=POST
api.gateway.endpoints[2].location=http://${customers.queryside.service.host}:8080 api.gateway.endpoints[2].location=http://${accounts.commandside.service.host}:8080
api.gateway.endpoints[3].path=[/]*customers.* api.gateway.endpoints[3].path=[/]*api/customers.*
api.gateway.endpoints[3].method=POST api.gateway.endpoints[3].method=GET
api.gateway.endpoints[3].location=http://${customers.commandside.service.host}:8080 api.gateway.endpoints[3].location=http://${customers.queryside.service.host}:8080
api.gateway.endpoints[4].path=[/]*transfers.* api.gateway.endpoints[4].path=[/]*api/customers.*
api.gateway.endpoints[4].method=POST api.gateway.endpoints[4].method=POST
api.gateway.endpoints[4].location=http://${transfers.commandside.service.host}:8080 api.gateway.endpoints[4].location=http://${customers.commandside.service.host}:8080
api.gateway.endpoints[5].path=[/]*api/transfers.*
api.gateway.endpoints[5].method=POST
api.gateway.endpoints[5].location=http://${transfers.commandside.service.host}:8080

View File

@@ -6,7 +6,7 @@ import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.a
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.accounts.AccountService; import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.accounts.AccountService;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.transactions.MoneyTransfer; import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.transactions.MoneyTransfer;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.transactions.MoneyTransferService; import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.transactions.MoneyTransferService;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.transactions.TransferState; import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.TransferState;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.TransferDetails; import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.TransferDetails;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;

View File

@@ -6,7 +6,7 @@ import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.a
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.accounts.AccountService; import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.accounts.AccountService;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.transactions.MoneyTransfer; import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.transactions.MoneyTransfer;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.transactions.MoneyTransferService; import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.transactions.MoneyTransferService;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.transactions.TransferState; import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.TransferState;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.TransferDetails; import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.TransferDetails;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@@ -17,6 +17,7 @@ import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.concurrent.CompletableFuture;
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.TestUtil.await; import static net.chrisrichardson.eventstorestore.javaexamples.testutil.TestUtil.await;
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.TestUtil.eventually; import static net.chrisrichardson.eventstorestore.javaexamples.testutil.TestUtil.eventually;
@@ -55,10 +56,10 @@ public class AccountQuerySideIntegrationTest {
updatedTransaction -> Assert.assertEquals(TransferState.COMPLETED, updatedTransaction.getEntity().getState())); updatedTransaction -> Assert.assertEquals(TransferState.COMPLETED, updatedTransaction.getEntity().getState()));
eventually( eventually(
() -> accountQueryService.findByAccountId(fromAccount.getEntityId()), () -> CompletableFuture.completedFuture(accountQueryService.findByAccountId(fromAccount.getEntityId())),
accountInfo -> Assert.assertEquals(70 * 100, accountInfo.getBalance())); accountInfo -> Assert.assertEquals(70 * 100, accountInfo.getBalance()));
eventually( eventually(
() -> accountQueryService.findByAccountId(toAccount.getEntityId()), () -> CompletableFuture.completedFuture(accountQueryService.findByAccountId(toAccount.getEntityId())),
accountInfo -> Assert.assertEquals(380 * 100, accountInfo.getBalance())); accountInfo -> Assert.assertEquals(380 * 100, accountInfo.getBalance()));
} }
} }

View File

@@ -28,6 +28,7 @@ import static org.springframework.web.bind.annotation.RequestMethod.POST;
*/ */
@RestController @RestController
@Validated @Validated
@RequestMapping("/api")
public class AuthController { public class AuthController {
@Autowired @Autowired

View File

@@ -80,7 +80,7 @@ public class AuthConfiguration extends WebSecurityConfigurerAdapter {
.authorizeRequests() .authorizeRequests()
.antMatchers("/index.html", "/", "/**.js", "/**.css").permitAll() .antMatchers("/index.html", "/", "/**.js", "/**.css").permitAll()
.antMatchers("/swagger-ui.html", "/v2/api-docs").permitAll() .antMatchers("/swagger-ui.html", "/v2/api-docs").permitAll()
.antMatchers(HttpMethod.POST, "/customers", "/login").permitAll() .antMatchers(HttpMethod.POST, "/api/customers", "/api/login").permitAll()
.anyRequest().authenticated().and() .anyRequest().authenticated().and()
.addFilterAfter(new StatelessAuthenticationFilter(tokenAuthenticationService), BasicAuthenticationFilter.class); .addFilterAfter(new StatelessAuthenticationFilter(tokenAuthenticationService), BasicAuthenticationFilter.class);
} }

View File

@@ -0,0 +1,80 @@
package net.chrisrichardson.eventstore.javaexamples.banking.common.accounts;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import java.util.Date;
public class AccountChangeInfo {
private String changeId;
private String transactionId;
private String transactionType;
private long amount;
private long balanceDelta;
public AccountChangeInfo() {
}
public AccountChangeInfo(String changeId, String transactionId, String transactionType, long amount, long balanceDelta) {
this(new Date(), changeId, transactionId, transactionType, amount, balanceDelta);
}
public AccountChangeInfo(Date date, String changeId, String transactionId, String transactionType, long amount, long balanceDelta) {
this.changeId = changeId;
this.transactionId = transactionId;
this.transactionType = transactionType;
this.amount = amount;
this.balanceDelta = balanceDelta;
}
public String getChangeId() {
return changeId;
}
public void setChangeId(String changeId) {
this.changeId = changeId;
}
public String getTransactionId() {
return transactionId;
}
public void setTransactionId(String transactionId) {
this.transactionId = transactionId;
}
public String getTransactionType() {
return transactionType;
}
public void setTransactionType(String transactionType) {
this.transactionType = transactionType;
}
public long getAmount() {
return amount;
}
public void setAmount(long amount) {
this.amount = amount;
}
public long getBalanceDelta() {
return balanceDelta;
}
public void setBalanceDelta(long balanceDelta) {
this.balanceDelta = balanceDelta;
}
@Override
public boolean equals(Object o) {
return EqualsBuilder.reflectionEquals(this, o);
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
}

View File

@@ -0,0 +1,50 @@
package net.chrisrichardson.eventstore.javaexamples.banking.common.accounts;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import java.util.Date;
/**
* Created by popikyardo on 9/1/16.
*/
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS,
include = JsonTypeInfo.As.PROPERTY,
property = "entryType")
@JsonSubTypes({
@JsonSubTypes.Type(value = AccountTransactionInfo.class, name = "transaction"),
@JsonSubTypes.Type(value = AccountOpenInfo.class, name = "account")
})
public class AccountHistoryEntry {
protected Date date;
protected EntryType entryType;
public AccountHistoryEntry() {
}
public AccountHistoryEntry(Date date, EntryType entryType) {
this.date = date;
this.entryType = entryType;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public EntryType getEntryType() {
return entryType;
}
public void setEntryType(EntryType entryType) {
this.entryType = entryType;
}
public enum EntryType {
transaction, account
}
}

View File

@@ -0,0 +1,26 @@
package net.chrisrichardson.eventstore.javaexamples.banking.common.accounts;
import java.util.List;
/**
* Created by popikyardo on 9/1/16.
*/
public class AccountHistoryResponse {
private List<AccountHistoryEntry> transactionsHistory;
public AccountHistoryResponse() {
}
public AccountHistoryResponse(List<AccountHistoryEntry> transactionsHistory) {
this.transactionsHistory = transactionsHistory;
}
public List<AccountHistoryEntry> getTransactionsHistory() {
return transactionsHistory;
}
public void setTransactionsHistory(List<AccountHistoryEntry> transactionsHistory) {
this.transactionsHistory = transactionsHistory;
}
}

View File

@@ -0,0 +1,27 @@
package net.chrisrichardson.eventstore.javaexamples.banking.common.accounts;
import java.util.Date;
/**
* Created by popikyardo on 9/1/16.
*/
public class AccountOpenInfo extends AccountHistoryEntry {
private long initialBalance;
public AccountOpenInfo() {
}
public AccountOpenInfo(Date date, EntryType entryType, long initialBalance) {
super(date, entryType);
this.initialBalance=initialBalance;
}
public long getInitialBalance() {
return initialBalance;
}
public void setInitialBalance(long initialBalance) {
this.initialBalance = initialBalance;
}
}

View File

@@ -1,19 +1,20 @@
package net.chrisrichardson.eventstore.javaexamples.banking.common.accounts; package net.chrisrichardson.eventstore.javaexamples.banking.common.accounts;
import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.TransferState;
import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringBuilder;
import java.util.Date; import java.util.Date;
public class AccountTransactionInfo { public class AccountTransactionInfo extends AccountHistoryEntry{
private String transactionId; private String transactionId;
private String fromAccountId; private String fromAccountId;
private String toAccountId; private String toAccountId;
private long amount; private long amount;
private Date date;
private String description; private String description;
private TransferState status = TransferState.INITIAL;
public AccountTransactionInfo() { public AccountTransactionInfo() {
} }
@@ -35,6 +36,7 @@ public class AccountTransactionInfo {
this.amount = amount; this.amount = amount;
this.date = date; this.date = date;
this.description = description; this.description = description;
this.entryType = EntryType.transaction;
} }
public String getTransactionId() { public String getTransactionId() {
@@ -69,14 +71,6 @@ public class AccountTransactionInfo {
this.amount = amount; this.amount = amount;
} }
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String getDescription() { public String getDescription() {
return description; return description;
} }
@@ -85,6 +79,14 @@ public class AccountTransactionInfo {
this.description = description; this.description = description;
} }
public TransferState getStatus() {
return status;
}
public void setStatus(TransferState status) {
this.status = status;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return EqualsBuilder.reflectionEquals(this, o); return EqualsBuilder.reflectionEquals(this, o);

View File

@@ -0,0 +1,25 @@
package net.chrisrichardson.eventstore.javaexamples.banking.common.accounts;
import java.util.List;
/**
* Created by popikyardo on 9/1/16.
*/
public class GetAccountsResponse {
private List<GetAccountResponse> accounts;
public GetAccountsResponse() {
}
public GetAccountsResponse(List<GetAccountResponse> accounts) {
this.accounts = accounts;
}
public List<GetAccountResponse> getAccounts() {
return accounts;
}
public void setAccounts(List<GetAccountResponse> accounts) {
this.accounts = accounts;
}
}

View File

@@ -1,4 +1,4 @@
package net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.transactions; package net.chrisrichardson.eventstore.javaexamples.banking.common.transactions;
public enum TransferState { public enum TransferState {
NEW, INITIAL, DEBITED, COMPLETED, FAILED_DUE_TO_INSUFFICIENT_FUNDS NEW, INITIAL, DEBITED, COMPLETED, FAILED_DUE_TO_INSUFFICIENT_FUNDS

View File

@@ -4,10 +4,12 @@ import io.eventuate.AggregateRepository;
import io.eventuate.EventuateAggregateStore; import io.eventuate.EventuateAggregateStore;
import io.eventuate.javaclient.spring.EnableEventHandlers; import io.eventuate.javaclient.spring.EnableEventHandlers;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@Configuration @Configuration
@EnableEventHandlers @EnableEventHandlers
@ComponentScan
public class CustomerConfiguration { public class CustomerConfiguration {
@Bean @Bean

View File

@@ -6,7 +6,6 @@ import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.custo
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.web.HttpMessageConverters; import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter;
@@ -15,7 +14,6 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert
@Configuration @Configuration
@Import({CustomersCommandSideWebConfiguration.class, EventuateHttpStompClientConfiguration.class, CommonSwaggerConfiguration.class}) @Import({CustomersCommandSideWebConfiguration.class, EventuateHttpStompClientConfiguration.class, CommonSwaggerConfiguration.class})
@EnableAutoConfiguration @EnableAutoConfiguration
@ComponentScan
public class CustomersCommandSideServiceConfiguration { public class CustomersCommandSideServiceConfiguration {

View File

@@ -25,7 +25,7 @@ public class CustomersCommandSideServiceIntegrationTest {
private int port; private int port;
private String baseUrl(String path) { private String baseUrl(String path) {
return "http://localhost:" + port + "/" + path; return "http://localhost:" + port + "/api" + path;
} }
@Autowired @Autowired

View File

@@ -15,7 +15,7 @@ import java.util.concurrent.CompletableFuture;
* Created by popikyardo on 03.02.16. * Created by popikyardo on 03.02.16.
*/ */
@RestController @RestController
@RequestMapping("/customers") @RequestMapping("/api/customers")
public class CustomerController { public class CustomerController {
private CustomerService customerService; private CustomerService customerService;

View File

@@ -5,6 +5,7 @@ import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.Quer
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.ToAccountInfo; import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.ToAccountInfo;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import java.util.Collections; import java.util.Collections;
@@ -13,36 +14,38 @@ import java.util.Collections;
*/ */
public class CustomerInfoUpdateService { public class CustomerInfoUpdateService {
private Logger logger = LoggerFactory.getLogger(getClass()); private Logger logger = LoggerFactory.getLogger(getClass());
private QuerySideCustomerRepository accountInfoRepository; private QuerySideCustomerRepository querySideCustomerRepository;
public CustomerInfoUpdateService(QuerySideCustomerRepository accountInfoRepository) { public CustomerInfoUpdateService(QuerySideCustomerRepository querySideCustomerRepository) {
this.accountInfoRepository = accountInfoRepository; this.querySideCustomerRepository = querySideCustomerRepository;
}
public void create(String id, CustomerInfo customerInfo) {
try {
accountInfoRepository.save(new QuerySideCustomer(id,
customerInfo.getName(),
customerInfo.getEmail(),
customerInfo.getSsn(),
customerInfo.getPhoneNumber(),
customerInfo.getAddress(),
Collections.<String, ToAccountInfo>emptyMap()
)
);
logger.info("Saved in mongo");
} catch (Throwable t) {
logger.error("Error during saving: ", t);
throw new RuntimeException(t);
} }
}
public void addToAccount(String id, ToAccountInfo accountInfo) { public void create(String id, CustomerInfo customerInfo) {
QuerySideCustomer customer = accountInfoRepository.findOne(id); try {
customer.getToAccounts().put(accountInfo.getId(), accountInfo); querySideCustomerRepository.save(new QuerySideCustomer(id,
accountInfoRepository.save(customer); customerInfo.getName(),
} customerInfo.getEmail(),
customerInfo.getSsn(),
customerInfo.getPhoneNumber(),
customerInfo.getAddress(),
Collections.<String, ToAccountInfo>emptyMap()
)
);
logger.info("Saved in mongo");
} catch (DuplicateKeyException t) {
logger.warn("When saving ", t);
} catch (Throwable t) {
logger.error("Error during saving: ", t);
throw new RuntimeException(t);
}
}
public void addToAccount(String id, ToAccountInfo accountInfo) {
QuerySideCustomer customer = querySideCustomerRepository.findOne(id);
customer.getToAccounts().put(accountInfo.getId(), accountInfo);
querySideCustomerRepository.save(customer);
}
} }

View File

@@ -2,6 +2,7 @@ package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.cu
import io.eventuate.javaclient.spring.EnableEventHandlers; import io.eventuate.javaclient.spring.EnableEventHandlers;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
@@ -12,6 +13,7 @@ import org.springframework.data.mongodb.repository.config.EnableMongoRepositorie
@Configuration @Configuration
@EnableMongoRepositories @EnableMongoRepositories
@EnableEventHandlers @EnableEventHandlers
@ComponentScan
public class QuerySideCustomerConfiguration { public class QuerySideCustomerConfiguration {
@Bean @Bean
public CustomerQueryWorkflow customerQueryWorkflow(CustomerInfoUpdateService accountInfoUpdateService) { public CustomerQueryWorkflow customerQueryWorkflow(CustomerInfoUpdateService accountInfoUpdateService) {

View File

@@ -1,21 +1,19 @@
package net.chrisrichardson.eventstore.javaexamples.banking.web; package net.chrisrichardson.eventstore.javaexamples.banking.web;
import io.eventuate.javaclient.spring.httpstomp.EventuateHttpStompClientConfiguration; import io.eventuate.javaclient.spring.httpstomp.EventuateHttpStompClientConfiguration;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.customers.QuerySideCustomerConfiguration;
import net.chrisrichardson.eventstore.javaexamples.banking.commonswagger.CommonSwaggerConfiguration; import net.chrisrichardson.eventstore.javaexamples.banking.commonswagger.CommonSwaggerConfiguration;
import net.chrisrichardson.eventstore.javaexamples.banking.web.customers.queryside.CustomersQuerySideWebConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.web.HttpMessageConverters; import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
@Configuration @Configuration
@Import({QuerySideCustomerConfiguration.class, EventuateHttpStompClientConfiguration.class, CommonSwaggerConfiguration.class}) @Import({CustomersQuerySideWebConfiguration.class, EventuateHttpStompClientConfiguration.class, CommonSwaggerConfiguration.class})
@EnableAutoConfiguration @EnableAutoConfiguration
@ComponentScan
public class CustomersQuerySideServiceConfiguration { public class CustomersQuerySideServiceConfiguration {

View File

@@ -1,9 +1,8 @@
package net.chrisrichardson.eventstore.javaexamples.banking.web; package net.chrisrichardson.eventstore.javaexamples.banking.web;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.*; import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.CustomerInfo;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.CustomerResponse;
import net.chrisrichardson.eventstorestore.javaexamples.testutil.CustomersTestUtils; import net.chrisrichardson.eventstorestore.javaexamples.testutil.CustomersTestUtils;
import org.apache.tomcat.jni.Thread;
import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -13,7 +12,6 @@ import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import rx.Observable;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
@@ -29,7 +27,7 @@ public class CustomersQuerySideServiceIntegrationTest {
private int port; private int port;
private String baseUrl(String path) { private String baseUrl(String path) {
return "http://localhost:" + port + "/" + path; return "http://localhost:" + port + "/api" + path;
} }
@Autowired @Autowired
@@ -51,12 +49,6 @@ public class CustomersQuerySideServiceIntegrationTest {
final CustomerResponse customerResponse = restTemplate.postForEntity(baseUrl("/customers"), customerInfo, CustomerResponse.class).getBody(); final CustomerResponse customerResponse = restTemplate.postForEntity(baseUrl("/customers"), customerInfo, CustomerResponse.class).getBody();
final String customerId = customerResponse.getId(); final String customerId = customerResponse.getId();
try {
java.lang.Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
customersTestUtils.assertCustomerResponse(customerId, customerInfo); customersTestUtils.assertCustomerResponse(customerId, customerInfo);
} }

View File

@@ -14,6 +14,7 @@ import java.util.concurrent.CompletableFuture;
* Created by Main on 05.02.2016. * Created by Main on 05.02.2016.
*/ */
@RestController @RestController
@RequestMapping("/api")
public class CustomerQueryController { public class CustomerQueryController {
private CustomerQueryService customerQueryService; private CustomerQueryService customerQueryService;

View File

@@ -3,7 +3,7 @@ apigateway:
working_dir: /app working_dir: /app
volumes: volumes:
- ./api-gateway-service/build/libs:/app - ./api-gateway-service/build/libs:/app
command: java -jar /app/api-gateway-service.jar --accounts.commandside.service.host=accountscommandside --transactions.commandside.service.host=transactionscommandside --accounts.queryside.service.host=accountsqueryside --customers.commandside.service.host=customerscommandside --customers.queryside.service.host=customersqueryside command: java -jar /app/api-gateway-service.jar --accounts.commandside.service.host=accountscommandside --transfers.commandside.service.host=transactionscommandside --accounts.queryside.service.host=accountsqueryside --customers.commandside.service.host=customerscommandside --customers.queryside.service.host=customersqueryside
ports: ports:
- "8080:8080" - "8080:8080"
links: links:

View File

@@ -18,7 +18,7 @@ public class EndToEndTest extends AbstractRestAPITest {
CustomersTestUtils customersTestUtils = new CustomersTestUtils(restTemplate, baseUrl("/customers/")); CustomersTestUtils customersTestUtils = new CustomersTestUtils(restTemplate, baseUrl("/customers/"));
public String baseUrl(String path) { public String baseUrl(String path) {
return "http://" + getenv("SERVICE_HOST", "localhost") + ":" + 8080 + "/" + path; return "http://" + getenv("SERVICE_HOST", "localhost") + ":" + 8080 + "/api" + path;
} }
@Override @Override

View File

@@ -22,7 +22,7 @@ dependencies {
} }
task copyWebStatic(type: Copy) { task copyWebStatic(type: Copy) {
from "../../prebuilt-web-client" from "../../js-frontend/build"
into "build/resources/main/static" into "build/resources/main/static"
} }

View File

@@ -43,7 +43,7 @@ public class BankingAuthTest {
} }
private String baseUrl(String path) { private String baseUrl(String path) {
return "http://localhost:" + port + "/" + path; return "http://localhost:" + port + "/api" + path;
} }
@Test @Test

View File

@@ -32,7 +32,7 @@ public class BankingWebIntegrationTest extends AbstractRestAPITest {
@Override @Override
public String baseUrl(String path) { public String baseUrl(String path) {
return "http://localhost:" + port + "/" + path; return "http://localhost:" + port + "/api" + path;
} }
@Override @Override

View File

@@ -1,9 +1,6 @@
package net.chrisrichardson.eventstorestore.javaexamples.testutil; package net.chrisrichardson.eventstorestore.javaexamples.testutil;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountTransactionInfo; import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.*;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.CreateAccountRequest;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.CreateAccountResponse;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.GetAccountResponse;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.CustomerInfo; import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.CustomerInfo;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.CustomerResponse; import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.CustomerResponse;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.QuerySideCustomer; import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.QuerySideCustomer;
@@ -51,12 +48,6 @@ public abstract class AbstractRestAPITest {
Assert.assertNotNull(fromAccountId); Assert.assertNotNull(fromAccountId);
Assert.assertNotNull(toAccountId); Assert.assertNotNull(toAccountId);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
assertAccountBalance(fromAccountId, initialFromAccountBalance); assertAccountBalance(fromAccountId, initialFromAccountBalance);
assertAccountBalance(toAccountId, initialToAccountBalance); assertAccountBalance(toAccountId, initialToAccountBalance);
@@ -68,21 +59,21 @@ public abstract class AbstractRestAPITest {
assertAccountBalance(toAccountId, finalToAccountBalance); assertAccountBalance(toAccountId, finalToAccountBalance);
eventually( eventually(
new Producer<AccountTransactionInfo[]>() { new Producer<AccountHistoryResponse>() {
@Override @Override
public CompletableFuture<AccountTransactionInfo[]> produce() { public CompletableFuture<AccountHistoryResponse> produce() {
return CompletableFuture.completedFuture(getAuthenticatedRestTemplate().getForEntity(baseUrl("/accounts/" + fromAccountId + "/history"), return CompletableFuture.completedFuture(getAuthenticatedRestTemplate().getForEntity(baseUrl("/accounts/" + fromAccountId + "/history"),
AccountTransactionInfo[].class)); AccountHistoryResponse.class));
} }
}, },
new Verifier<AccountTransactionInfo[]>() { new Verifier<AccountHistoryResponse>() {
@Override @Override
public void verify(AccountTransactionInfo[] transactionInfos) { public void verify(AccountHistoryResponse accountHistoryResponse) {
Optional<AccountTransactionInfo> first = Arrays.asList(transactionInfos).stream().filter(ti -> ti.getTransactionId().equals(moneyTransfer.getMoneyTransferId())).findFirst(); Optional<AccountHistoryEntry> first = accountHistoryResponse.getTransactionsHistory().stream().filter( ahe -> ahe.getEntryType() == AccountHistoryEntry.EntryType.transaction && ((AccountTransactionInfo)ahe).getTransactionId().equals(moneyTransfer.getMoneyTransferId())).findFirst();
assertTrue(first.isPresent()); assertTrue(first.isPresent());
AccountTransactionInfo ti = first.get(); AccountTransactionInfo ti = (AccountTransactionInfo)first.get();
assertEquals(fromAccountId, ti.getFromAccountId()); assertEquals(fromAccountId, ti.getFromAccountId());
assertEquals(toAccountId, ti.getToAccountId()); assertEquals(toAccountId, ti.getToAccountId());
@@ -104,12 +95,6 @@ public abstract class AbstractRestAPITest {
Assert.assertNotNull(customerId); Assert.assertNotNull(customerId);
assertEquals(customerInfo, customerResponse.getCustomerInfo()); assertEquals(customerInfo, customerResponse.getCustomerInfo());
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
getCustomersTestUtils().assertCustomerResponse(customerId, customerInfo); getCustomersTestUtils().assertCustomerResponse(customerId, customerInfo);
final CreateAccountResponse account = getAuthenticatedRestTemplate().postForEntity(baseUrl("/accounts"), final CreateAccountResponse account = getAuthenticatedRestTemplate().postForEntity(baseUrl("/accounts"),
@@ -123,17 +108,17 @@ public abstract class AbstractRestAPITest {
assertAccountBalance(accountId, initialFromAccountBalance); assertAccountBalance(accountId, initialFromAccountBalance);
eventually( eventually(
new Producer<GetAccountResponse[]>() { new Producer<GetAccountsResponse>() {
@Override @Override
public CompletableFuture<GetAccountResponse[]> produce() { public CompletableFuture<GetAccountsResponse> produce() {
return CompletableFuture.completedFuture(getAuthenticatedRestTemplate().getForEntity(baseUrl("/accounts?customerId=" + customerId), return CompletableFuture.completedFuture(getAuthenticatedRestTemplate().getForEntity(baseUrl("/customers/"+customerId+"/accounts"),
GetAccountResponse[].class)); GetAccountsResponse.class));
} }
}, },
new Verifier<GetAccountResponse[]>() { new Verifier<GetAccountsResponse>() {
@Override @Override
public void verify(GetAccountResponse[] accountResponses) { public void verify(GetAccountsResponse accountResponses) {
assertTrue(Arrays.asList(accountResponses).stream().filter(acc -> acc.getAccountId().equals(accountId)).findFirst().isPresent()); assertTrue(accountResponses.getAccounts().stream().filter(acc -> acc.getAccountId().equals(accountId)).findFirst().isPresent());
} }
}); });
} }

View File

@@ -1,6 +1,5 @@
package net.chrisrichardson.eventstorestore.javaexamples.testutil; package net.chrisrichardson.eventstorestore.javaexamples.testutil;
import net.chrisrichardson.eventstore.javaexamples.banking.commonauth.utils.BasicAuthUtils;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;

View File

@@ -1,4 +1,4 @@
package net.chrisrichardson.eventstore.javaexamples.banking.commonauth.utils; package net.chrisrichardson.eventstorestore.javaexamples.testutil;
import org.apache.tomcat.util.codec.binary.Base64; import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.http.*; import org.springframework.http.*;

View File

@@ -6,7 +6,6 @@ import org.springframework.web.client.RestTemplate;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.TestUtil.awaitSuccessfulRequest;
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.TestUtil.eventually; import static net.chrisrichardson.eventstorestore.javaexamples.testutil.TestUtil.eventually;
/** /**

View File

@@ -1,7 +1,5 @@
package net.chrisrichardson.eventstorestore.javaexamples.testutil; package net.chrisrichardson.eventstorestore.javaexamples.testutil;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import rx.Observable; import rx.Observable;
import rx.Subscriber; import rx.Subscriber;
import rx.functions.Action1; import rx.functions.Action1;
@@ -13,7 +11,6 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.function.Supplier;
public class TestUtil { public class TestUtil {
@@ -25,18 +22,6 @@ public class TestUtil {
} }
} }
public static <T> T awaitSuccessfulRequest(Supplier<ResponseEntity<T>> func, Func1<T, Boolean> predicate) {
try {
return Observable.interval(400, TimeUnit.MILLISECONDS)
.take(50)
.map(x -> func.get())
.filter(re -> re.getStatusCode().equals(HttpStatus.OK) && re.getBody() != null && predicate.call(re.getBody()))
.toBlocking().first().getBody();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
static class Tuple2<A, B> { static class Tuple2<A, B> {
private A first; private A first;
@@ -52,7 +37,7 @@ public class TestUtil {
} }
static class Success<T> implements Outcome<T> { static class Success<T> implements Outcome<T> {
T value; T value;
@@ -69,51 +54,26 @@ public class TestUtil {
} }
} }
public static <T> void eventually(final Producer<T> producer, final Verifier<T> verifier) { public static <T> void eventually(Producer<T> producer, Verifier<T> predicate) {
final int n = 150; Throwable laste = null;
Object possibleException = Observable.timer(0, 200, TimeUnit.MILLISECONDS).flatMap(new Func1<Long, Observable<Outcome<T>>>() { for (int i = 0; i < 30 ; i++) {
try {
@Override T x = producer.produce().get(30, TimeUnit.SECONDS);
public Observable<Outcome<T>> call(Long aLong) { predicate.verify(x);
try { return;
return fromCompletableFuture(producer.produce()).map(new Func1<T, Outcome<T>>() { } catch (Throwable t) {
@Override laste = t;
public Outcome<T> call(T t) {
return new Success<T>(t);
}
});
} catch (Exception e) {
Outcome<T> value = new Failure<T>(e);
return Observable.just(value);
}
} }
}).map(new Func1<Outcome<T>, Throwable>() { try {
@Override TimeUnit.SECONDS.sleep(1);
public Throwable call(Outcome<T> t) { } catch (InterruptedException e) {
try { throw new RuntimeException(e);
if (t instanceof Success) {
verifier.verify(((Success<T>) t).value);
return null;
} else
return ((Failure<T>) t).t;
} catch (Throwable e) {
return e;
}
} }
}).take(n).zipWith(Observable.range(0, n), new Func2<Throwable, Integer, Tuple2<Throwable, Integer>>() { }
@Override if (laste != null)
public Tuple2<Throwable, Integer> call(Throwable e, Integer idx) { throw new RuntimeException("Last exception was", laste);
return new Tuple2<Throwable, Integer>(e, idx); else
} throw new RuntimeException("predicate never satisfied");
}).skipWhile(new Func1<Tuple2<Throwable, Integer>, Boolean>() {
@Override
public Boolean call(Tuple2<Throwable, Integer> tuple2) {
return tuple2.first != null && tuple2.second < n - 1;
}
}).first().toBlocking().getIterator().next().first;
if (possibleException != null)
throw new RuntimeException((Throwable) possibleException);
} }
private static <T> Observable<T> fromCompletableFuture(CompletableFuture<T> future) { private static <T> Observable<T> fromCompletableFuture(CompletableFuture<T> future) {

View File

@@ -4,6 +4,7 @@ import io.eventuate.Event;
import io.eventuate.EventUtil; import io.eventuate.EventUtil;
import io.eventuate.ReflectiveMutableCommandProcessingAggregate; import io.eventuate.ReflectiveMutableCommandProcessingAggregate;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.*; import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.*;
import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.TransferState;
import java.util.List; import java.util.List;

View File

@@ -20,7 +20,7 @@ public class TransactionsCommandSideServiceIntegrationTest {
private int port; private int port;
private String baseUrl(String path) { private String baseUrl(String path) {
return "http://localhost:" + port + "/" + path; return "http://localhost:" + port + "/api" + path;
} }
@Autowired @Autowired

View File

@@ -16,7 +16,7 @@ import java.util.Date;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@RestController @RestController
@RequestMapping("/transfers") @RequestMapping("/api/transfers")
public class MoneyTransferController { public class MoneyTransferController {
private final MoneyTransferService moneyTransferService; private final MoneyTransferService moneyTransferService;

View File

@@ -36,7 +36,7 @@ public class MoneyTransferControllerIntegrationTest {
@Test @Test
public void shouldCreateAccount() throws Exception { public void shouldCreateAccount() throws Exception {
mockMvc.perform(post("/transfers") mockMvc.perform(post("/api/transfers")
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content("{\"fromAccountId\" : \"fromAccountId\", \"toAccountId\" : \"toAccountId\", \"amount\" : \"500\"}") .content("{\"fromAccountId\" : \"fromAccountId\", \"toAccountId\" : \"toAccountId\", \"amount\" : \"500\"}")
.accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
@@ -45,7 +45,7 @@ public class MoneyTransferControllerIntegrationTest {
@Test @Test
public void shouldRejectBadRequest() throws Exception { public void shouldRejectBadRequest() throws Exception {
mockMvc.perform(post("/transfers") mockMvc.perform(post("/api/transfers")
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content("{\"fromAccountId\" : \"fromAccountIdXXXXXX\"}, {\"toAccountId\" : \"toAccountId\"}, {\"amount\" : \"500\"}") .content("{\"fromAccountId\" : \"fromAccountIdXXXXXX\"}, {\"toAccountId\" : \"toAccountId\"}, {\"amount\" : \"500\"}")
.accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))

File diff suppressed because one or more lines are too long

View File

@@ -185,11 +185,11 @@ webpackJsonp([0,3],{
return store.dispatch((0, _configure.configure)([{ return store.dispatch((0, _configure.configure)([{
default: { default: {
//apiUrl: '/', //apiUrl: '/',
emailSignInPath: '/login', emailSignInPath: '/api/login',
customersPath: '/customers', customersPath: '/api/customers',
currentUserPath: '/user', currentUserPath: '/api/user',
accountsPath: '/accounts', accountsPath: '/api/accounts',
transfersPath: '/transfers' transfersPath: '/api/transfers'
} }
}], { }], {
cookies: cookies, cookies: cookies,
@@ -1403,6 +1403,9 @@ webpackJsonp([0,3],{
var state = arguments.length <= 0 || arguments[0] === undefined ? _extends({}, initialState) : arguments[0]; var state = arguments.length <= 0 || arguments[0] === undefined ? _extends({}, initialState) : arguments[0];
var action = arguments[1]; var action = arguments[1];
if (typeof action.length !== 'undefined') {
debugger;
}
switch (action.type) { switch (action.type) {
case _ACTION_TYPES2.default.ENTITIES.REQUESTED: case _ACTION_TYPES2.default.ENTITIES.REQUESTED:
{ {
@@ -1829,7 +1832,7 @@ webpackJsonp([0,3],{
var _authenticate = __webpack_require__(316); var _authenticate = __webpack_require__(316);
var _sessionStorage = __webpack_require__(317); var _sessionStorage = __webpack_require__(318);
var _clientSettings = __webpack_require__(327); var _clientSettings = __webpack_require__(327);
@@ -1839,7 +1842,7 @@ webpackJsonp([0,3],{
var _reduxRouter = __webpack_require__(246); var _reduxRouter = __webpack_require__(246);
var _root = __webpack_require__(319); var _root = __webpack_require__(320);
var _root2 = _interopRequireDefault(_root); var _root2 = _interopRequireDefault(_root);
@@ -1919,35 +1922,32 @@ webpackJsonp([0,3],{
Object.defineProperty(exports, "__esModule", { Object.defineProperty(exports, "__esModule", {
value: true value: true
}); });
exports.authenticateStart = authenticateStart; exports.authenticateError = exports.authenticateComplete = exports.authenticateStart = undefined;
exports.authenticateComplete = authenticateComplete;
exports.authenticateError = authenticateError;
exports.authenticate = authenticate; exports.authenticate = authenticate;
var _ACTION_TYPES = __webpack_require__(295); var _ACTION_TYPES = __webpack_require__(295);
var _ACTION_TYPES2 = _interopRequireDefault(_ACTION_TYPES); var _ACTION_TYPES2 = _interopRequireDefault(_ACTION_TYPES);
var _sessionStorage = __webpack_require__(317); var _actions = __webpack_require__(317);
var _api = __webpack_require__(320); var _sessionStorage = __webpack_require__(318);
var _entities = __webpack_require__(325); var U = _interopRequireWildcard(_sessionStorage);
var _api = __webpack_require__(321);
var _entities = __webpack_require__(326);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/** var authenticateStart = exports.authenticateStart = (0, _actions.makeActionCreator)(_ACTION_TYPES2.default.AUTH.AUTHENTICATE_START); /**
* Created by andrew on 26/02/16. * Created by andrew on 26/02/16.
*/ */
function authenticateStart() { var authenticateComplete = exports.authenticateComplete = (0, _actions.makeActionCreator)(_ACTION_TYPES2.default.AUTH.AUTHENTICATE_COMPLETE, 'user');
return { type: _ACTION_TYPES2.default.AUTH.AUTHENTICATE_START }; var authenticateError = exports.authenticateError = (0, _actions.makeActionCreator)(_ACTION_TYPES2.default.AUTH.AUTHENTICATE_ERROR, 'errors');
}
function authenticateComplete(user) {
return { type: _ACTION_TYPES2.default.AUTH.AUTHENTICATE_COMPLETE, user: user };
}
function authenticateError(errors) {
return { type: _ACTION_TYPES2.default.AUTH.AUTHENTICATE_ERROR, errors: errors };
}
function authenticate(forceReread) { function authenticate(forceReread) {
return function (dispatch) { return function (dispatch) {
@@ -1956,25 +1956,24 @@ webpackJsonp([0,3],{
var savedUserPromise = new Promise(function (rs, rj) { var savedUserPromise = new Promise(function (rs, rj) {
var currentHeaders = (0, _sessionStorage.retrieveHeaders)(); var currentHeaders = U.retrieveHeaders();
var accessToken = currentHeaders["access-token"]; var accessToken = currentHeaders["access-token"];
if (!accessToken) { if (!accessToken) {
return rj({ reason: 'no token' }); return rj({ reason: 'no token' });
} }
var savedUser = (0, _sessionStorage.retrieveUserData)(); var savedUser = U.retrieveUserData();
if (savedUser && !forceReread) { if (savedUser && !forceReread) {
return rs(savedUser); return rs(savedUser);
} }
return (0, _api.apiGetCurrentUser)().then(function (userData) { return (0, _api.apiGetCurrentUser)().then(function (userData) {
(0, _sessionStorage.persistUserData)(userData); U.persistUserData(userData);
dispatch((0, _entities.entityReceived)(userData.id, userData)); dispatch((0, _entities.entityReceived)(userData.id, userData));
rs(userData); rs(userData);
}, function (err) { }, function (err) {
debugger;
rj(err); rj(err);
}); });
}); });
@@ -2011,6 +2010,43 @@ webpackJsonp([0,3],{
Object.defineProperty(exports, "__esModule", { Object.defineProperty(exports, "__esModule", {
value: true value: true
}); });
exports.makeActionCreator = makeActionCreator;
/**
* Created by andrew on 15/03/16.
*/
function makeActionCreator(type) {
for (var _len = arguments.length, argNames = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
argNames[_key - 1] = arguments[_key];
}
return function () {
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
var action = { type: type };
argNames.forEach(function (arg, index) {
action[argNames[index]] = args[index];
});
return action;
};
}
/* REACT HOT LOADER */ }).call(this); } finally { if (false) { (function () { var foundReactClasses = module.hot.data && module.hot.data.foundReactClasses || false; if (module.exports && module.makeHot) { var makeExportsHot = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/makeExportsHot.js"); if (makeExportsHot(module, require("react"))) { foundReactClasses = true; } var shouldAcceptModule = true && foundReactClasses; if (shouldAcceptModule) { module.hot.accept(function (err) { if (err) { console.error("Cannot not apply hot update to " + "actions.js" + ": " + err.message); } }); } } module.hot.dispose(function (data) { data.makeHot = module.makeHot; data.foundReactClasses = foundReactClasses; }); })(); } }
/***/ },
/***/ 318:
/***/ function(module, exports, __webpack_require__) {
/* REACT HOT LOADER */ if (false) { (function () { var ReactHotAPI = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/node_modules/react-hot-api/modules/index.js"), RootInstanceProvider = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/RootInstanceProvider.js"), ReactMount = require("react/lib/ReactMount"), React = require("react"); module.makeHot = module.hot.data ? module.hot.data.makeHot : ReactHotAPI(function () { return RootInstanceProvider.getRootInstances(ReactMount); }, React); })(); } try { (function () {
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.retrieveUserData = exports.persistUserData = undefined;
exports.setCurrentSettings = setCurrentSettings; exports.setCurrentSettings = setCurrentSettings;
exports.getCurrentSettings = getCurrentSettings; exports.getCurrentSettings = getCurrentSettings;
exports.setCurrentEndpoint = setCurrentEndpoint; exports.setCurrentEndpoint = setCurrentEndpoint;
@@ -2033,13 +2069,11 @@ webpackJsonp([0,3],{
exports.getTransfersUrl = getTransfersUrl; exports.getTransfersUrl = getTransfersUrl;
exports.getApiUrl = getApiUrl; exports.getApiUrl = getApiUrl;
exports.getTokenFormat = getTokenFormat; exports.getTokenFormat = getTokenFormat;
exports.persistUserData = persistUserData;
exports.retrieveUserData = retrieveUserData;
exports.retrieveHeaders = retrieveHeaders; exports.retrieveHeaders = retrieveHeaders;
exports.persistData = persistData; exports.persistData = persistData;
exports.retrieveData = retrieveData; exports.retrieveData = retrieveData;
var _jsCookie = __webpack_require__(318); var _jsCookie = __webpack_require__(319);
var _jsCookie2 = _interopRequireDefault(_jsCookie); var _jsCookie2 = _interopRequireDefault(_jsCookie);
@@ -2047,7 +2081,7 @@ webpackJsonp([0,3],{
var C = _interopRequireWildcard(_constants); var C = _interopRequireWildcard(_constants);
var _root = __webpack_require__(319); var _root = __webpack_require__(320);
var _root2 = _interopRequireDefault(_root); var _root2 = _interopRequireDefault(_root);
@@ -2055,31 +2089,39 @@ webpackJsonp([0,3],{
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
//import "babel-polyfill";
// stateful variables that persist throughout session // stateful variables that persist throughout session
_root2.default.authState = { var authState = {
currentSettings: {}, currentSettings: {},
currentEndpoint: {}, currentEndpoint: {},
defaultEndpointKey: 'default' defaultEndpointKey: 'default'
}; /** }; /**
* Created by andrew on 26/02/16. * Created by andrew on 26/02/16.
*/ */
var memoryStorage = {};
function clean(obj) {
Object.keys(obj).forEach(function (k) {
delete obj[k];
});
return obj;
}
function setCurrentSettings(s) { function setCurrentSettings(s) {
_root2.default.authState.currentSettings = s; authState.currentSettings = s;
} }
function getCurrentSettings() { function getCurrentSettings() {
return _root2.default.authState.currentSettings; return authState.currentSettings;
} }
function setCurrentEndpoint(e) { function setCurrentEndpoint(e) {
_root2.default.authState.currentEndpoint = e; authState.currentEndpoint = e;
} }
function getCurrentEndpoint() { function getCurrentEndpoint() {
return _root2.default.authState.currentEndpoint; return authState.currentEndpoint;
} }
/** /**
@@ -2108,18 +2150,15 @@ webpackJsonp([0,3],{
// reset stateful variables // reset stateful variables
function resetConfig() { function resetConfig() {
_root2.default.authState = _root2.default.authState || {}; clean(authState);
_root2.default.authState.currentSettings = {}; authState.currentSettings = {};
_root2.default.authState.currentEndpoint = {}; authState.currentEndpoint = {};
destroySession(); destroySession();
} }
function destroySession() { function destroySession() {
var sessionKeys = [C.SAVED_CREDS_KEY, C.SAVED_CONFIG_KEY, C.SAVED_USER_INFO];
for (var key in sessionKeys) {
key = sessionKeys[key];
[C.SAVED_CREDS_KEY, C.SAVED_CONFIG_KEY, C.SAVED_USER_INFO].forEach(function (key) {
// kill all local storage keys // kill all local storage keys
if (_root2.default.localStorage) { if (_root2.default.localStorage) {
_root2.default.localStorage.removeItem(key); _root2.default.localStorage.removeItem(key);
@@ -2127,9 +2166,11 @@ webpackJsonp([0,3],{
// remove from base path in case config is not specified // remove from base path in case config is not specified
_jsCookie2.default.remove(key, { _jsCookie2.default.remove(key, {
path: _root2.default.authState.currentSettings.cookiePath || "/" path: authState.currentSettings.cookiePath || "/"
}); });
} });
clean(memoryStorage);
} }
function unescapeQuotes(val) { function unescapeQuotes(val) {
@@ -2158,7 +2199,7 @@ webpackJsonp([0,3],{
//} //}
function getEmailSignInUrl() { function getEmailSignInUrl() {
return "" + getSessionEndpoint().emailSignInPath; return '' + getSessionEndpoint().emailSignInPath;
} }
function getEmailSignUpUrl() { function getEmailSignUpUrl() {
@@ -2166,19 +2207,19 @@ webpackJsonp([0,3],{
} }
function getCurrentUserUrl() { function getCurrentUserUrl() {
return "" + getSessionEndpoint().currentUserPath; return '' + getSessionEndpoint().currentUserPath;
} }
function getAccountsUrl() { function getAccountsUrl() {
return "" + getSessionEndpoint().accountsPath; return '' + getSessionEndpoint().accountsPath;
} }
function getCustomersUrl() { function getCustomersUrl() {
return "" + getSessionEndpoint().customersPath; return '' + getSessionEndpoint().customersPath;
} }
function getTransfersUrl() { function getTransfersUrl() {
return "" + getSessionEndpoint().transfersPath; return '' + getSessionEndpoint().transfersPath;
} }
/** /**
@@ -2188,20 +2229,20 @@ webpackJsonp([0,3],{
*/ */
function getApiUrl(key) { function getApiUrl(key) {
var configKey = getSessionEndpointKey(key); var configKey = getSessionEndpointKey(key);
return _root2.default.authState.currentEndpoint[configKey].apiUrl; return rauthState.currentEndpoint[configKey].apiUrl;
} }
function getTokenFormat() { function getTokenFormat() {
return _root2.default.authState.currentSettings.tokenFormat; return authState.currentSettings.tokenFormat;
} }
function persistUserData(user) { var persistUserData = exports.persistUserData = function persistUserData(user) {
persistData(C.SAVED_USER_INFO, user); memoryStorage[C.SAVED_USER_INFO] = user;
} };
function retrieveUserData() { var retrieveUserData = exports.retrieveUserData = function retrieveUserData() {
return retrieveData(C.SAVED_USER_INFO); return memoryStorage[C.SAVED_USER_INFO];
} };
function retrieveHeaders() { function retrieveHeaders() {
return retrieveData(C.SAVED_CREDS_KEY) || {}; return retrieveData(C.SAVED_CREDS_KEY) || {};
@@ -2210,15 +2251,15 @@ webpackJsonp([0,3],{
function persistData(key, val) { function persistData(key, val) {
val = _root2.default.JSON.stringify(val); val = _root2.default.JSON.stringify(val);
switch (_root2.default.authState.currentSettings.storage) { switch (authState.currentSettings.storage) {
case "localStorage": case "localStorage":
_root2.default.localStorage.setItem(key, val); _root2.default.localStorage.setItem(key, val);
break; break;
default: default:
_jsCookie2.default.set(key, val, { _jsCookie2.default.set(key, val, {
expires: _root2.default.authState.currentSettings.cookieExpiry, expires: authState.currentSettings.cookieExpiry,
path: _root2.default.authState.currentSettings.cookiePath path: authState.currentSettings.cookiePath
}); });
break; break;
} }
@@ -2227,7 +2268,7 @@ webpackJsonp([0,3],{
function retrieveData(key) { function retrieveData(key) {
var val = null; var val = null;
switch (_root2.default.authState.currentSettings.storage) { switch (authState.currentSettings.storage) {
case "localStorage": case "localStorage":
val = _root2.default.localStorage && _root2.default.localStorage.getItem(key); val = _root2.default.localStorage && _root2.default.localStorage.getItem(key);
@@ -2253,7 +2294,7 @@ webpackJsonp([0,3],{
/***/ }, /***/ },
/***/ 319: /***/ 320:
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
/* REACT HOT LOADER */ if (false) { (function () { var ReactHotAPI = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/node_modules/react-hot-api/modules/index.js"), RootInstanceProvider = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/RootInstanceProvider.js"), ReactMount = require("react/lib/ReactMount"), React = require("react"); module.makeHot = module.hot.data ? module.hot.data.makeHot : ReactHotAPI(function () { return RootInstanceProvider.getRootInstances(ReactMount); }, React); })(); } try { (function () { /* REACT HOT LOADER */ if (false) { (function () { var ReactHotAPI = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/node_modules/react-hot-api/modules/index.js"), RootInstanceProvider = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/RootInstanceProvider.js"), ReactMount = require("react/lib/ReactMount"), React = require("react"); module.makeHot = module.hot.data ? module.hot.data.makeHot : ReactHotAPI(function () { return RootInstanceProvider.getRootInstances(ReactMount); }, React); })(); } try { (function () {
@@ -2274,7 +2315,7 @@ webpackJsonp([0,3],{
/***/ }, /***/ },
/***/ 320: /***/ 321:
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
/* REACT HOT LOADER */ if (false) { (function () { var ReactHotAPI = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/node_modules/react-hot-api/modules/index.js"), RootInstanceProvider = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/RootInstanceProvider.js"), ReactMount = require("react/lib/ReactMount"), React = require("react"); module.makeHot = module.hot.data ? module.hot.data.makeHot : ReactHotAPI(function () { return RootInstanceProvider.getRootInstances(ReactMount); }, React); })(); } try { (function () { /* REACT HOT LOADER */ if (false) { (function () { var ReactHotAPI = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/node_modules/react-hot-api/modules/index.js"), RootInstanceProvider = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/RootInstanceProvider.js"), ReactMount = require("react/lib/ReactMount"), React = require("react"); module.makeHot = module.hot.data ? module.hot.data.makeHot : ReactHotAPI(function () { return RootInstanceProvider.getRootInstances(ReactMount); }, React); })(); } try { (function () {
@@ -2297,17 +2338,17 @@ webpackJsonp([0,3],{
exports.apiRetrieveUsers = apiRetrieveUsers; exports.apiRetrieveUsers = apiRetrieveUsers;
exports.apiRetrieveUser = apiRetrieveUser; exports.apiRetrieveUser = apiRetrieveUser;
var _fetch = __webpack_require__(321); var _fetch = __webpack_require__(322);
var _fetch2 = _interopRequireDefault(_fetch); var _fetch2 = _interopRequireDefault(_fetch);
var _sessionStorage = __webpack_require__(317); var _sessionStorage = __webpack_require__(318);
var _root = __webpack_require__(319); var _root = __webpack_require__(320);
var _root2 = _interopRequireDefault(_root); var _root2 = _interopRequireDefault(_root);
var _handleFetchResponse = __webpack_require__(324); var _handleFetchResponse = __webpack_require__(325);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -2419,7 +2460,7 @@ webpackJsonp([0,3],{
function apiRetrieveAccounts(customerId) { function apiRetrieveAccounts(customerId) {
return (0, _fetch2.default)((0, _sessionStorage.getAccountsUrl)() + '?' + makeQuery({ customerId: customerId }), { return (0, _fetch2.default)((0, _sessionStorage.getCustomersUrl)() + '/' + customerId + '/accounts', {
headers: { headers: {
"Accept": "application/json", "Accept": "application/json",
"Content-Type": "application/json" "Content-Type": "application/json"
@@ -2487,7 +2528,7 @@ webpackJsonp([0,3],{
/***/ }, /***/ },
/***/ 321: /***/ 322:
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
/* REACT HOT LOADER */ if (false) { (function () { var ReactHotAPI = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/node_modules/react-hot-api/modules/index.js"), RootInstanceProvider = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/RootInstanceProvider.js"), ReactMount = require("react/lib/ReactMount"), React = require("react"); module.makeHot = module.hot.data ? module.hot.data.makeHot : ReactHotAPI(function () { return RootInstanceProvider.getRootInstances(ReactMount); }, React); })(); } try { (function () { /* REACT HOT LOADER */ if (false) { (function () { var ReactHotAPI = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/node_modules/react-hot-api/modules/index.js"), RootInstanceProvider = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/RootInstanceProvider.js"), ReactMount = require("react/lib/ReactMount"), React = require("react"); module.makeHot = module.hot.data ? module.hot.data.makeHot : ReactHotAPI(function () { return RootInstanceProvider.getRootInstances(ReactMount); }, React); })(); } try { (function () {
@@ -2519,7 +2560,7 @@ webpackJsonp([0,3],{
}); });
}; };
var _isomorphicFetch = __webpack_require__(322); var _isomorphicFetch = __webpack_require__(323);
var _isomorphicFetch2 = _interopRequireDefault(_isomorphicFetch); var _isomorphicFetch2 = _interopRequireDefault(_isomorphicFetch);
@@ -2527,7 +2568,7 @@ webpackJsonp([0,3],{
var C = _interopRequireWildcard(_constants); var C = _interopRequireWildcard(_constants);
var _sessionStorage = __webpack_require__(317); var _sessionStorage = __webpack_require__(318);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
@@ -2591,7 +2632,7 @@ webpackJsonp([0,3],{
/***/ }, /***/ },
/***/ 324: /***/ 325:
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
/* REACT HOT LOADER */ if (false) { (function () { var ReactHotAPI = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/node_modules/react-hot-api/modules/index.js"), RootInstanceProvider = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/RootInstanceProvider.js"), ReactMount = require("react/lib/ReactMount"), React = require("react"); module.makeHot = module.hot.data ? module.hot.data.makeHot : ReactHotAPI(function () { return RootInstanceProvider.getRootInstances(ReactMount); }, React); })(); } try { (function () { /* REACT HOT LOADER */ if (false) { (function () { var ReactHotAPI = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/node_modules/react-hot-api/modules/index.js"), RootInstanceProvider = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/RootInstanceProvider.js"), ReactMount = require("react/lib/ReactMount"), React = require("react"); module.makeHot = module.hot.data ? module.hot.data.makeHot : ReactHotAPI(function () { return RootInstanceProvider.getRootInstances(ReactMount); }, React); })(); } try { (function () {
@@ -2649,7 +2690,7 @@ webpackJsonp([0,3],{
/***/ }, /***/ },
/***/ 325: /***/ 326:
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
/* REACT HOT LOADER */ if (false) { (function () { var ReactHotAPI = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/node_modules/react-hot-api/modules/index.js"), RootInstanceProvider = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/RootInstanceProvider.js"), ReactMount = require("react/lib/ReactMount"), React = require("react"); module.makeHot = module.hot.data ? module.hot.data.makeHot : ReactHotAPI(function () { return RootInstanceProvider.getRootInstances(ReactMount); }, React); })(); } try { (function () { /* REACT HOT LOADER */ if (false) { (function () { var ReactHotAPI = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/node_modules/react-hot-api/modules/index.js"), RootInstanceProvider = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/RootInstanceProvider.js"), ReactMount = require("react/lib/ReactMount"), React = require("react"); module.makeHot = module.hot.data ? module.hot.data.makeHot : ReactHotAPI(function () { return RootInstanceProvider.getRootInstances(ReactMount); }, React); })(); } try { (function () {
@@ -2678,15 +2719,15 @@ webpackJsonp([0,3],{
var _ACTION_TYPES2 = _interopRequireDefault(_ACTION_TYPES); var _ACTION_TYPES2 = _interopRequireDefault(_ACTION_TYPES);
var _actions = __webpack_require__(326); var _actions = __webpack_require__(317);
var _api = __webpack_require__(320); var _api = __webpack_require__(321);
var api = _interopRequireWildcard(_api); var api = _interopRequireWildcard(_api);
var _authenticate = __webpack_require__(316); var _authenticate = __webpack_require__(316);
var _root = __webpack_require__(319); var _root = __webpack_require__(320);
var _root2 = _interopRequireDefault(_root); var _root2 = _interopRequireDefault(_root);
@@ -2799,7 +2840,7 @@ webpackJsonp([0,3],{
return function (dispatch) { return function (dispatch) {
//dispatch(accountsListRequested()); //dispatch(accountsListRequested());
return api.apiRetrieveAccounts(customerId).then(function (data) { return api.apiRetrieveAccounts(customerId).then(function (data) {
dispatch(accountsListReceived(data)); dispatch(accountsListReceived(data.accounts));
}); });
}; };
} }
@@ -2933,7 +2974,7 @@ webpackJsonp([0,3],{
return function (dispatch) { return function (dispatch) {
dispatch(getTransfersRequested(accountId)); dispatch(getTransfersRequested(accountId));
return api.apiRetrieveTransfers(accountId).then(function (data) { return api.apiRetrieveTransfers(accountId).then(function (data) {
dispatch(getTransfersComplete(accountId, data)); dispatch(getTransfersComplete(accountId, data.transactionsHistory));
return data; return data;
}).catch(function (err) { }).catch(function (err) {
dispatch(getTransfersError(accountId, err)); dispatch(getTransfersError(accountId, err));
@@ -2946,42 +2987,6 @@ webpackJsonp([0,3],{
/***/ }, /***/ },
/***/ 326:
/***/ function(module, exports, __webpack_require__) {
/* REACT HOT LOADER */ if (false) { (function () { var ReactHotAPI = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/node_modules/react-hot-api/modules/index.js"), RootInstanceProvider = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/RootInstanceProvider.js"), ReactMount = require("react/lib/ReactMount"), React = require("react"); module.makeHot = module.hot.data ? module.hot.data.makeHot : ReactHotAPI(function () { return RootInstanceProvider.getRootInstances(ReactMount); }, React); })(); } try { (function () {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.makeActionCreator = makeActionCreator;
/**
* Created by andrew on 15/03/16.
*/
function makeActionCreator(type) {
for (var _len = arguments.length, argNames = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
argNames[_key - 1] = arguments[_key];
}
return function () {
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
var action = { type: type };
argNames.forEach(function (arg, index) {
action[argNames[index]] = args[index];
});
return action;
};
}
/* REACT HOT LOADER */ }).call(this); } finally { if (false) { (function () { var foundReactClasses = module.hot.data && module.hot.data.foundReactClasses || false; if (module.exports && module.makeHot) { var makeExportsHot = require("/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/react-hot-loader/makeExportsHot.js"); if (makeExportsHot(module, require("react"))) { foundReactClasses = true; } var shouldAcceptModule = true && foundReactClasses; if (shouldAcceptModule) { module.hot.accept(function (err) { if (err) { console.error("Cannot not apply hot update to " + "actions.js" + ": " + err.message); } }); } } module.hot.dispose(function (data) { data.makeHot = module.makeHot; data.foundReactClasses = foundReactClasses; }); })(); } }
/***/ },
/***/ 327: /***/ 327:
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
@@ -3003,11 +3008,11 @@ webpackJsonp([0,3],{
var C = _interopRequireWildcard(_constants); var C = _interopRequireWildcard(_constants);
var _root = __webpack_require__(319); var _root = __webpack_require__(320);
var _root2 = _interopRequireDefault(_root); var _root2 = _interopRequireDefault(_root);
var _fetch = __webpack_require__(321); var _fetch = __webpack_require__(322);
var _fetch2 = _interopRequireDefault(_fetch); var _fetch2 = _interopRequireDefault(_fetch);
@@ -3017,7 +3022,7 @@ webpackJsonp([0,3],{
var _configure = __webpack_require__(314); var _configure = __webpack_require__(314);
var _sessionStorage = __webpack_require__(317); var _sessionStorage = __webpack_require__(318);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -3836,15 +3841,15 @@ webpackJsonp([0,3],{
exports.signOutComplete = signOutComplete; exports.signOutComplete = signOutComplete;
exports.signOut = signOut; exports.signOut = signOut;
var _sessionStorage = __webpack_require__(317); var _sessionStorage = __webpack_require__(318);
var _entities = __webpack_require__(325); var _entities = __webpack_require__(326);
var _configure = __webpack_require__(314); var _configure = __webpack_require__(314);
var _handleFetchResponse = __webpack_require__(324); var _handleFetchResponse = __webpack_require__(325);
var _fetch = __webpack_require__(321); var _fetch = __webpack_require__(322);
var _fetch2 = _interopRequireDefault(_fetch); var _fetch2 = _interopRequireDefault(_fetch);
@@ -3852,7 +3857,7 @@ webpackJsonp([0,3],{
var _ACTION_TYPES2 = _interopRequireDefault(_ACTION_TYPES); var _ACTION_TYPES2 = _interopRequireDefault(_ACTION_TYPES);
var _root = __webpack_require__(319); var _root = __webpack_require__(320);
var _root2 = _interopRequireDefault(_root); var _root2 = _interopRequireDefault(_root);
@@ -3923,7 +3928,7 @@ webpackJsonp([0,3],{
var _IndexPanel2 = _interopRequireDefault(_IndexPanel); var _IndexPanel2 = _interopRequireDefault(_IndexPanel);
var _entities = __webpack_require__(325); var _entities = __webpack_require__(326);
var A = _interopRequireWildcard(_entities); var A = _interopRequireWildcard(_entities);
@@ -4476,7 +4481,7 @@ webpackJsonp([0,3],{
var _reactSelect2 = _interopRequireDefault(_reactSelect); var _reactSelect2 = _interopRequireDefault(_reactSelect);
var _entities = __webpack_require__(325); var _entities = __webpack_require__(326);
var A = _interopRequireWildcard(_entities); var A = _interopRequireWildcard(_entities);
@@ -5101,7 +5106,7 @@ webpackJsonp([0,3],{
var _readProp2 = _interopRequireDefault(_readProp); var _readProp2 = _interopRequireDefault(_readProp);
var _entities = __webpack_require__(325); var _entities = __webpack_require__(326);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
@@ -5619,7 +5624,7 @@ webpackJsonp([0,3],{
var Modals = _interopRequireWildcard(_modals); var Modals = _interopRequireWildcard(_modals);
var _entities = __webpack_require__(325); var _entities = __webpack_require__(326);
var A = _interopRequireWildcard(_entities); var A = _interopRequireWildcard(_entities);
@@ -6158,32 +6163,83 @@ webpackJsonp([0,3],{
} }
var currentAccountId = forAccount; var currentAccountId = forAccount;
var transfersMarkup = data.length ? data.filter(function (_ref2) { var transfersMarkup = data.length ? data.sort(function (a, b) {
return a.date - b.date;
}).filter(function (_ref2) {
var entryType = _ref2.entryType;
var toAccountId = _ref2.toAccountId; var toAccountId = _ref2.toAccountId;
var fromAccountId = _ref2.fromAccountId; var fromAccountId = _ref2.fromAccountId;
return fromAccountId === currentAccountId || toAccountId === currentAccountId; return entryType !== 'transaction' || fromAccountId === currentAccountId || toAccountId === currentAccountId;
}).sort(function (a, b) { }).reduce(function (_ref3, v) {
return -(a.date - b.date); var items = _ref3.items;
}).map(function (_ref3) { var balance = _ref3.balance;
var amount = _ref3.amount;
var fromAccountId = _ref3.fromAccountId;
var toAccountId = _ref3.toAccountId;
var transactionId = _ref3.transactionId;
var _ref3$description = _ref3.description;
var description = _ref3$description === undefined ? '' : _ref3$description;
var _ref3$date = _ref3.date;
var date = _ref3$date === undefined ? null : _ref3$date;
var _ref3$status = _ref3.status;
var status = _ref3$status === undefined ? '' : _ref3$status;
if (v.entryType == 'account') {
balance = v.initialBalance;
} else if (v.entryType == 'transaction') {
var isOriginating = v.fromAccountId == currentAccountId;
balance += (isOriginating ? -1 : 1) * v.amount;
}
v.balance = balance;
items.push(v);
return { items: items, balance: balance };
}, {
items: [],
balance: 0
}).items.sort(function (a, b) {
return -(a.date - b.date);
}).map(function (_ref4) {
var entryType = _ref4.entryType;
var amount = _ref4.amount;
var fromAccountId = _ref4.fromAccountId;
var toAccountId = _ref4.toAccountId;
var transactionId = _ref4.transactionId;
var _ref4$description = _ref4.description;
var description = _ref4$description === undefined ? '—' : _ref4$description;
var _ref4$date = _ref4.date;
var date = _ref4$date === undefined ? null : _ref4$date;
var _ref4$status = _ref4.status;
var status = _ref4$status === undefined ? '—' : _ref4$status;
var balance = _ref4.balance;
var _ref4$initialBalance = _ref4.initialBalance;
var initialBalance = _ref4$initialBalance === undefined ? null : _ref4$initialBalance;
var transferTimestamp = new Date(date);
var timeAgoTitle = transferTimestamp.toLocaleDateString() + ' ' + transferTimestamp.toLocaleTimeString();
if (entryType == 'account') {
return _react2.default.createElement(
"tr",
null,
_react2.default.createElement(
"td",
null,
_react2.default.createElement(_reactTimeago2.default, { date: date, title: timeAgoTitle })
),
_react2.default.createElement(
"td",
{ colSpan: "3" },
"Account created"
),
_react2.default.createElement(
"td",
null,
_react2.default.createElement(_Money.Money, { amount: initialBalance })
),
_react2.default.createElement("td", null),
_react2.default.createElement(
"td",
null,
status || '—'
)
);
}
var isOriginating = fromAccountId == currentAccountId; var isOriginating = fromAccountId == currentAccountId;
var directionMarkup = isOriginating ? 'Debit' : 'Credit'; var directionMarkup = isOriginating ? 'Debit' : 'Credit';
var counterAccountMarkup = isOriginating ? _react2.default.createElement(_AccountInfo2.default, { accountId: toAccountId }) : _react2.default.createElement(_AccountInfo2.default, { accountId: fromAccountId }); var counterAccountMarkup = isOriginating ? _react2.default.createElement(_AccountInfo2.default, { accountId: toAccountId }) : _react2.default.createElement(_AccountInfo2.default, { accountId: fromAccountId });
var transferTimestamp = new Date(date);
var timeAgoTitle = transferTimestamp.toLocaleDateString() + ' ' + transferTimestamp.toLocaleTimeString();
return _react2.default.createElement( return _react2.default.createElement(
"tr", "tr",
null, null,
@@ -6207,6 +6263,11 @@ webpackJsonp([0,3],{
null, null,
_react2.default.createElement(_Money.Money, { amount: amount }) _react2.default.createElement(_Money.Money, { amount: amount })
), ),
_react2.default.createElement(
"td",
null,
_react2.default.createElement(_Money.Money, { amount: balance })
),
_react2.default.createElement( _react2.default.createElement(
"td", "td",
null, null,
@@ -6257,6 +6318,11 @@ webpackJsonp([0,3],{
null, null,
"Amount" "Amount"
), ),
_react2.default.createElement(
"th",
null,
"Balance"
),
_react2.default.createElement( _react2.default.createElement(
"th", "th",
null, null,
@@ -6309,7 +6375,7 @@ webpackJsonp([0,3],{
var _reactLoader2 = _interopRequireDefault(_reactLoader); var _reactLoader2 = _interopRequireDefault(_reactLoader);
var _entities = __webpack_require__(325); var _entities = __webpack_require__(326);
var A = _interopRequireWildcard(_entities); var A = _interopRequireWildcard(_entities);
@@ -6763,15 +6829,15 @@ webpackJsonp([0,3],{
exports.emailSignInError = exports.emailSignInComplete = exports.emailSignInStart = exports.emailSignInFormUpdate = undefined; exports.emailSignInError = exports.emailSignInComplete = exports.emailSignInStart = exports.emailSignInFormUpdate = undefined;
exports.emailSignIn = emailSignIn; exports.emailSignIn = emailSignIn;
var _sessionStorage = __webpack_require__(317); var _sessionStorage = __webpack_require__(318);
var _entities = __webpack_require__(325); var _entities = __webpack_require__(326);
var _configure = __webpack_require__(314); var _configure = __webpack_require__(314);
var _api = __webpack_require__(320); var _api = __webpack_require__(321);
var _actions = __webpack_require__(326); var _actions = __webpack_require__(317);
var _ACTION_TYPES = __webpack_require__(295); var _ACTION_TYPES = __webpack_require__(295);
@@ -7227,13 +7293,13 @@ webpackJsonp([0,3],{
exports.emailSignUpError = emailSignUpError; exports.emailSignUpError = emailSignUpError;
exports.emailSignUp = emailSignUp; exports.emailSignUp = emailSignUp;
var _sessionStorage = __webpack_require__(317); var _sessionStorage = __webpack_require__(318);
var _entities = __webpack_require__(325); var _entities = __webpack_require__(326);
var _configure = __webpack_require__(314); var _configure = __webpack_require__(314);
var _api = __webpack_require__(320); var _api = __webpack_require__(321);
var _signIn = __webpack_require__(609); var _signIn = __webpack_require__(609);
@@ -7287,4 +7353,4 @@ webpackJsonp([0,3],{
/***/ } /***/ }
}); });
//# sourceMappingURL=app.3a9a7c962cfa5ee06c64.js.map //# sourceMappingURL=app.d4bdff82ac1db214898b.js.map

File diff suppressed because one or more lines are too long

View File

@@ -13,7 +13,7 @@
<!-- Optional theme --> <!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap-theme.min.css"><link href="/style.6d7a32b1405ea1bb2bdf.css" rel="stylesheet"></head> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap-theme.min.css"><link href="/style.6d7a32b1405ea1bb2bdf.css" rel="stylesheet"></head>
<body><div id="root"></div><script src="/manifest.3614fb531d249ed18cb9.js"></script><script src="/vendor.9bf2d755cba11113a020.js"></script><script src="/style.6d7a32b1405ea1bb2bdf.js"></script><script src="/app.3a9a7c962cfa5ee06c64.js"></script><script> <body><div id="root"></div><script src="/manifest.09cb8f5a05c9cfc35585.js"></script><script src="/vendor.f73c0104cb72cfb2809e.js"></script><script src="/style.6d7a32b1405ea1bb2bdf.js"></script><script src="/app.d4bdff82ac1db214898b.js"></script><script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
@@ -27,5 +27,5 @@
ga('send', 'pageview'); ga('send', 'pageview');
</script><!--{"files":{"publicPath":"/","chunks":{"manifest":{"size":0,"entry":"/manifest.3614fb531d249ed18cb9.js","hash":"3614fb531d249ed18cb9","css":[]},"vendor":{"size":1670874,"entry":"/vendor.9bf2d755cba11113a020.js","hash":"9bf2d755cba11113a020","css":[]},"style":{"size":122,"entry":"/style.6d7a32b1405ea1bb2bdf.js","hash":"6d7a32b1405ea1bb2bdf","css":["/style.6d7a32b1405ea1bb2bdf.css"]},"app":{"size":348671,"entry":"/app.3a9a7c962cfa5ee06c64.js","hash":"3a9a7c962cfa5ee06c64","css":[]}},"js":["/manifest.3614fb531d249ed18cb9.js","/vendor.9bf2d755cba11113a020.js","/style.6d7a32b1405ea1bb2bdf.js","/app.3a9a7c962cfa5ee06c64.js"],"css":["/style.6d7a32b1405ea1bb2bdf.css"]},"options":{"template":"/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/html-webpack-plugin/lib/loader.js!/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/public/index.ejs","filename":"index.html","hash":false,"inject":false,"compile":true,"favicon":false,"minify":false,"cache":true,"showErrors":true,"chunks":"all","excludeChunks":[],"title":"Money Transfer App","xhtml":false,"description":"ES Money Transfer App","appMountId":"root","googleAnalytics":{"trackingId":"UA-XXXX-XX","pageViewOnLoad":true},"mobile":true}}--></body> </script><!--{"files":{"publicPath":"/","chunks":{"manifest":{"size":0,"entry":"/manifest.09cb8f5a05c9cfc35585.js","hash":"09cb8f5a05c9cfc35585","css":[]},"vendor":{"size":1670874,"entry":"/vendor.f73c0104cb72cfb2809e.js","hash":"f73c0104cb72cfb2809e","css":[]},"style":{"size":122,"entry":"/style.6d7a32b1405ea1bb2bdf.js","hash":"6d7a32b1405ea1bb2bdf","css":["/style.6d7a32b1405ea1bb2bdf.css"]},"app":{"size":351315,"entry":"/app.d4bdff82ac1db214898b.js","hash":"d4bdff82ac1db214898b","css":[]}},"js":["/manifest.09cb8f5a05c9cfc35585.js","/vendor.f73c0104cb72cfb2809e.js","/style.6d7a32b1405ea1bb2bdf.js","/app.d4bdff82ac1db214898b.js"],"css":["/style.6d7a32b1405ea1bb2bdf.css"]},"options":{"template":"/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/html-webpack-plugin/lib/loader.js!/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/public/index.ejs","filename":"index.html","hash":false,"inject":false,"compile":true,"favicon":false,"minify":false,"cache":true,"showErrors":true,"chunks":"all","excludeChunks":[],"title":"Money Transfer App","xhtml":false,"description":"ES Money Transfer App","appMountId":"root","googleAnalytics":{"trackingId":"UA-XXXX-XX","pageViewOnLoad":true},"mobile":true}}--></body>
</html> </html>

View File

@@ -76,7 +76,7 @@
/******/ script.charset = 'utf-8'; /******/ script.charset = 'utf-8';
/******/ script.async = true; /******/ script.async = true;
/******/ /******/
/******/ script.src = __webpack_require__.p + "" + {"0":"3a9a7c962cfa5ee06c64","1":"6d7a32b1405ea1bb2bdf","2":"9bf2d755cba11113a020"}[chunkId] + ".js"; /******/ script.src = __webpack_require__.p + "" + {"0":"d4bdff82ac1db214898b","1":"6d7a32b1405ea1bb2bdf","2":"f73c0104cb72cfb2809e"}[chunkId] + ".js";
/******/ head.appendChild(script); /******/ head.appendChild(script);
/******/ } /******/ }
/******/ }; /******/ };
@@ -92,4 +92,4 @@
/******/ }) /******/ })
/************************************************************************/ /************************************************************************/
/******/ ([]); /******/ ([]);
//# sourceMappingURL=manifest.3614fb531d249ed18cb9.js.map //# sourceMappingURL=manifest.09cb8f5a05c9cfc35585.js.map

View File

@@ -1 +1 @@
{"version":3,"sources":["webpack:///webpack/bootstrap c67ebd10dee52fe43758?"],"names":[],"mappings":";AAAA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAQ,oBAAoB;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,uBAAe;AACf;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,YAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,uDAA+C,iFAAiF;AAChI;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA","file":"manifest.3614fb531d249ed18cb9.js","sourcesContent":[" \t// install a JSONP callback for chunk loading\n \tvar parentJsonpFunction = window[\"webpackJsonp\"];\n \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules) {\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, callbacks = [];\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(installedChunks[chunkId])\n \t\t\t\tcallbacks.push.apply(callbacks, installedChunks[chunkId]);\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tmodules[moduleId] = moreModules[moduleId];\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules);\n \t\twhile(callbacks.length)\n \t\t\tcallbacks.shift().call(null, __webpack_require__);\n \t\tif(moreModules[0]) {\n \t\t\tinstalledModules[0] = 0;\n \t\t\treturn __webpack_require__(0);\n \t\t}\n \t};\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// object to store loaded and loading chunks\n \t// \"0\" means \"already loaded\"\n \t// Array means \"loading\", array contains callbacks\n \tvar installedChunks = {\n \t\t3:0\n \t};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n \t// This file contains only the entry chunk.\n \t// The chunk loading function for additional chunks\n \t__webpack_require__.e = function requireEnsure(chunkId, callback) {\n \t\t// \"0\" is the signal for \"already loaded\"\n \t\tif(installedChunks[chunkId] === 0)\n \t\t\treturn callback.call(null, __webpack_require__);\n\n \t\t// an array means \"currently loading\".\n \t\tif(installedChunks[chunkId] !== undefined) {\n \t\t\tinstalledChunks[chunkId].push(callback);\n \t\t} else {\n \t\t\t// start chunk loading\n \t\t\tinstalledChunks[chunkId] = [callback];\n \t\t\tvar head = document.getElementsByTagName('head')[0];\n \t\t\tvar script = document.createElement('script');\n \t\t\tscript.type = 'text/javascript';\n \t\t\tscript.charset = 'utf-8';\n \t\t\tscript.async = true;\n\n \t\t\tscript.src = __webpack_require__.p + \"\" + {\"0\":\"3a9a7c962cfa5ee06c64\",\"1\":\"6d7a32b1405ea1bb2bdf\",\"2\":\"9bf2d755cba11113a020\"}[chunkId] + \".js\";\n \t\t\thead.appendChild(script);\n \t\t}\n \t};\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/\";\n\n\n\n/** WEBPACK FOOTER **\n ** webpack/bootstrap c67ebd10dee52fe43758\n **/"],"sourceRoot":""} {"version":3,"sources":["webpack:///webpack/bootstrap 8ac05bd1ead33e72514a?"],"names":[],"mappings":";AAAA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAQ,oBAAoB;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,uBAAe;AACf;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,YAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,uDAA+C,iFAAiF;AAChI;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA","file":"manifest.09cb8f5a05c9cfc35585.js","sourcesContent":[" \t// install a JSONP callback for chunk loading\n \tvar parentJsonpFunction = window[\"webpackJsonp\"];\n \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules) {\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, callbacks = [];\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(installedChunks[chunkId])\n \t\t\t\tcallbacks.push.apply(callbacks, installedChunks[chunkId]);\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tmodules[moduleId] = moreModules[moduleId];\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules);\n \t\twhile(callbacks.length)\n \t\t\tcallbacks.shift().call(null, __webpack_require__);\n \t\tif(moreModules[0]) {\n \t\t\tinstalledModules[0] = 0;\n \t\t\treturn __webpack_require__(0);\n \t\t}\n \t};\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// object to store loaded and loading chunks\n \t// \"0\" means \"already loaded\"\n \t// Array means \"loading\", array contains callbacks\n \tvar installedChunks = {\n \t\t3:0\n \t};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n \t// This file contains only the entry chunk.\n \t// The chunk loading function for additional chunks\n \t__webpack_require__.e = function requireEnsure(chunkId, callback) {\n \t\t// \"0\" is the signal for \"already loaded\"\n \t\tif(installedChunks[chunkId] === 0)\n \t\t\treturn callback.call(null, __webpack_require__);\n\n \t\t// an array means \"currently loading\".\n \t\tif(installedChunks[chunkId] !== undefined) {\n \t\t\tinstalledChunks[chunkId].push(callback);\n \t\t} else {\n \t\t\t// start chunk loading\n \t\t\tinstalledChunks[chunkId] = [callback];\n \t\t\tvar head = document.getElementsByTagName('head')[0];\n \t\t\tvar script = document.createElement('script');\n \t\t\tscript.type = 'text/javascript';\n \t\t\tscript.charset = 'utf-8';\n \t\t\tscript.async = true;\n\n \t\t\tscript.src = __webpack_require__.p + \"\" + {\"0\":\"d4bdff82ac1db214898b\",\"1\":\"6d7a32b1405ea1bb2bdf\",\"2\":\"f73c0104cb72cfb2809e\"}[chunkId] + \".js\";\n \t\t\thead.appendChild(script);\n \t\t}\n \t};\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/\";\n\n\n\n/** WEBPACK FOOTER **\n ** webpack/bootstrap 8ac05bd1ead33e72514a\n **/"],"sourceRoot":""}

View File

@@ -6,8 +6,8 @@ webpackJsonp([2,3],[
__webpack_require__(262); __webpack_require__(262);
__webpack_require__(621); __webpack_require__(621);
__webpack_require__(180); __webpack_require__(180);
__webpack_require__(322); __webpack_require__(323);
__webpack_require__(318); __webpack_require__(319);
__webpack_require__(622); __webpack_require__(622);
__webpack_require__(330); __webpack_require__(330);
__webpack_require__(2); __webpack_require__(2);
@@ -30146,7 +30146,8 @@ webpackJsonp([2,3],[
/* 315 */, /* 315 */,
/* 316 */, /* 316 */,
/* 317 */, /* 317 */,
/* 318 */ /* 318 */,
/* 319 */
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
@@ -30297,22 +30298,22 @@ webpackJsonp([2,3],[
/***/ }, /***/ },
/* 319 */,
/* 320 */, /* 320 */,
/* 321 */, /* 321 */,
/* 322 */ /* 322 */,
/* 323 */
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
// the whatwg-fetch polyfill installs the fetch() function // the whatwg-fetch polyfill installs the fetch() function
// on the global object (window or self) // on the global object (window or self)
// //
// Return that as the export for use in Webpack, Browserify etc. // Return that as the export for use in Webpack, Browserify etc.
__webpack_require__(323); __webpack_require__(324);
module.exports = self.fetch.bind(self); module.exports = self.fetch.bind(self);
/***/ }, /***/ },
/* 323 */ /* 324 */
/***/ function(module, exports) { /***/ function(module, exports) {
(function(self) { (function(self) {
@@ -30707,7 +30708,6 @@ webpackJsonp([2,3],[
/***/ }, /***/ },
/* 324 */,
/* 325 */, /* 325 */,
/* 326 */, /* 326 */,
/* 327 */, /* 327 */,
@@ -55902,4 +55902,4 @@ webpackJsonp([2,3],[
/***/ } /***/ }
]); ]);
//# sourceMappingURL=vendor.9bf2d755cba11113a020.js.map //# sourceMappingURL=vendor.f73c0104cb72cfb2809e.js.map

View File

@@ -21,21 +21,24 @@ exports.devServer = function(options) {
host: options.host, // Defaults to `localhost` host: options.host, // Defaults to `localhost`
port: options.port, // Defaults to 8080 port: options.port, // Defaults to 8080
proxy: { proxy: {
'/user*' : { '/api*' : {
target: 'http://localhost:8080'
},
'/login' : {
target: 'http://localhost:8080'
},
'/customers*' : {
target: 'http://localhost:8080'
},
'/accounts*' : {
target: 'http://localhost:8080'
},
'/transfers*' : {
target: 'http://localhost:8080' target: 'http://localhost:8080'
} }
// '/user*' : {
// target: 'http://localhost:8080'
// },
// '/login' : {
// target: 'http://localhost:8080'
// },
// '/customers*' : {
// target: 'http://localhost:8080'
// },
// '/accounts*' : {
// target: 'http://localhost:8080'
// },
// '/transfers*' : {
// target: 'http://localhost:8080'
// }
} }
}, },
watchOptions: { watchOptions: {

View File

@@ -15,7 +15,7 @@ import { reduxReactRouter as serverRouter } from "redux-router/server";
import mainReducer from './reducers'; import mainReducer from './reducers';
import { configure as reduxAuthConfigure } from './actions/configure'; import { configure as endpointsConfig } from './actions/configure';
import { requireAuthentication } from './components/AuthComponent'; import { requireAuthentication } from './components/AuthComponent';
import Container from "./components/partials/Container"; import Container from "./components/partials/Container";
import MyAccounts from "./views/MyAccounts"; import MyAccounts from "./views/MyAccounts";
@@ -64,15 +64,15 @@ export function initialize({cookies, isServer, currentLocation, userAgent} = {})
/** /**
* The React Router 1.0 routes for both the server and the client. * The React Router 1.0 routes for both the server and the client.
*/ */
return store.dispatch(reduxAuthConfigure([ return store.dispatch(endpointsConfig([
{ {
default: { default: {
//apiUrl: '/', //apiUrl: '/',
emailSignInPath: '/login', emailSignInPath: '/api/login',
customersPath: '/customers', customersPath: '/api/customers',
currentUserPath: '/user', currentUserPath: '/api/user',
accountsPath: '/accounts', accountsPath: '/api/accounts',
transfersPath: '/transfers' transfersPath: '/api/transfers'
} }
} }
], { ], {

View File

@@ -2,65 +2,41 @@
* Created by andrew on 26/02/16. * Created by andrew on 26/02/16.
*/ */
import T from '../constants/ACTION_TYPES'; import T from '../constants/ACTION_TYPES';
import { makeActionCreator } from '../utils/actions';
import * as U from '../utils/sessionStorage';
import { import { apiGetCurrentUser } from '../utils/api';
getCurrentSettings, import { entityReceived } from './entities';
setCurrentSettings,
getInitialEndpointKey,
setDefaultEndpointKey,
setCurrentEndpoint,
setCurrentEndpointKey,
retrieveData,
persistData,
destroySession,
persistUserData,
retrieveUserData,
retrieveHeaders
} from "../utils/sessionStorage";
import {
apiGetCurrentUser
} from '../utils/api';
import {entityReceived } from './entities';
export function authenticateStart() {
return { type: T.AUTH.AUTHENTICATE_START };
}
export function authenticateComplete(user) {
return { type: T.AUTH.AUTHENTICATE_COMPLETE, user };
}
export function authenticateError(errors) {
return { type: T.AUTH.AUTHENTICATE_ERROR, errors };
}
export const authenticateStart = makeActionCreator(T.AUTH.AUTHENTICATE_START);
export const authenticateComplete = makeActionCreator(T.AUTH.AUTHENTICATE_COMPLETE, 'user');
export const authenticateError = makeActionCreator(T.AUTH.AUTHENTICATE_ERROR, 'errors');
export function authenticate(forceReread) { export function authenticate(forceReread) {
return dispatch => { return (dispatch) => {
dispatch(authenticateStart()); dispatch(authenticateStart());
const savedUserPromise = new Promise((rs, rj) => { const savedUserPromise = new Promise((rs, rj) => {
const currentHeaders = retrieveHeaders(); const currentHeaders = U.retrieveHeaders();
const accessToken = currentHeaders["access-token"]; const accessToken = currentHeaders["access-token"];
if (!accessToken) { if (!accessToken) {
return rj({ reason: 'no token'}); return rj({ reason: 'no token'});
} }
const savedUser = retrieveUserData(); const savedUser = U.retrieveUserData();
if (savedUser && !forceReread) { if (savedUser && !forceReread) {
return rs(savedUser); return rs(savedUser);
} }
return apiGetCurrentUser().then((userData) => { return apiGetCurrentUser().then((userData) => {
persistUserData(userData); U.persistUserData(userData);
dispatch(entityReceived(userData.id, userData)); dispatch(entityReceived(userData.id, userData));
rs(userData); rs(userData);
}, (err) => { }, (err) => {
debugger;
rj(err); rj(err);
}); });

View File

@@ -123,7 +123,7 @@ export function fetchOwnAccounts(customerId) {
//dispatch(accountsListRequested()); //dispatch(accountsListRequested());
return api.apiRetrieveAccounts(customerId) return api.apiRetrieveAccounts(customerId)
.then(data => { .then(data => {
dispatch(accountsListReceived(data)); dispatch(accountsListReceived(data.accounts));
}); });
}; };
} }
@@ -256,7 +256,7 @@ export const getTransfers = (accountId) => {
dispatch(getTransfersRequested(accountId)); dispatch(getTransfersRequested(accountId));
return api.apiRetrieveTransfers(accountId) return api.apiRetrieveTransfers(accountId)
.then(data => { .then(data => {
dispatch(getTransfersComplete(accountId, data)); dispatch(getTransfersComplete(accountId, data.transactionsHistory));
return data; return data;
}) })
.catch(err => { .catch(err => {

View File

@@ -25,36 +25,67 @@ export class TransfersTable extends React.Component {
const currentAccountId = forAccount; const currentAccountId = forAccount;
const transfersMarkup = data.length ? const transfersMarkup = data.length ?
data data
.filter(({ toAccountId, fromAccountId}) => ((fromAccountId === currentAccountId) || (toAccountId === currentAccountId))) .sort((a, b) => ((a.date - b.date)))
.filter(({ entryType, toAccountId, fromAccountId}) => ((entryType !=='transaction') || (fromAccountId === currentAccountId) || (toAccountId === currentAccountId)))
.reduce(({
items, balance
}, v) => {
if (v.entryType == 'account') {
balance = v.initialBalance;
} else if (v.entryType == 'transaction') {
const isOriginating = v.fromAccountId == currentAccountId;
balance += (isOriginating ? -1 : 1) * v.amount;
}
v.balance = balance;
items.push(v);
return { items, balance };
}, {
items: [],
balance: 0
}).items
.sort((a, b) => (-(a.date - b.date))) .sort((a, b) => (-(a.date - b.date)))
.map(({ .map(({
amount, entryType,
fromAccountId, amount,
toAccountId, fromAccountId,
transactionId, toAccountId,
description = '', transactionId,
date = null, description = '—',
status = '' date = null,
}) => { status = '—',
balance,
initialBalance = null
}) => {
const isOriginating = fromAccountId == currentAccountId; const transferTimestamp = new Date(date);
const directionMarkup = isOriginating ? 'Debit' : 'Credit'; const timeAgoTitle = transferTimestamp.toLocaleDateString() + ' ' + transferTimestamp.toLocaleTimeString();
const counterAccountMarkup = isOriginating ?
<AccountInfo accountId={ toAccountId } /> :
<AccountInfo accountId={ fromAccountId } />;
const transferTimestamp = new Date(date); if (entryType == 'account') {
const timeAgoTitle = transferTimestamp.toLocaleDateString() + ' ' + transferTimestamp.toLocaleTimeString(); return (<tr>
<td><TimeAgo date={date} title={ timeAgoTitle } /></td>
<td colSpan="3">Account created</td>
<td><Money amount={ initialBalance } /></td>
<td></td>
<td>{ status || '—' }</td>
</tr>);
}
return (<tr> const isOriginating = fromAccountId == currentAccountId;
<td><TimeAgo date={date} title={ timeAgoTitle } /></td> const directionMarkup = isOriginating ? 'Debit' : 'Credit';
<td>{ directionMarkup }</td> const counterAccountMarkup = isOriginating ?
<td>{ counterAccountMarkup }</td> <AccountInfo accountId={ toAccountId } /> :
<td><Money amount={ amount } /></td> <AccountInfo accountId={ fromAccountId } />;
<td>{ description || '—' }</td>
<td>{ status || '—' }</td> return (<tr>
</tr>); <td><TimeAgo date={date} title={ timeAgoTitle } /></td>
}) : (<tr> <td>{ directionMarkup }</td>
<td>{ counterAccountMarkup }</td>
<td><Money amount={ amount } /></td>
<td><Money amount={ balance } /></td>
<td>{ description || '—' }</td>
<td>{ status || '—' }</td>
</tr>);
}) : (<tr>
<td colSpan={6}>No transfers for this account just yet.</td> <td colSpan={6}>No transfers for this account just yet.</td>
</tr>); </tr>);
@@ -66,6 +97,7 @@ export class TransfersTable extends React.Component {
<th>Type</th> <th>Type</th>
<th>Other Account</th> <th>Other Account</th>
<th>Amount</th> <th>Amount</th>
<th>Balance</th>
<th>Description</th> <th>Description</th>
<th>Status</th> <th>Status</th>
</tr> </tr>

View File

@@ -12,6 +12,9 @@ const nodeInitialState = {
}; };
export const entities = (state = {...initialState}, action) => { export const entities = (state = {...initialState}, action) => {
if (typeof action.length !== 'undefined') {
debugger;
}
switch(action.type) { switch(action.type) {
case T.ENTITIES.REQUESTED: { case T.ENTITIES.REQUESTED: {
const { id } = action; const { id } = action;

View File

@@ -108,7 +108,7 @@ export function apiMakeTransfer(fromAccountId, {
export function apiRetrieveAccounts(customerId) { export function apiRetrieveAccounts(customerId) {
return fetch(`${getAccountsUrl()}?${makeQuery({ customerId })}`, { return fetch(`${getCustomersUrl()}/${customerId}/accounts`, {
headers: { headers: {
"Accept": "application/json", "Accept": "application/json",
"Content-Type": "application/json" "Content-Type": "application/json"

View File

@@ -1,34 +1,40 @@
/** /**
* Created by andrew on 26/02/16. * Created by andrew on 26/02/16.
*/ */
import Cookies from "js-cookie"; import Cookies from 'js-cookie';
import * as C from "./constants"; import * as C from "./constants";
import root from './root'; import root from './root';
//import "babel-polyfill";
// stateful variables that persist throughout session // stateful variables that persist throughout session
root.authState = { const authState = {
currentSettings: {}, currentSettings: {},
currentEndpoint: {}, currentEndpoint: {},
defaultEndpointKey: 'default' defaultEndpointKey: 'default'
}; };
const memoryStorage = {};
function clean(obj) {
Object.keys(obj).forEach(k => {
delete obj[k];
});
return obj;
}
export function setCurrentSettings (s) { export function setCurrentSettings (s) {
root.authState.currentSettings = s; authState.currentSettings = s;
} }
export function getCurrentSettings () { export function getCurrentSettings () {
return root.authState.currentSettings; return authState.currentSettings;
} }
export function setCurrentEndpoint (e) { export function setCurrentEndpoint (e) {
root.authState.currentEndpoint = e; authState.currentEndpoint = e;
} }
export function getCurrentEndpoint () { export function getCurrentEndpoint () {
return root.authState.currentEndpoint; return authState.currentEndpoint;
} }
/** /**
@@ -57,23 +63,20 @@ export function getDefaultEndpointKey () {
// reset stateful variables // reset stateful variables
export function resetConfig () { export function resetConfig () {
root.authState = root.authState || {}; clean(authState);
root.authState.currentSettings = {}; authState.currentSettings = {};
root.authState.currentEndpoint = {}; authState.currentEndpoint = {};
destroySession(); destroySession();
} }
export function destroySession () { export function destroySession () {
var sessionKeys = [
([
C.SAVED_CREDS_KEY, C.SAVED_CREDS_KEY,
C.SAVED_CONFIG_KEY, C.SAVED_CONFIG_KEY,
C.SAVED_USER_INFO C.SAVED_USER_INFO
]; ]).forEach(key => {
for (var key in sessionKeys) {
key = sessionKeys[key];
// kill all local storage keys // kill all local storage keys
if (root.localStorage) { if (root.localStorage) {
root.localStorage.removeItem(key); root.localStorage.removeItem(key);
@@ -81,9 +84,11 @@ export function destroySession () {
// remove from base path in case config is not specified // remove from base path in case config is not specified
Cookies.remove(key, { Cookies.remove(key, {
path: root.authState.currentSettings.cookiePath || "/" path: authState.currentSettings.cookiePath || "/"
}); });
} });
clean(memoryStorage);
} }
function unescapeQuotes (val) { function unescapeQuotes (val) {
@@ -146,19 +151,19 @@ export function getTransfersUrl () {
*/ */
export function getApiUrl(key) { export function getApiUrl(key) {
let configKey = getSessionEndpointKey(key); let configKey = getSessionEndpointKey(key);
return root.authState.currentEndpoint[configKey].apiUrl; return rauthState.currentEndpoint[configKey].apiUrl;
} }
export function getTokenFormat() { export function getTokenFormat() {
return root.authState.currentSettings.tokenFormat; return authState.currentSettings.tokenFormat;
} }
export function persistUserData(user) { export const persistUserData = (user) => {
persistData(C.SAVED_USER_INFO, user); memoryStorage[C.SAVED_USER_INFO] = user;
} };
export function retrieveUserData() { export const retrieveUserData = () =>{
return retrieveData(C.SAVED_USER_INFO); return memoryStorage[C.SAVED_USER_INFO];
} }
export function retrieveHeaders() { export function retrieveHeaders() {
@@ -168,24 +173,24 @@ export function retrieveHeaders() {
export function persistData (key, val) { export function persistData (key, val) {
val = root.JSON.stringify(val); val = root.JSON.stringify(val);
switch (root.authState.currentSettings.storage) { switch (authState.currentSettings.storage) {
case "localStorage": case "localStorage":
root.localStorage.setItem(key, val); root.localStorage.setItem(key, val);
break; break;
default: default:
Cookies.set(key, val, { Cookies.set(key, val, {
expires: root.authState.currentSettings.cookieExpiry, expires: authState.currentSettings.cookieExpiry,
path: root.authState.currentSettings.cookiePath path: authState.currentSettings.cookiePath
}); });
break; break;
} }
} }
export function retrieveData (key) { export function retrieveData (key) {
var val = null; let val = null;
switch (root.authState.currentSettings.storage) { switch (authState.currentSettings.storage) {
case "localStorage": case "localStorage":
val = root.localStorage && root.localStorage.getItem(key); val = root.localStorage && root.localStorage.getItem(key);
@@ -205,4 +210,4 @@ export function retrieveData (key) {
// unescape quotes // unescape quotes
return unescapeQuotes(val); return unescapeQuotes(val);
} }
} }