Merge pull request #49 from dartandrevinsky/private-event-sourcing-examples-38
Account deletion + UI improvements
This commit is contained in:
@@ -3,23 +3,30 @@ package net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.
|
||||
import io.eventuate.Event;
|
||||
import io.eventuate.EventUtil;
|
||||
import io.eventuate.ReflectiveMutableCommandProcessingAggregate;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountCreditedEvent;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountDebitFailedDueToInsufficientFundsEvent;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountDebitedEvent;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountOpenedEvent;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class Account extends ReflectiveMutableCommandProcessingAggregate<Account, AccountCommand> {
|
||||
|
||||
private BigDecimal balance;
|
||||
private boolean deleted;
|
||||
|
||||
public List<Event> process(OpenAccountCommand cmd) {
|
||||
return EventUtil.events(new AccountOpenedEvent(cmd.getCustomerId(), cmd.getTitle(), cmd.getInitialBalance(), cmd.getDescription()));
|
||||
}
|
||||
|
||||
public List<Event> process(DeleteAccountCommand cmd) {
|
||||
return EventUtil.events(new AccountDeletedEvent());
|
||||
}
|
||||
|
||||
public List<Event> process(DebitAccountCommand cmd) {
|
||||
if(deleted)
|
||||
return new ArrayList<>();
|
||||
|
||||
if (balance.compareTo(cmd.getAmount()) < 0)
|
||||
return EventUtil.events(new AccountDebitFailedDueToInsufficientFundsEvent(cmd.getTransactionId()));
|
||||
else
|
||||
@@ -27,6 +34,9 @@ public class Account extends ReflectiveMutableCommandProcessingAggregate<Account
|
||||
}
|
||||
|
||||
public List<Event> process(CreditAccountCommand cmd) {
|
||||
if(deleted)
|
||||
return new ArrayList<>();
|
||||
|
||||
return EventUtil.events(new AccountCreditedEvent(cmd.getAmount(), cmd.getTransactionId()));
|
||||
}
|
||||
|
||||
@@ -34,6 +44,10 @@ public class Account extends ReflectiveMutableCommandProcessingAggregate<Account
|
||||
balance = event.getInitialBalance();
|
||||
}
|
||||
|
||||
public void apply(AccountDeletedEvent event) {
|
||||
deleted = true;
|
||||
}
|
||||
|
||||
public void apply(AccountDebitedEvent event) {
|
||||
balance = balance.subtract(event.getAmount());
|
||||
}
|
||||
|
||||
@@ -19,4 +19,7 @@ public class AccountService {
|
||||
return accountRepository.save(new OpenAccountCommand(customerId, title, initialBalance, description));
|
||||
}
|
||||
|
||||
public CompletableFuture<EntityWithIdAndVersion<Account>> deleteAccount(String accountId) {
|
||||
return accountRepository.update(accountId, new DeleteAccountCommand());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.eventuate.EntityWithIdAndVersion;
|
||||
import io.eventuate.EventHandlerContext;
|
||||
import io.eventuate.EventHandlerMethod;
|
||||
import io.eventuate.EventSubscriber;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.customers.CustomerToAccountDeleted;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.DebitRecordedEvent;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.MoneyTransferCreatedEvent;
|
||||
|
||||
@@ -22,13 +23,7 @@ public class AccountWorkflow {
|
||||
|
||||
String fromAccountId = event.getDetails().getFromAccountId();
|
||||
|
||||
return ctx.update(Account.class, fromAccountId, new DebitAccountCommand(amount, transactionId)).handle((x, e) -> {
|
||||
if (e != null) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
);
|
||||
return ctx.update(Account.class, fromAccountId, new DebitAccountCommand(amount, transactionId));
|
||||
}
|
||||
|
||||
@EventHandlerMethod
|
||||
@@ -38,13 +33,6 @@ public class AccountWorkflow {
|
||||
String fromAccountId = event.getDetails().getToAccountId();
|
||||
String transactionId = ctx.getEntityId();
|
||||
|
||||
return ctx.update(Account.class, fromAccountId, new CreditAccountCommand(amount, transactionId)).handle((x, e) -> {
|
||||
if (e != null) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
);
|
||||
return ctx.update(Account.class, fromAccountId, new CreditAccountCommand(amount, transactionId));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.accounts;
|
||||
|
||||
public class DeleteAccountCommand implements AccountCommand {
|
||||
}
|
||||
@@ -3,12 +3,10 @@ package net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.acco
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.accounts.AccountService;
|
||||
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.DeleteAccountResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@@ -26,6 +24,12 @@ public class AccountController {
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
public CompletableFuture<CreateAccountResponse> createAccount(@Validated @RequestBody CreateAccountRequest request) {
|
||||
return accountService.openAccount(request.getCustomerId(), request.getTitle(), request.getInitialBalance(), request.getDescription())
|
||||
.thenApply(entityAndEventInfo -> new CreateAccountResponse(entityAndEventInfo.getEntityId()));
|
||||
.thenApply(entityAndEventInfo -> new CreateAccountResponse(entityAndEventInfo.getEntityId()));
|
||||
}
|
||||
|
||||
@RequestMapping(value = "{accountId}", method = RequestMethod.DELETE)
|
||||
public CompletableFuture<DeleteAccountResponse> deleteAccount(@PathVariable String accountId) {
|
||||
return accountService.deleteAccount(accountId)
|
||||
.thenApply(entityAndEventInfo -> new DeleteAccountResponse(accountId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,10 @@ public class AccountInfoUpdateService {
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(String accountId) {
|
||||
accountInfoRepository.delete(accountId);
|
||||
}
|
||||
|
||||
|
||||
public void addTransaction(String accountId, AccountTransactionInfo ti) {
|
||||
mongoTemplate.upsert(new Query(where("id").is(accountId)),
|
||||
|
||||
@@ -45,6 +45,12 @@ public class AccountQueryWorkflow {
|
||||
accountInfoUpdateService.create(id, customerId, title, initialBalance, description, eventId);
|
||||
}
|
||||
|
||||
@EventHandlerMethod
|
||||
public void delete(DispatchedEvent<AccountDeletedEvent> de) {
|
||||
String id = de.getEntityId();
|
||||
accountInfoUpdateService.delete(id);
|
||||
}
|
||||
|
||||
@EventHandlerMethod
|
||||
public void recordTransfer(DispatchedEvent<MoneyTransferCreatedEvent> de) {
|
||||
String eventId = de.getEventId().asString();
|
||||
|
||||
@@ -5,9 +5,6 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 15.01.16.
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "api.gateway")
|
||||
public class ApiGatewayProperties {
|
||||
|
||||
|
||||
@@ -20,9 +20,6 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 15.01.16.
|
||||
*/
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
@EnableAutoConfiguration
|
||||
|
||||
@@ -2,9 +2,6 @@ package net.chrisrichardson.eventstore.javaexamples.banking.apigateway;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 07.12.15.
|
||||
*/
|
||||
public class RestUtil {
|
||||
|
||||
public static boolean isError(HttpStatus status) {
|
||||
|
||||
@@ -16,7 +16,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@@ -32,12 +31,8 @@ import java.net.URISyntaxException;
|
||||
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.POST;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.*;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 15.01.16.
|
||||
*/
|
||||
@RestController
|
||||
public class GatewayController {
|
||||
|
||||
@@ -57,7 +52,7 @@ public class GatewayController {
|
||||
.build();
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/api/**", method = {GET, POST})
|
||||
@RequestMapping(value = "/api/**", method = {GET, POST, DELETE})
|
||||
@ResponseBody
|
||||
public ResponseEntity<String> proxyRequest(HttpServletRequest request) throws NoSuchRequestHandlingMethodException, IOException, URISyntaxException {
|
||||
HttpUriRequest proxiedRequest = createHttpUriRequest(request);
|
||||
|
||||
@@ -10,9 +10,6 @@ import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 21.01.16.
|
||||
*/
|
||||
public class ContentRequestTransformer extends ProxyRequestTransformer {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -8,9 +8,6 @@ import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 21.01.16.
|
||||
*/
|
||||
public class HeadersRequestTransformer extends ProxyRequestTransformer {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -7,9 +7,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 21.01.16.
|
||||
*/
|
||||
public abstract class ProxyRequestTransformer {
|
||||
|
||||
protected ProxyRequestTransformer predecessor;
|
||||
|
||||
@@ -9,9 +9,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 21.01.16.
|
||||
*/
|
||||
public class URLRequestTransformer extends ProxyRequestTransformer {
|
||||
|
||||
private ApiGatewayProperties apiGatewayProperties;
|
||||
|
||||
@@ -22,4 +22,10 @@ api.gateway.endpoints[4].method=POST
|
||||
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
|
||||
api.gateway.endpoints[5].location=http://${transfers.commandside.service.host}:8080
|
||||
api.gateway.endpoints[6].path=[/]*api/customers.*
|
||||
api.gateway.endpoints[6].method=DELETE
|
||||
api.gateway.endpoints[6].location=http://${customers.commandside.service.host}:8080
|
||||
api.gateway.endpoints[7].path=[/]*api/accounts.*
|
||||
api.gateway.endpoints[7].method=DELETE
|
||||
api.gateway.endpoints[7].location=http://${accounts.commandside.service.host}:8080
|
||||
@@ -61,7 +61,7 @@ public class CustomerQuerySideIntegrationTest {
|
||||
public void verify(QuerySideCustomer querySideCustomer) {
|
||||
Assert.assertEquals(customerInfo.getName(), querySideCustomer.getName());
|
||||
Assert.assertEquals(customerInfo.getSsn(), querySideCustomer.getSsn());
|
||||
Assert.assertEquals(customerInfo.getEmail(), querySideCustomer.getEmail());
|
||||
Assert.assertEquals(customerInfo.getUserCredentials().getEmail(), querySideCustomer.getEmail());
|
||||
Assert.assertEquals(customerInfo.getPhoneNumber(), querySideCustomer.getPhoneNumber());
|
||||
Assert.assertEquals(customerInfo.getAddress(), querySideCustomer.getAddress());
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#! /bin/bash
|
||||
|
||||
export JAVA_OPTS="-Xmx128m -Xms128m"
|
||||
export EXTRA_INFRASTRUCTURE_SERVICES=cdcservice
|
||||
../_build-and-test-all.sh -f docker-compose-eventuate-local.yml -P eventuateLocal=1 $*
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#! /bin/bash
|
||||
|
||||
export JAVA_OPTS="-Xmx128m -Xms128m"
|
||||
../_build-and-test-all.sh $*
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.chrisrichardson.eventstore.javaexamples.banking.commonauth.controlle
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.QuerySideCustomer;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.UserCredentials;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.commonauth.CustomerAuthService;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.commonauth.model.AuthRequest;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.commonauth.model.ErrorResponse;
|
||||
@@ -23,9 +24,6 @@ import java.io.IOException;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.GET;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 21.09.15.
|
||||
*/
|
||||
@RestController
|
||||
@Validated
|
||||
@RequestMapping("/api")
|
||||
@@ -40,8 +38,8 @@ public class AuthController {
|
||||
private static ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
@RequestMapping(value = "/login", method = POST)
|
||||
public ResponseEntity<QuerySideCustomer> doAuth(@RequestBody @Valid AuthRequest request) throws IOException {
|
||||
QuerySideCustomer customer = customerAuthService.findByEmail(request.getEmail());
|
||||
public ResponseEntity<QuerySideCustomer> doAuth(@RequestBody @Valid UserCredentials request) throws IOException {
|
||||
QuerySideCustomer customer = customerAuthService.findByEmailAndPassword(request.getEmail(), request.getPassword());
|
||||
|
||||
Token token = tokenService.allocateToken(objectMapper.writeValueAsString(new User(request.getEmail())));
|
||||
return ResponseEntity.status(HttpStatus.OK).header("access-token", token.getKey())
|
||||
|
||||
@@ -3,20 +3,21 @@ package net.chrisrichardson.eventstore.javaexamples.banking.commonauth.model;
|
||||
import org.hibernate.validator.constraints.Email;
|
||||
import org.hibernate.validator.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 19.10.15.
|
||||
*/
|
||||
public class AuthRequest {
|
||||
|
||||
@NotBlank
|
||||
@Email
|
||||
private String email;
|
||||
|
||||
@NotBlank
|
||||
private String password;
|
||||
|
||||
public AuthRequest() {
|
||||
}
|
||||
|
||||
public AuthRequest(String email) {
|
||||
public AuthRequest(String email, String password) {
|
||||
this.email = email;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
@@ -26,4 +27,12 @@ public class AuthRequest {
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.commonauth;
|
||||
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.QuerySideCustomer;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.commonauth.filter.StatelessAuthenticationFilter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
@@ -22,9 +23,6 @@ import org.springframework.security.web.authentication.www.BasicAuthenticationFi
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 21.09.15.
|
||||
*/
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
@EnableWebSecurity
|
||||
@@ -43,21 +41,14 @@ public class AuthConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
//auth.inMemoryAuthentication();
|
||||
auth.userDetailsService(userDetailsServiceBean());
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDetailsService userDetailsServiceBean() {
|
||||
return email -> {
|
||||
/* QuerySideCustomer customer = customerAuthService.findByEmail(email);
|
||||
if (customer != null) {
|
||||
return new User(email);
|
||||
} else {
|
||||
throw new UsernameNotFoundException(String.format("could not find the customer '%s'", email));
|
||||
}*/
|
||||
//authorize everyone with basic authentication
|
||||
return new User(email, "", true, true, true, true,
|
||||
QuerySideCustomer customer = customerAuthService.findByEmail(email);
|
||||
return new User(email, customer.getPassword(), true, true, true, true,
|
||||
AuthorityUtils.createAuthorityList("USER"));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,9 +2,6 @@ package net.chrisrichardson.eventstore.javaexamples.banking.commonauth;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 21.09.15.
|
||||
*/
|
||||
@ConfigurationProperties(locations = "classpath:auth.properties", ignoreUnknownFields = false, prefix = "auth")
|
||||
public class AuthProperties {
|
||||
private String serverSecret;
|
||||
|
||||
@@ -8,4 +8,6 @@ import java.util.List;
|
||||
interface CustomerAuthRepository extends MongoRepository<QuerySideCustomer, String> {
|
||||
|
||||
List<QuerySideCustomer> findByEmail(String email);
|
||||
|
||||
List<QuerySideCustomer> findByEmailAndPassword(String email, String password);
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.commonauth;
|
||||
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.QuerySideCustomer;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.dao.support.DataAccessUtils;
|
||||
|
||||
/**
|
||||
* Created by Main on 15.02.2016.
|
||||
@@ -16,13 +14,10 @@ public class CustomerAuthService {
|
||||
}
|
||||
|
||||
public QuerySideCustomer findByEmail(String email) {
|
||||
List<QuerySideCustomer> customers = customerAuthRepository.findByEmail(email);
|
||||
if (customers.isEmpty())
|
||||
throw new EmptyResultDataAccessException(1);
|
||||
//TODO: add unique email constraint
|
||||
/* else if(customers.size()>1)
|
||||
throw new IncorrectResultSizeDataAccessException(1, customers.size());*/
|
||||
else
|
||||
return customers.get(0);
|
||||
return DataAccessUtils.uniqueResult(customerAuthRepository.findByEmail(email));
|
||||
}
|
||||
|
||||
public QuerySideCustomer findByEmailAndPassword(String email, String password) {
|
||||
return DataAccessUtils.uniqueResult(customerAuthRepository.findByEmailAndPassword(email, password));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,6 @@ import org.springframework.stereotype.Service;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 23.09.15.
|
||||
*/
|
||||
@Service
|
||||
public class TokenAuthenticationService {
|
||||
|
||||
|
||||
@@ -11,9 +11,6 @@ import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 23.09.15.
|
||||
*/
|
||||
public class StatelessAuthenticationFilter extends GenericFilterBean {
|
||||
|
||||
private final TokenAuthenticationService tokenAuthenticationService;
|
||||
|
||||
@@ -10,9 +10,6 @@ import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 23.09.15.
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class User implements UserDetails {
|
||||
|
||||
|
||||
@@ -5,9 +5,6 @@ import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 23.09.15.
|
||||
*/
|
||||
public class UserAuthentication implements Authentication {
|
||||
|
||||
private final User user;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts;
|
||||
|
||||
import io.eventuate.Event;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class AccountDeletedEvent implements Event {
|
||||
}
|
||||
@@ -2,9 +2,6 @@ package net.chrisrichardson.eventstore.javaexamples.banking.backend.common.custo
|
||||
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.CustomerInfo;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 02.02.16.
|
||||
*/
|
||||
public class CustomerCreatedEvent extends CustomerEvent {
|
||||
|
||||
private CustomerInfo customerInfo;
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.backend.common.customers;
|
||||
|
||||
public class CustomerToAccountDeleted extends CustomerEvent {
|
||||
|
||||
private String accountId;
|
||||
|
||||
public CustomerToAccountDeleted() {
|
||||
}
|
||||
|
||||
public CustomerToAccountDeleted(String accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
|
||||
public String getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public void setAccountId(String accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ apply plugin: 'java'
|
||||
dependencies {
|
||||
compile "commons-lang:commons-lang:2.6"
|
||||
compile "org.springframework.boot:spring-boot-starter-web:$springBootVersion"
|
||||
compile "org.springframework.boot:spring-boot-starter-data-mongodb:$springBootVersion"
|
||||
|
||||
testCompile group: 'junit', name: 'junit', version: '4.11'
|
||||
}
|
||||
|
||||
@@ -5,9 +5,6 @@ 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")
|
||||
|
||||
@@ -2,9 +2,6 @@ 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;
|
||||
|
||||
|
||||
@@ -2,9 +2,6 @@ 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;
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.accounts;
|
||||
|
||||
|
||||
public class DeleteAccountResponse {
|
||||
|
||||
private String accountId;
|
||||
|
||||
public DeleteAccountResponse() {
|
||||
}
|
||||
|
||||
public DeleteAccountResponse(String accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
|
||||
public String getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public void setAccountId(String accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,6 @@ 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;
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.customers;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 24.03.16.
|
||||
*/
|
||||
public class AddToAccountResponse {
|
||||
|
||||
private String version;
|
||||
|
||||
@@ -5,9 +5,6 @@ import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 02.02.16.
|
||||
*/
|
||||
public class Address {
|
||||
@NotNull
|
||||
private String street1;
|
||||
|
||||
@@ -1,29 +1,26 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.customers;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonUnwrapped;
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 03.02.16.
|
||||
*/
|
||||
public class CustomerInfo {
|
||||
private Name name;
|
||||
@NotNull
|
||||
protected String email;
|
||||
@JsonUnwrapped
|
||||
protected UserCredentials userCredentials;
|
||||
@NotNull
|
||||
protected String ssn;
|
||||
@NotNull
|
||||
protected String phoneNumber;
|
||||
protected Address address;
|
||||
|
||||
public CustomerInfo() {
|
||||
}
|
||||
|
||||
public CustomerInfo(Name name, String email, String ssn, String phoneNumber, Address address) {
|
||||
public CustomerInfo(Name name, UserCredentials userCredentials, String ssn, String phoneNumber, Address address) {
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
this.userCredentials = userCredentials;
|
||||
this.ssn = ssn;
|
||||
this.phoneNumber = phoneNumber;
|
||||
this.address = address;
|
||||
@@ -33,8 +30,8 @@ public class CustomerInfo {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
public UserCredentials getUserCredentials() {
|
||||
return userCredentials;
|
||||
}
|
||||
|
||||
public String getSsn() {
|
||||
|
||||
@@ -3,9 +3,6 @@ package net.chrisrichardson.eventstore.javaexamples.banking.common.customers;
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 03.02.16.
|
||||
*/
|
||||
public class CustomerResponse {
|
||||
|
||||
private String id;
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.customers;
|
||||
|
||||
import org.springframework.data.mongodb.core.index.Indexed;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Main on 05.02.2016.
|
||||
*/
|
||||
public class QuerySideCustomer {
|
||||
|
||||
private String id;
|
||||
private Name name;
|
||||
@Indexed(unique=true)
|
||||
private String email;
|
||||
private String password;
|
||||
private String ssn;
|
||||
private String phoneNumber;
|
||||
private Address address;
|
||||
@@ -17,10 +22,11 @@ public class QuerySideCustomer {
|
||||
public QuerySideCustomer() {
|
||||
}
|
||||
|
||||
public QuerySideCustomer(String id, Name name, String email, String ssn, String phoneNumber, Address address, Map<String, ToAccountInfo> toAccounts) {
|
||||
public QuerySideCustomer(String id, Name name, String email, String password, String ssn, String phoneNumber, Address address, Map<String, ToAccountInfo> toAccounts) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
this.password = password;
|
||||
this.ssn = ssn;
|
||||
this.phoneNumber = phoneNumber;
|
||||
this.address = address;
|
||||
@@ -51,6 +57,14 @@ public class QuerySideCustomer {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getSsn() {
|
||||
return ssn;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.common.customers;
|
||||
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
import org.hibernate.validator.constraints.Email;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
public class UserCredentials {
|
||||
@NotNull
|
||||
@Email
|
||||
private String email;
|
||||
@NotNull
|
||||
private String password;
|
||||
|
||||
public UserCredentials() {
|
||||
}
|
||||
|
||||
public UserCredentials(String email, String password) {
|
||||
this.email = email;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return EqualsBuilder.reflectionEquals(this, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCodeBuilder.reflectionHashCode(this);
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,6 @@ package net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.
|
||||
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.CustomerInfo;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 02.02.16.
|
||||
*/
|
||||
public class CreateCustomerCommand implements CustomerCommand {
|
||||
private CustomerInfo customerInfo;
|
||||
|
||||
|
||||
@@ -3,15 +3,13 @@ package net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.
|
||||
import io.eventuate.Event;
|
||||
import io.eventuate.EventUtil;
|
||||
import io.eventuate.ReflectiveMutableCommandProcessingAggregate;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.customers.CustomerToAccountDeleted;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.customers.CustomerAddedToAccount;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.customers.CustomerCreatedEvent;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.CustomerInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 02.02.16.
|
||||
*/
|
||||
public class Customer extends ReflectiveMutableCommandProcessingAggregate<Customer, CustomerCommand> {
|
||||
|
||||
private CustomerInfo customerInfo;
|
||||
@@ -23,6 +21,9 @@ public class Customer extends ReflectiveMutableCommandProcessingAggregate<Custom
|
||||
public List<Event> process(AddToAccountCommand cmd) {
|
||||
return EventUtil.events(new CustomerAddedToAccount(cmd.getToAccountInfo()));
|
||||
}
|
||||
public List<Event> process(DeleteToAccountCommand cmd) {
|
||||
return EventUtil.events(new CustomerToAccountDeleted(cmd.getAccountId()));
|
||||
}
|
||||
|
||||
public void apply(CustomerCreatedEvent event) {
|
||||
customerInfo = event.getCustomerInfo();
|
||||
@@ -30,6 +31,8 @@ public class Customer extends ReflectiveMutableCommandProcessingAggregate<Custom
|
||||
|
||||
public void apply(CustomerAddedToAccount event) {
|
||||
}
|
||||
public void apply(CustomerToAccountDeleted event) {
|
||||
}
|
||||
|
||||
public CustomerInfo getCustomerInfo() {
|
||||
return customerInfo;
|
||||
|
||||
@@ -23,4 +23,8 @@ public class CustomerService {
|
||||
public CompletableFuture<EntityWithIdAndVersion<Customer>> addToAccount(String customerId, ToAccountInfo toAccountInfo) {
|
||||
return accountRepository.update(customerId, new AddToAccountCommand(toAccountInfo));
|
||||
}
|
||||
|
||||
public CompletableFuture<EntityWithIdAndVersion<Customer>> deleteToAccount(String customerId, String accountId) {
|
||||
return accountRepository.update(customerId, new DeleteToAccountCommand(accountId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.customers;
|
||||
|
||||
public class DeleteToAccountCommand implements CustomerCommand {
|
||||
|
||||
private String accountId;
|
||||
|
||||
public DeleteToAccountCommand() {
|
||||
}
|
||||
|
||||
public DeleteToAccountCommand(String accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
|
||||
public String getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public void setAccountId(String accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.customers;
|
||||
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.customers.CustomerService;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.CreateAccountResponse;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.DeleteAccountResponse;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.AddToAccountResponse;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.CustomerInfo;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.CustomerResponse;
|
||||
@@ -11,9 +13,6 @@ import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 03.02.16.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/customers")
|
||||
public class CustomerController {
|
||||
@@ -37,4 +36,10 @@ public class CustomerController {
|
||||
.thenApply(entityAndEventInfo -> new AddToAccountResponse(entityAndEventInfo.getEntityVersion().toString()));
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/{customerId}/toaccounts/{accountId}", method = RequestMethod.DELETE)
|
||||
public CompletableFuture<DeleteAccountResponse> deleteToAccount(@PathVariable String customerId, @PathVariable String accountId) {
|
||||
return customerService.deleteToAccount(customerId, accountId)
|
||||
.thenApply(entityAndEventInfo -> new DeleteAccountResponse(accountId));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,9 +6,6 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 03.02.16.
|
||||
*/
|
||||
@Configuration
|
||||
@Import({CustomerConfiguration.class})
|
||||
@ComponentScan
|
||||
|
||||
@@ -6,46 +6,65 @@ import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.ToAc
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.core.query.Update;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.springframework.data.mongodb.core.query.Criteria.where;
|
||||
|
||||
/**
|
||||
* Created by Main on 04.02.2016.
|
||||
*/
|
||||
public class CustomerInfoUpdateService {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private QuerySideCustomerRepository querySideCustomerRepository;
|
||||
private QuerySideCustomerRepository querySideCustomerRepository;
|
||||
private MongoTemplate mongoTemplate;
|
||||
|
||||
public CustomerInfoUpdateService(QuerySideCustomerRepository querySideCustomerRepository) {
|
||||
this.querySideCustomerRepository = querySideCustomerRepository;
|
||||
public CustomerInfoUpdateService(QuerySideCustomerRepository querySideCustomerRepository, MongoTemplate mongoTemplate) {
|
||||
this.querySideCustomerRepository = querySideCustomerRepository;
|
||||
this.mongoTemplate = mongoTemplate;
|
||||
}
|
||||
|
||||
public void create(String id, CustomerInfo customerInfo) {
|
||||
try {
|
||||
querySideCustomerRepository.save(new QuerySideCustomer(id,
|
||||
customerInfo.getName(),
|
||||
customerInfo.getUserCredentials().getEmail(),
|
||||
customerInfo.getUserCredentials().getPassword(),
|
||||
customerInfo.getSsn(),
|
||||
customerInfo.getPhoneNumber(),
|
||||
customerInfo.getAddress(),
|
||||
Collections.<String, ToAccountInfo>emptyMap()
|
||||
)
|
||||
);
|
||||
logger.info("Saved in mongo");
|
||||
} catch (DuplicateKeyException t) {
|
||||
logger.warn("When saving ", t);
|
||||
}
|
||||
}
|
||||
|
||||
public void create(String id, CustomerInfo customerInfo) {
|
||||
try {
|
||||
querySideCustomerRepository.save(new QuerySideCustomer(id,
|
||||
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) {
|
||||
mongoTemplate.upsert(new Query(where("id").is(id)),
|
||||
new Update().
|
||||
set("toAccounts." + accountInfo.getId(), accountInfo),
|
||||
QuerySideCustomer.class);
|
||||
}
|
||||
|
||||
public void addToAccount(String id, ToAccountInfo accountInfo) {
|
||||
QuerySideCustomer customer = querySideCustomerRepository.findOne(id);
|
||||
customer.getToAccounts().put(accountInfo.getId(), accountInfo);
|
||||
querySideCustomerRepository.save(customer);
|
||||
}
|
||||
public void deleteToAccountFromAllCustomers(String accountId) {
|
||||
mongoTemplate.updateMulti(new Query(where("toAccounts." + accountId).exists(true)),
|
||||
new Update().
|
||||
unset("toAccounts." + accountId),
|
||||
QuerySideCustomer.class);
|
||||
}
|
||||
|
||||
public void deleteToAccount(String customerId, String accountId) {
|
||||
mongoTemplate.upsert(new Query(where("id").is(customerId)),
|
||||
new Update().
|
||||
unset("toAccounts." + accountId),
|
||||
QuerySideCustomer.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.cu
|
||||
import io.eventuate.DispatchedEvent;
|
||||
import io.eventuate.EventHandlerMethod;
|
||||
import io.eventuate.EventSubscriber;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountDeletedEvent;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.customers.CustomerToAccountDeleted;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.customers.CustomerAddedToAccount;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.customers.CustomerCreatedEvent;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.ToAccountInfo;
|
||||
@@ -42,4 +44,19 @@ public class CustomerQueryWorkflow {
|
||||
customerInfoUpdateService.addToAccount(id, toAccountInfo);
|
||||
}
|
||||
|
||||
@EventHandlerMethod
|
||||
public void deleteToAccount(DispatchedEvent<CustomerToAccountDeleted> de) {
|
||||
String id = de.getEntityId();
|
||||
CustomerToAccountDeleted event = de.getEvent();
|
||||
String accountId = event.getAccountId();
|
||||
|
||||
customerInfoUpdateService.deleteToAccount(id, accountId);
|
||||
}
|
||||
|
||||
@EventHandlerMethod
|
||||
public void deleteToAccounts(DispatchedEvent<AccountDeletedEvent> de) {
|
||||
String accountId = de.getEntityId();
|
||||
|
||||
customerInfoUpdateService.deleteToAccountFromAllCustomers(accountId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ public class QuerySideCustomerConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CustomerInfoUpdateService customerInfoUpdateService(QuerySideCustomerRepository querySideCustomerRepository) {
|
||||
return new CustomerInfoUpdateService(querySideCustomerRepository);
|
||||
public CustomerInfoUpdateService customerInfoUpdateService(QuerySideCustomerRepository querySideCustomerRepository, MongoTemplate mongoTemplate) {
|
||||
return new CustomerInfoUpdateService(querySideCustomerRepository, mongoTemplate);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.customers;
|
||||
|
||||
import io.eventuate.javaclient.spring.jdbc.EventuateJdbcEventStoreConfiguration;
|
||||
import io.eventuate.javaclient.spring.jdbc.IdGenerator;
|
||||
import io.eventuate.javaclient.spring.jdbc.IdGeneratorImpl;
|
||||
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.customers.CustomerInfo;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.QuerySideCustomer;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.ToAccountInfo;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.TransferState;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.IntegrationTest;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.CustomersTestUtils.generateCustomerInfo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = CustomerInfoUpdateServiceTest.CustomerInfoUpdateServiceTestConfiguration.class)
|
||||
@IntegrationTest
|
||||
public class CustomerInfoUpdateServiceTest {
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@Import({QuerySideCustomerConfiguration.class, EventuateJdbcEventStoreConfiguration.class})
|
||||
public static class CustomerInfoUpdateServiceTestConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private CustomerInfoUpdateService customerInfoUpdateService;
|
||||
|
||||
@Autowired
|
||||
private CustomerQueryService customerQueryService;
|
||||
|
||||
@Test
|
||||
public void shouldSaveQuerysideCustomer() throws ExecutionException, InterruptedException {
|
||||
IdGenerator x = new IdGeneratorImpl();
|
||||
String customerId = x.genId().asString();
|
||||
|
||||
CustomerInfo customerInfo = generateCustomerInfo();
|
||||
customerInfoUpdateService.create(customerId, customerInfo);
|
||||
|
||||
QuerySideCustomer querySideCustomer = customerQueryService.findByCustomerId(customerId).get();
|
||||
|
||||
assertEquals(customerInfo.getName(), querySideCustomer.getName());
|
||||
assertEquals(customerInfo.getAddress(), querySideCustomer.getAddress());
|
||||
assertEquals(customerInfo.getUserCredentials().getEmail(), querySideCustomer.getEmail());
|
||||
assertEquals(customerInfo.getPhoneNumber(), querySideCustomer.getPhoneNumber());
|
||||
assertEquals(customerInfo.getSsn(), querySideCustomer.getSsn());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldAddAndDeleteToAccount() throws ExecutionException, InterruptedException {
|
||||
IdGenerator x = new IdGeneratorImpl();
|
||||
String customerId = x.genId().asString();
|
||||
String accountId = x.genId().asString();
|
||||
|
||||
CustomerInfo customerInfo = generateCustomerInfo();
|
||||
customerInfoUpdateService.create(customerId, customerInfo);
|
||||
|
||||
ToAccountInfo toAccountInfo = new ToAccountInfo(accountId, "title", "owner", "description");
|
||||
|
||||
customerInfoUpdateService.addToAccount(customerId, toAccountInfo);
|
||||
|
||||
QuerySideCustomer querySideCustomer = customerQueryService.findByCustomerId(customerId).get();
|
||||
|
||||
assertTrue(querySideCustomer.getToAccounts().containsKey(accountId));
|
||||
assertEquals(toAccountInfo, querySideCustomer.getToAccounts().get(accountId));
|
||||
|
||||
customerInfoUpdateService.deleteToAccountFromAllCustomers(accountId);
|
||||
querySideCustomer = customerQueryService.findByCustomerId(customerId).get();
|
||||
|
||||
assertFalse(querySideCustomer.getToAccounts().containsKey(accountId));
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ dependencies {
|
||||
testCompile project(":testutil")
|
||||
testCompile project(":customers-command-side-service")
|
||||
testCompile "org.springframework.boot:spring-boot-starter-test"
|
||||
testCompile "io.eventuate.client.java:eventuate-client-java-jdbc:$eventuateClientVersion"
|
||||
}
|
||||
|
||||
test {
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package net.chrisrichardson.eventstore.javaexamples.banking.web;
|
||||
|
||||
import io.eventuate.javaclient.spring.jdbc.EventuateJdbcEventStoreConfiguration;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.commonauth.AuthConfiguration;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.customers.CustomersCommandSideWebConfiguration;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.web.customers.queryside.CustomersQuerySideWebConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -14,7 +17,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@Import({CustomersCommandSideServiceConfiguration.class, CustomersQuerySideServiceConfiguration.class, AuthConfiguration.class})
|
||||
@Import({CustomersCommandSideWebConfiguration.class, CustomersQuerySideWebConfiguration.class, EventuateJdbcEventStoreConfiguration.class, AuthConfiguration.class})
|
||||
@EnableAutoConfiguration
|
||||
public class CustomersQuerySideServiceTestConfiguration {
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
apigateway:
|
||||
image: java:openjdk-8u91-jdk
|
||||
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
|
||||
command: java ${JAVA_OPTS} -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
|
||||
environment:
|
||||
SPRING_DATA_MONGODB_URI: mongodb://mongodb/mydb
|
||||
ports:
|
||||
@@ -8,19 +8,19 @@ apigateway:
|
||||
|
||||
accountscommandside:
|
||||
image: java:openjdk-8u91-jdk
|
||||
command: java -jar /app/accounts-command-side-service.jar
|
||||
command: java ${JAVA_OPTS} -jar /app/accounts-command-side-service.jar
|
||||
ports:
|
||||
- "8085:8080"
|
||||
|
||||
transactionscommandside:
|
||||
image: java:openjdk-8u91-jdk
|
||||
command: java -jar /app/transactions-command-side-service.jar
|
||||
command: java ${JAVA_OPTS} -jar /app/transactions-command-side-service.jar
|
||||
ports:
|
||||
- "8082:8080"
|
||||
|
||||
accountsqueryside:
|
||||
image: java:openjdk-8u91-jdk
|
||||
command: java -jar /app/accounts-query-side-service.jar
|
||||
command: java ${JAVA_OPTS} -jar /app/accounts-query-side-service.jar
|
||||
environment:
|
||||
SPRING_DATA_MONGODB_URI: mongodb://mongodb/mydb
|
||||
ports:
|
||||
@@ -28,13 +28,13 @@ accountsqueryside:
|
||||
|
||||
customerscommandside:
|
||||
image: java:openjdk-8u91-jdk
|
||||
command: java -jar /app/customers-command-side-service.jar
|
||||
command: java ${JAVA_OPTS} -jar /app/customers-command-side-service.jar
|
||||
ports:
|
||||
- "8083:8080"
|
||||
|
||||
customersqueryside:
|
||||
image: java:openjdk-8u91-jdk
|
||||
command: java -jar /app/customers-query-side-service.jar
|
||||
command: java ${JAVA_OPTS} -jar /app/customers-query-side-service.jar
|
||||
ports:
|
||||
- "8084:8080"
|
||||
environment:
|
||||
|
||||
@@ -9,6 +9,7 @@ dependencies {
|
||||
testCompile project(":common-auth")
|
||||
testCompile "junit:junit:4.11"
|
||||
testCompile "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
|
||||
testCompile "org.jsoup:jsoup:1.9.2"
|
||||
}
|
||||
|
||||
test {
|
||||
|
||||
@@ -2,12 +2,21 @@ package net.chrisrichardson.eventstore.examples.bank.web;
|
||||
|
||||
|
||||
import net.chrisrichardson.eventstorestore.javaexamples.testutil.AbstractRestAPITest;
|
||||
import net.chrisrichardson.eventstorestore.javaexamples.testutil.AuthenticatedRestTemplate;
|
||||
import net.chrisrichardson.eventstorestore.javaexamples.testutil.CustomersTestUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.junit.Test;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
public class EndToEndTest extends AbstractRestAPITest {
|
||||
|
||||
private String indexUrl = "http://" + getenv("SERVICE_HOST", "localhost") + ":" + 8080 + "/index.html";
|
||||
|
||||
private String getenv(String name, String defaultValue) {
|
||||
String x = System.getenv(name);
|
||||
return x == null ? defaultValue : x;
|
||||
@@ -21,14 +30,16 @@ public class EndToEndTest extends AbstractRestAPITest {
|
||||
return "http://" + getenv("SERVICE_HOST", "localhost") + ":" + 8080 + "/api" + path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomersTestUtils getCustomersTestUtils() {
|
||||
return customersTestUtils;
|
||||
@Test
|
||||
public void shouldLoadStaticPage() throws IOException {
|
||||
Document doc = Jsoup.connect(indexUrl).get();
|
||||
assertNotNull(doc.title());
|
||||
assertEquals("Money Transfer App", doc.title());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticatedRestTemplate getAuthenticatedRestTemplate() {
|
||||
return new AuthenticatedRestTemplate(restTemplate);
|
||||
public CustomersTestUtils getCustomersTestUtils() {
|
||||
return customersTestUtils;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,6 +3,7 @@ package net.chrisrichardson.eventstore.javaexamples.banking.web;
|
||||
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.QuerySideCustomer;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.UserCredentials;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.commonauth.model.AuthRequest;
|
||||
import net.chrisrichardson.eventstorestore.javaexamples.testutil.CustomersTestUtils;
|
||||
import org.junit.Assert;
|
||||
@@ -48,8 +49,7 @@ public class BankingAuthTest {
|
||||
|
||||
@Test
|
||||
public void shouldCreateCustomerAndLogin() {
|
||||
String email = uniqueEmail();
|
||||
CustomerInfo customerInfo = generateCustomerInfo(email);
|
||||
CustomerInfo customerInfo = generateCustomerInfo();
|
||||
|
||||
final CustomerResponse customerResponse = restTemplate.postForEntity(baseUrl("/customers"), customerInfo, CustomerResponse.class).getBody();
|
||||
final String customerId = customerResponse.getId();
|
||||
@@ -57,23 +57,10 @@ public class BankingAuthTest {
|
||||
Assert.assertNotNull(customerId);
|
||||
Assert.assertEquals(customerInfo, customerResponse.getCustomerInfo());
|
||||
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
customersTestUtils.assertCustomerResponse(customerId, customerInfo);
|
||||
|
||||
AuthRequest authRequest = new AuthRequest(email);
|
||||
|
||||
final QuerySideCustomer loginQuerySideCustomer = restTemplate.postForEntity(baseUrl("/login"), authRequest, QuerySideCustomer.class).getBody();
|
||||
final QuerySideCustomer loginQuerySideCustomer = restTemplate.postForEntity(baseUrl("/login"), customerInfo.getUserCredentials(), QuerySideCustomer.class).getBody();
|
||||
|
||||
customersTestUtils.assertQuerySideCustomerEqualscCustomerInfo(loginQuerySideCustomer, customerResponse.getCustomerInfo());
|
||||
}
|
||||
|
||||
|
||||
private String uniqueEmail() {
|
||||
return System.currentTimeMillis() + "@email.com";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,11 +43,6 @@ public class BankingWebIntegrationTest extends AbstractRestAPITest {
|
||||
@Autowired
|
||||
RestTemplate restTemplate;
|
||||
|
||||
@Override
|
||||
public AuthenticatedRestTemplate getAuthenticatedRestTemplate() {
|
||||
return new AuthenticatedRestTemplate(restTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestTemplate getRestTemplate() {
|
||||
return restTemplate;
|
||||
|
||||
@@ -1,31 +1,36 @@
|
||||
package net.chrisrichardson.eventstorestore.javaexamples.testutil;
|
||||
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.*;
|
||||
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.QuerySideCustomer;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.ToAccountInfo;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.*;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.CreateMoneyTransferRequest;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.CreateMoneyTransferResponse;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.CustomersTestUtils.generateCustomerInfo;
|
||||
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.CustomersTestUtils.generateToAccountInfo;
|
||||
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.TestUtil.eventually;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public abstract class AbstractRestAPITest {
|
||||
|
||||
@Test
|
||||
public void shouldCreateAccountsAndTransferMoney() {
|
||||
CustomerInfo customerInfo = generateCustomerInfo();
|
||||
AuthenticatedRestTemplate authenticatedRestTemplate = getAuthenticatedRestTemplate(customerInfo.getUserCredentials());
|
||||
|
||||
final CustomerResponse customerResponse = getRestTemplate().postForEntity(baseUrl("/customers"), customerInfo, CustomerResponse.class).getBody();
|
||||
final String customerId = customerResponse.getId();
|
||||
|
||||
getCustomersTestUtils().assertCustomerResponse(customerId, customerInfo);
|
||||
|
||||
BigDecimal initialFromAccountBalance = new BigDecimal(500);
|
||||
BigDecimal initialToAccountBalance = new BigDecimal(100);
|
||||
BigDecimal amountToTransfer = new BigDecimal(150);
|
||||
@@ -33,14 +38,14 @@ public abstract class AbstractRestAPITest {
|
||||
BigDecimal finalFromAccountBalance = initialFromAccountBalance.subtract(amountToTransfer);
|
||||
BigDecimal finalToAccountBalance = initialToAccountBalance.add(amountToTransfer);
|
||||
|
||||
final CreateAccountResponse fromAccount = getAuthenticatedRestTemplate().postForEntity(baseUrl("/accounts"),
|
||||
new CreateAccountRequest("00000000-00000000", "My 1 Account", "", initialFromAccountBalance),
|
||||
final CreateAccountResponse fromAccount = authenticatedRestTemplate.postForEntity(baseUrl("/accounts"),
|
||||
new CreateAccountRequest(customerId, "My 1 Account", "", initialFromAccountBalance),
|
||||
CreateAccountResponse.class);
|
||||
|
||||
final String fromAccountId = fromAccount.getAccountId();
|
||||
|
||||
CreateAccountResponse toAccount = getAuthenticatedRestTemplate().postForEntity(baseUrl("/accounts"),
|
||||
new CreateAccountRequest("00000000-00000000", "My 2 Account", "", initialToAccountBalance),
|
||||
CreateAccountResponse toAccount = authenticatedRestTemplate.postForEntity(baseUrl("/accounts"),
|
||||
new CreateAccountRequest(customerId, "My 2 Account", "", initialToAccountBalance),
|
||||
CreateAccountResponse.class);
|
||||
|
||||
String toAccountId = toAccount.getAccountId();
|
||||
@@ -48,46 +53,39 @@ public abstract class AbstractRestAPITest {
|
||||
Assert.assertNotNull(fromAccountId);
|
||||
Assert.assertNotNull(toAccountId);
|
||||
|
||||
assertAccountBalance(fromAccountId, initialFromAccountBalance);
|
||||
assertAccountBalance(toAccountId, initialToAccountBalance);
|
||||
assertAccountBalance(authenticatedRestTemplate, fromAccountId, initialFromAccountBalance);
|
||||
assertAccountBalance(authenticatedRestTemplate, toAccountId, initialToAccountBalance);
|
||||
|
||||
final CreateMoneyTransferResponse moneyTransfer = getAuthenticatedRestTemplate().postForEntity(baseUrl("/transfers"),
|
||||
final CreateMoneyTransferResponse moneyTransfer = authenticatedRestTemplate.postForEntity(baseUrl("/transfers"),
|
||||
new CreateMoneyTransferRequest(fromAccountId, toAccountId, amountToTransfer, ""),
|
||||
CreateMoneyTransferResponse.class);
|
||||
|
||||
assertAccountBalance(fromAccountId, finalFromAccountBalance);
|
||||
assertAccountBalance(toAccountId, finalToAccountBalance);
|
||||
assertAccountBalance(authenticatedRestTemplate, fromAccountId, finalFromAccountBalance);
|
||||
assertAccountBalance(authenticatedRestTemplate, toAccountId, finalToAccountBalance);
|
||||
|
||||
eventually(
|
||||
new Producer<AccountHistoryResponse>() {
|
||||
@Override
|
||||
public CompletableFuture<AccountHistoryResponse> produce() {
|
||||
return CompletableFuture.completedFuture(getAuthenticatedRestTemplate().getForEntity(baseUrl("/accounts/" + fromAccountId + "/history"),
|
||||
AccountHistoryResponse.class));
|
||||
}
|
||||
},
|
||||
new Verifier<AccountHistoryResponse>() {
|
||||
@Override
|
||||
public void verify(AccountHistoryResponse accountHistoryResponse) {
|
||||
Optional<AccountHistoryEntry> first = accountHistoryResponse.getTransactionsHistory().stream().filter( ahe -> ahe.getEntryType() == AccountHistoryEntry.EntryType.transaction && ((AccountTransactionInfo)ahe).getTransactionId().equals(moneyTransfer.getMoneyTransferId())).findFirst();
|
||||
() -> CompletableFuture.completedFuture(authenticatedRestTemplate.getForEntity(baseUrl("/accounts/" + fromAccountId + "/history"),
|
||||
AccountHistoryResponse.class)),
|
||||
accountHistoryResponse -> {
|
||||
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 = (AccountTransactionInfo)first.get();
|
||||
AccountTransactionInfo ti = (AccountTransactionInfo) first.get();
|
||||
|
||||
assertEquals(fromAccountId, ti.getFromAccountId());
|
||||
assertEquals(toAccountId, ti.getToAccountId());
|
||||
assertEquals(toAccountId, ti.getToAccountId());
|
||||
assertEquals(fromAccountId, ti.getFromAccountId());
|
||||
assertEquals(toCents(amountToTransfer).longValue(), ti.getAmount());
|
||||
}
|
||||
assertEquals(fromAccountId, ti.getFromAccountId());
|
||||
assertEquals(toAccountId, ti.getToAccountId());
|
||||
assertEquals(toAccountId, ti.getToAccountId());
|
||||
assertEquals(fromAccountId, ti.getFromAccountId());
|
||||
assertEquals(toCents(amountToTransfer).longValue(), ti.getAmount());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateAccountsAndGetByCustomer() {
|
||||
public void shouldCreateAndDeleteAccountsAndGetByCustomer() {
|
||||
BigDecimal initialFromAccountBalance = new BigDecimal(500);
|
||||
CustomerInfo customerInfo = generateCustomerInfo();
|
||||
AuthenticatedRestTemplate authenticatedRestTemplate = getAuthenticatedRestTemplate(customerInfo.getUserCredentials());
|
||||
|
||||
final CustomerResponse customerResponse = getRestTemplate().postForEntity(baseUrl("/customers"), customerInfo, CustomerResponse.class).getBody();
|
||||
final String customerId = customerResponse.getId();
|
||||
@@ -97,7 +95,7 @@ public abstract class AbstractRestAPITest {
|
||||
|
||||
getCustomersTestUtils().assertCustomerResponse(customerId, customerInfo);
|
||||
|
||||
final CreateAccountResponse account = getAuthenticatedRestTemplate().postForEntity(baseUrl("/accounts"),
|
||||
final CreateAccountResponse account = authenticatedRestTemplate.postForEntity(baseUrl("/accounts"),
|
||||
new CreateAccountRequest(customerId, "My 1 Account", "", initialFromAccountBalance),
|
||||
CreateAccountResponse.class);
|
||||
|
||||
@@ -105,27 +103,26 @@ public abstract class AbstractRestAPITest {
|
||||
|
||||
Assert.assertNotNull(accountId);
|
||||
|
||||
assertAccountBalance(accountId, initialFromAccountBalance);
|
||||
assertAccountBalance(authenticatedRestTemplate, accountId, initialFromAccountBalance);
|
||||
|
||||
eventually(
|
||||
new Producer<GetAccountsResponse>() {
|
||||
@Override
|
||||
public CompletableFuture<GetAccountsResponse> produce() {
|
||||
return CompletableFuture.completedFuture(getAuthenticatedRestTemplate().getForEntity(baseUrl("/customers/"+customerId+"/accounts"),
|
||||
GetAccountsResponse.class));
|
||||
}
|
||||
},
|
||||
new Verifier<GetAccountsResponse>() {
|
||||
@Override
|
||||
public void verify(GetAccountsResponse accountResponses) {
|
||||
assertTrue(accountResponses.getAccounts().stream().filter(acc -> acc.getAccountId().equals(accountId)).findFirst().isPresent());
|
||||
}
|
||||
});
|
||||
() -> CompletableFuture.completedFuture(authenticatedRestTemplate.getForEntity(baseUrl("/customers/" + customerId + "/accounts"),
|
||||
GetAccountsResponse.class)),
|
||||
accountResponses -> assertTrue(accountResponses.getAccounts().stream().filter(acc -> acc.getAccountId().equals(accountId)).findFirst().isPresent()));
|
||||
|
||||
authenticatedRestTemplate.deleteEntity(baseUrl("/accounts/" + accountId),
|
||||
DeleteAccountResponse.class);
|
||||
|
||||
eventually(
|
||||
() -> CompletableFuture.completedFuture(authenticatedRestTemplate.getForEntity(baseUrl("/customers/" + customerId + "/accounts"),
|
||||
GetAccountsResponse.class)),
|
||||
accountResponses -> assertFalse(accountResponses.getAccounts().stream().filter(acc -> acc.getAccountId().equals(accountId)).findFirst().isPresent()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateCustomersAndAddToAccount() {
|
||||
CustomerInfo customerInfo = generateCustomerInfo();
|
||||
AuthenticatedRestTemplate authenticatedRestTemplate = getAuthenticatedRestTemplate(customerInfo.getUserCredentials());
|
||||
|
||||
final CustomerResponse customerResponse = getRestTemplate().postForEntity(baseUrl("/customers"), customerInfo, CustomerResponse.class).getBody();
|
||||
final String customerId = customerResponse.getId();
|
||||
@@ -137,55 +134,41 @@ public abstract class AbstractRestAPITest {
|
||||
|
||||
ToAccountInfo toAccountInfo = generateToAccountInfo();
|
||||
|
||||
getAuthenticatedRestTemplate().postForEntity(baseUrl("/customers/" + customerId + "/toaccounts"),
|
||||
authenticatedRestTemplate.postForEntity(baseUrl("/customers/" + customerId + "/toaccounts"),
|
||||
toAccountInfo,
|
||||
null);
|
||||
|
||||
assertToAccountsContains(customerId, toAccountInfo);
|
||||
assertToAccountsContains(customerId, authenticatedRestTemplate, toAccountInfo);
|
||||
}
|
||||
|
||||
private BigDecimal toCents(BigDecimal dollarAmount) {
|
||||
return dollarAmount.multiply(new BigDecimal(100));
|
||||
}
|
||||
|
||||
private void assertAccountBalance(final String fromAccountId, final BigDecimal expectedBalanceInDollars) {
|
||||
private void assertAccountBalance(AuthenticatedRestTemplate authenticatedRestTemplate, final String fromAccountId, final BigDecimal expectedBalanceInDollars) {
|
||||
final BigDecimal inCents = toCents(expectedBalanceInDollars);
|
||||
eventually(
|
||||
new Producer<GetAccountResponse>() {
|
||||
@Override
|
||||
public CompletableFuture<GetAccountResponse> produce() {
|
||||
return CompletableFuture.completedFuture(getAuthenticatedRestTemplate().getForEntity(baseUrl("/accounts/" + fromAccountId),
|
||||
GetAccountResponse.class));
|
||||
}
|
||||
},
|
||||
new Verifier<GetAccountResponse>() {
|
||||
@Override
|
||||
public void verify(GetAccountResponse accountInfo) {
|
||||
assertEquals(fromAccountId, accountInfo.getAccountId());
|
||||
assertEquals(inCents, accountInfo.getBalance());
|
||||
}
|
||||
() -> CompletableFuture.completedFuture(authenticatedRestTemplate.getForEntity(baseUrl("/accounts/" + fromAccountId),
|
||||
GetAccountResponse.class)),
|
||||
accountInfo -> {
|
||||
assertEquals(fromAccountId, accountInfo.getAccountId());
|
||||
assertEquals(inCents, accountInfo.getBalance());
|
||||
});
|
||||
}
|
||||
|
||||
private void assertToAccountsContains(final String customerId, final ToAccountInfo toAccountInfo) {
|
||||
private void assertToAccountsContains(final String customerId, AuthenticatedRestTemplate authenticatedRestTemplate, final ToAccountInfo toAccountInfo) {
|
||||
eventually(
|
||||
new Producer<QuerySideCustomer>() {
|
||||
@Override
|
||||
public CompletableFuture<QuerySideCustomer> produce() {
|
||||
return CompletableFuture.completedFuture(getAuthenticatedRestTemplate().getForEntity(baseUrl("/customers/" + customerId),
|
||||
QuerySideCustomer.class));
|
||||
}
|
||||
},
|
||||
new Verifier<QuerySideCustomer>() {
|
||||
@Override
|
||||
public void verify(QuerySideCustomer customerResponse) {
|
||||
assertEquals(customerId, customerResponse.getId());
|
||||
assertTrue(customerResponse.getToAccounts().values().stream().anyMatch(t -> t.equals(toAccountInfo)));
|
||||
}
|
||||
() -> CompletableFuture.completedFuture(authenticatedRestTemplate.getForEntity(baseUrl("/customers/" + customerId),
|
||||
QuerySideCustomer.class)),
|
||||
customerResponse -> {
|
||||
assertEquals(customerId, customerResponse.getId());
|
||||
assertTrue(customerResponse.getToAccounts().values().stream().anyMatch(t -> t.equals(toAccountInfo)));
|
||||
});
|
||||
}
|
||||
|
||||
public abstract AuthenticatedRestTemplate getAuthenticatedRestTemplate();
|
||||
public AuthenticatedRestTemplate getAuthenticatedRestTemplate(UserCredentials userCredentials) {
|
||||
return new AuthenticatedRestTemplate(getRestTemplate(), userCredentials);
|
||||
}
|
||||
|
||||
public abstract RestTemplate getRestTemplate();
|
||||
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
package net.chrisrichardson.eventstorestore.javaexamples.testutil;
|
||||
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.UserCredentials;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
public class AuthenticatedRestTemplate {
|
||||
|
||||
private RestTemplate restTemplate;
|
||||
private UserCredentials userCredentials;
|
||||
|
||||
public AuthenticatedRestTemplate(RestTemplate restTemplate) {
|
||||
public AuthenticatedRestTemplate(RestTemplate restTemplate, UserCredentials userCredentials) {
|
||||
this.restTemplate = restTemplate;
|
||||
this.userCredentials = userCredentials;
|
||||
}
|
||||
|
||||
public <T> T getForEntity(String url, Class<T> clazz) {
|
||||
return BasicAuthUtils.doBasicAuthenticatedRequest(restTemplate,
|
||||
url,
|
||||
HttpMethod.GET,
|
||||
clazz);
|
||||
clazz,
|
||||
userCredentials);
|
||||
}
|
||||
|
||||
public <T> T postForEntity(String url, Object requestObject, Class<T> clazz) {
|
||||
@@ -23,7 +27,17 @@ public class AuthenticatedRestTemplate {
|
||||
url,
|
||||
HttpMethod.POST,
|
||||
clazz,
|
||||
requestObject
|
||||
requestObject,
|
||||
userCredentials
|
||||
);
|
||||
}
|
||||
|
||||
public <T> T deleteEntity(String url, Class<T> clazz) {
|
||||
return BasicAuthUtils.doBasicAuthenticatedRequest(restTemplate,
|
||||
url,
|
||||
HttpMethod.DELETE,
|
||||
clazz,
|
||||
userCredentials
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.chrisrichardson.eventstorestore.javaexamples.testutil;
|
||||
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.UserCredentials;
|
||||
import org.apache.tomcat.util.codec.binary.Base64;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -12,10 +13,10 @@ import java.nio.charset.Charset;
|
||||
*/
|
||||
public class BasicAuthUtils {
|
||||
|
||||
public static HttpHeaders basicAuthHeaders(String username) {
|
||||
public static HttpHeaders basicAuthHeaders(UserCredentials userCredentials) {
|
||||
return new HttpHeaders() {
|
||||
{
|
||||
String auth = username + ":";
|
||||
String auth = userCredentials.getEmail() + ":" + userCredentials.getPassword();
|
||||
byte[] encodedAuth = Base64.encodeBase64(
|
||||
auth.getBytes(Charset.forName("US-ASCII")));
|
||||
String authHeader = "Basic " + new String(encodedAuth);
|
||||
@@ -24,16 +25,16 @@ public class BasicAuthUtils {
|
||||
};
|
||||
}
|
||||
|
||||
public static <T> T doBasicAuthenticatedRequest(RestTemplate restTemplate, String url, HttpMethod httpMethod, Class<T> responseType) {
|
||||
return doBasicAuthenticatedRequest(restTemplate, url, httpMethod, responseType, null);
|
||||
public static <T> T doBasicAuthenticatedRequest(RestTemplate restTemplate, String url, HttpMethod httpMethod, Class<T> responseType, UserCredentials userCredentials) {
|
||||
return doBasicAuthenticatedRequest(restTemplate, url, httpMethod, responseType, null, userCredentials);
|
||||
}
|
||||
|
||||
public static <T> T doBasicAuthenticatedRequest(RestTemplate restTemplate, String url, HttpMethod httpMethod, Class<T> responseType, Object requestObject) {
|
||||
public static <T> T doBasicAuthenticatedRequest(RestTemplate restTemplate, String url, HttpMethod httpMethod, Class<T> responseType, Object requestObject, UserCredentials userCredentials) {
|
||||
HttpEntity httpEntity;
|
||||
if (requestObject != null) {
|
||||
httpEntity = new HttpEntity<>(requestObject, BasicAuthUtils.basicAuthHeaders("test_user@mail.com"));
|
||||
httpEntity = new HttpEntity<>(requestObject, BasicAuthUtils.basicAuthHeaders(userCredentials));
|
||||
} else {
|
||||
httpEntity = new HttpEntity(BasicAuthUtils.basicAuthHeaders("test_user@mail.com"));
|
||||
httpEntity = new HttpEntity(BasicAuthUtils.basicAuthHeaders(userCredentials));
|
||||
}
|
||||
|
||||
ResponseEntity<T> responseEntity = restTemplate.exchange(url,
|
||||
|
||||
@@ -8,9 +8,6 @@ import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.TestUtil.eventually;
|
||||
|
||||
/**
|
||||
* Created by popikyardo on 02.03.16.
|
||||
*/
|
||||
public class CustomersTestUtils {
|
||||
|
||||
private RestTemplate restTemplate;
|
||||
@@ -22,39 +19,31 @@ public class CustomersTestUtils {
|
||||
}
|
||||
|
||||
public void assertCustomerResponse(final String customerId, final CustomerInfo customerInfo) {
|
||||
AuthenticatedRestTemplate art = new AuthenticatedRestTemplate(restTemplate);
|
||||
AuthenticatedRestTemplate art = new AuthenticatedRestTemplate(restTemplate, customerInfo.getUserCredentials());
|
||||
eventually(
|
||||
new Producer<QuerySideCustomer>() {
|
||||
@Override
|
||||
public CompletableFuture<QuerySideCustomer> produce() {
|
||||
return CompletableFuture.completedFuture(art.getForEntity(customersBaseUrl + customerId, QuerySideCustomer.class));
|
||||
}
|
||||
},
|
||||
new Verifier<QuerySideCustomer>() {
|
||||
@Override
|
||||
public void verify(QuerySideCustomer querySideCustomer) {
|
||||
Assert.assertEquals(customerId, querySideCustomer.getId());
|
||||
assertQuerySideCustomerEqualscCustomerInfo(querySideCustomer, customerInfo);
|
||||
}
|
||||
() -> CompletableFuture.completedFuture(art.getForEntity(customersBaseUrl + customerId, QuerySideCustomer.class)),
|
||||
querySideCustomer -> {
|
||||
Assert.assertEquals(customerId, querySideCustomer.getId());
|
||||
assertQuerySideCustomerEqualscCustomerInfo(querySideCustomer, customerInfo);
|
||||
});
|
||||
}
|
||||
|
||||
public void assertQuerySideCustomerEqualscCustomerInfo(QuerySideCustomer querySideCustomer, CustomerInfo customerInfo) {
|
||||
Assert.assertEquals(querySideCustomer.getName(), customerInfo.getName());
|
||||
Assert.assertEquals(querySideCustomer.getEmail(), customerInfo.getEmail());
|
||||
Assert.assertEquals(querySideCustomer.getEmail(), customerInfo.getUserCredentials().getEmail());
|
||||
Assert.assertEquals(querySideCustomer.getPhoneNumber(), customerInfo.getPhoneNumber());
|
||||
Assert.assertEquals(querySideCustomer.getSsn(), customerInfo.getSsn());
|
||||
Assert.assertEquals(querySideCustomer.getAddress(), customerInfo.getAddress());
|
||||
}
|
||||
|
||||
public static CustomerInfo generateCustomerInfo() {
|
||||
return generateCustomerInfo("current@email.com");
|
||||
return generateCustomerInfo(uniqueEmail());
|
||||
}
|
||||
|
||||
public static CustomerInfo generateCustomerInfo(String email) {
|
||||
return new CustomerInfo(
|
||||
new Name("John", "Doe"),
|
||||
email,
|
||||
new UserCredentials(email, "simple_password"),
|
||||
"000-00-0000",
|
||||
"1-111-111-1111",
|
||||
new Address("street 1",
|
||||
@@ -68,4 +57,8 @@ public class CustomersTestUtils {
|
||||
public static ToAccountInfo generateToAccountInfo() {
|
||||
return new ToAccountInfo("11111111-11111111", "New Account", "John Doe", "");
|
||||
}
|
||||
|
||||
private static String uniqueEmail() {
|
||||
return System.currentTimeMillis() + "@email.com";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public class TestUtil {
|
||||
|
||||
public static <T> void eventually(Producer<T> producer, Verifier<T> predicate) {
|
||||
Throwable laste = null;
|
||||
for (int i = 0; i < 30 ; i++) {
|
||||
for (int i = 0; i < 50 ; i++) {
|
||||
try {
|
||||
T x = producer.produce().get(30, TimeUnit.SECONDS);
|
||||
predicate.verify(x);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1
js-frontend/build/app.497ed0e9fa8411cbbf1d.js.map
Normal file
1
js-frontend/build/app.497ed0e9fa8411cbbf1d.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -12,8 +12,8 @@
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css">
|
||||
|
||||
<!-- 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>
|
||||
<body><div id="root"></div><script src="/manifest.087a5454fa0c34daf3c9.js"></script><script src="/vendor.c882d66445aebc52c21b.js"></script><script src="/style.6d7a32b1405ea1bb2bdf.js"></script><script src="/app.fcbedf54f0345474ccc1.js"></script><script>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap-theme.min.css"><link href="/style.b588c60da106277d78c8.css" rel="stylesheet"></head>
|
||||
<body><div id="root"></div><script src="/manifest.15c5d6172500c36b3280.js"></script><script src="/vendor.85781b28c9410377534e.js"></script><script src="/style.b588c60da106277d78c8.js"></script><script src="/app.497ed0e9fa8411cbbf1d.js"></script><script>
|
||||
(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),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
@@ -27,5 +27,5 @@
|
||||
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script><!--{"files":{"publicPath":"/","chunks":{"manifest":{"size":0,"entry":"/manifest.087a5454fa0c34daf3c9.js","hash":"087a5454fa0c34daf3c9","css":[]},"vendor":{"size":1670874,"entry":"/vendor.c882d66445aebc52c21b.js","hash":"c882d66445aebc52c21b","css":[]},"style":{"size":122,"entry":"/style.6d7a32b1405ea1bb2bdf.js","hash":"6d7a32b1405ea1bb2bdf","css":["/style.6d7a32b1405ea1bb2bdf.css"]},"app":{"size":352314,"entry":"/app.fcbedf54f0345474ccc1.js","hash":"fcbedf54f0345474ccc1","css":[]}},"js":["/manifest.087a5454fa0c34daf3c9.js","/vendor.c882d66445aebc52c21b.js","/style.6d7a32b1405ea1bb2bdf.js","/app.fcbedf54f0345474ccc1.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.15c5d6172500c36b3280.js","hash":"15c5d6172500c36b3280","css":[]},"vendor":{"size":1654379,"entry":"/vendor.85781b28c9410377534e.js","hash":"85781b28c9410377534e","css":[]},"style":{"size":122,"entry":"/style.b588c60da106277d78c8.js","hash":"b588c60da106277d78c8","css":["/style.b588c60da106277d78c8.css"]},"app":{"size":350105,"entry":"/app.497ed0e9fa8411cbbf1d.js","hash":"497ed0e9fa8411cbbf1d","css":[]}},"js":["/manifest.15c5d6172500c36b3280.js","/vendor.85781b28c9410377534e.js","/style.b588c60da106277d78c8.js","/app.497ed0e9fa8411cbbf1d.js"],"css":["/style.b588c60da106277d78c8.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>
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
/******/ script.charset = 'utf-8';
|
||||
/******/ script.async = true;
|
||||
/******/
|
||||
/******/ script.src = __webpack_require__.p + "" + {"0":"fcbedf54f0345474ccc1","1":"6d7a32b1405ea1bb2bdf","2":"c882d66445aebc52c21b"}[chunkId] + ".js";
|
||||
/******/ script.src = __webpack_require__.p + "" + {"0":"497ed0e9fa8411cbbf1d","1":"b588c60da106277d78c8","2":"85781b28c9410377534e"}[chunkId] + ".js";
|
||||
/******/ head.appendChild(script);
|
||||
/******/ }
|
||||
/******/ };
|
||||
@@ -92,4 +92,4 @@
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ([]);
|
||||
//# sourceMappingURL=manifest.087a5454fa0c34daf3c9.js.map
|
||||
//# sourceMappingURL=manifest.15c5d6172500c36b3280.js.map
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"sources":["webpack:///webpack/bootstrap edd3ecd6d3192330eb69?"],"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.087a5454fa0c34daf3c9.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\":\"fcbedf54f0345474ccc1\",\"1\":\"6d7a32b1405ea1bb2bdf\",\"2\":\"c882d66445aebc52c21b\"}[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 edd3ecd6d3192330eb69\n **/"],"sourceRoot":""}
|
||||
{"version":3,"sources":["webpack:///webpack/bootstrap ee51b0824572a7d4b9ec?"],"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.15c5d6172500c36b3280.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\":\"497ed0e9fa8411cbbf1d\",\"1\":\"b588c60da106277d78c8\",\"2\":\"85781b28c9410377534e\"}[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 ee51b0824572a7d4b9ec\n **/"],"sourceRoot":""}
|
||||
@@ -438,4 +438,4 @@ body {
|
||||
h1 {
|
||||
margin-top: .5em;
|
||||
}
|
||||
/*# sourceMappingURL=style.6d7a32b1405ea1bb2bdf.css.map*/
|
||||
/*# sourceMappingURL=style.b588c60da106277d78c8.css.map*/
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"sources":[],"names":[],"mappings":"","file":"style.6d7a32b1405ea1bb2bdf.css","sourceRoot":""}
|
||||
{"version":3,"sources":[],"names":[],"mappings":"","file":"style.b588c60da106277d78c8.css","sourceRoot":""}
|
||||
@@ -3,20 +3,20 @@ webpackJsonp([1,3],{
|
||||
/***/ 0:
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
__webpack_require__(614);
|
||||
module.exports = __webpack_require__(618);
|
||||
__webpack_require__(612);
|
||||
module.exports = __webpack_require__(616);
|
||||
|
||||
|
||||
/***/ },
|
||||
|
||||
/***/ 614:
|
||||
/***/ 612:
|
||||
/***/ function(module, exports) {
|
||||
|
||||
// removed by extract-text-webpack-plugin
|
||||
|
||||
/***/ },
|
||||
|
||||
/***/ 618:
|
||||
/***/ 616:
|
||||
/***/ function(module, exports) {
|
||||
|
||||
// removed by extract-text-webpack-plugin
|
||||
@@ -24,4 +24,4 @@ webpackJsonp([1,3],{
|
||||
/***/ }
|
||||
|
||||
});
|
||||
//# sourceMappingURL=style.6d7a32b1405ea1bb2bdf.js.map
|
||||
//# sourceMappingURL=style.b588c60da106277d78c8.js.map
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"sources":["webpack:///./~/react-select/dist/react-select.css?","webpack:///./src/main.less?"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,0C;;;;;;;ACAA,0C","file":"style.6d7a32b1405ea1bb2bdf.js","sourcesContent":["// removed by extract-text-webpack-plugin\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./~/react-select/dist/react-select.css\n ** module id = 614\n ** module chunks = 1\n **/","// removed by extract-text-webpack-plugin\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/main.less\n ** module id = 618\n ** module chunks = 1\n **/"],"sourceRoot":""}
|
||||
{"version":3,"sources":["webpack:///./~/react-select/dist/react-select.css?","webpack:///./src/main.less?"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,0C;;;;;;;ACAA,0C","file":"style.b588c60da106277d78c8.js","sourcesContent":["// removed by extract-text-webpack-plugin\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./~/react-select/dist/react-select.css\n ** module id = 612\n ** module chunks = 1\n **/","// removed by extract-text-webpack-plugin\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/main.less\n ** module id = 616\n ** module chunks = 1\n **/"],"sourceRoot":""}
|
||||
File diff suppressed because it is too large
Load Diff
1
js-frontend/build/vendor.85781b28c9410377534e.js.map
Normal file
1
js-frontend/build/vendor.85781b28c9410377534e.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,127 +0,0 @@
|
||||
import del from "del";
|
||||
import path from "path";
|
||||
import gulp from "gulp";
|
||||
import open from "open";
|
||||
import gulpLoadPlugins from "gulp-load-plugins";
|
||||
import packageJson from "./package.json";
|
||||
import runSequence from "run-sequence";
|
||||
import webpack from "webpack";
|
||||
import webpackConfig from "./webpack.config";
|
||||
import WebpackDevServer from "webpack-dev-server";
|
||||
|
||||
|
||||
const PORT = process.env.PORT || 3000;
|
||||
const $ = gulpLoadPlugins({camelize: true});
|
||||
|
||||
|
||||
// MyAccounts tasks
|
||||
gulp.task('serve', () => runSequence('serve:clean', 'serve:index', 'serve:start'));
|
||||
gulp.task('dist', () => runSequence('dist:clean', 'dist:build', 'dist:index'));
|
||||
gulp.task('clean', ['dist:clean', 'serve:clean']);
|
||||
gulp.task('open', () => open('http://localhost:3000'));
|
||||
|
||||
gulp.task('export', () => runSequence(/*'dist:clean', 'dist:build', 'dist:index',*/ 'export:clean', 'export:copy'));
|
||||
|
||||
// Remove all built files
|
||||
gulp.task('serve:clean', cb => del('build', {dot: true}, cb));
|
||||
gulp.task('dist:clean', cb => del(['dist', 'dist-intermediate'], {dot: true}, cb));
|
||||
gulp.task('export:clean', cb => del(['../prebuilt-web-client/**'], {dot: true, force: true}, cb));
|
||||
|
||||
// Copy static files across to our final directory
|
||||
gulp.task('serve:static', () =>
|
||||
gulp.src([
|
||||
'src/static/**'
|
||||
])
|
||||
.pipe($.changed('build'))
|
||||
.pipe(gulp.dest('build'))
|
||||
.pipe($.size({title: 'static'}))
|
||||
);
|
||||
|
||||
gulp.task('dist:static', () =>
|
||||
gulp.src([
|
||||
'src/static/**'
|
||||
])
|
||||
.pipe(gulp.dest('dist'))
|
||||
.pipe($.size({title: 'static'}))
|
||||
);
|
||||
|
||||
gulp.task('export:copy', () => {
|
||||
return gulp.src(['dist/**'])
|
||||
.pipe(gulp.dest('../prebuilt-web-client'));
|
||||
});
|
||||
|
||||
// Copy our index file and inject css/script imports for this build
|
||||
gulp.task('serve:index', () => {
|
||||
return gulp
|
||||
.src('src/index.html')
|
||||
.pipe($.injectString.after('<!-- inject:app:js -->', '<script src="generated/main.js"></script>'))
|
||||
.pipe(gulp.dest('build'));
|
||||
});
|
||||
|
||||
// Copy our index file and inject css/script imports for this build
|
||||
gulp.task('dist:index', () => {
|
||||
const app = gulp
|
||||
.src(["*.{css,js}"], {cwd: 'dist-intermediate/generated'})
|
||||
.pipe(gulp.dest('dist'));
|
||||
|
||||
// Build the index.html using the names of compiled files
|
||||
return gulp.src('src/index.html')
|
||||
.pipe($.inject(app, {
|
||||
ignorePath: 'dist',
|
||||
starttag: '<!-- inject:app:{{ext}} -->'
|
||||
}))
|
||||
.on("error", $.util.log)
|
||||
.pipe(gulp.dest('dist'));
|
||||
});
|
||||
|
||||
// Start a livereloading development server
|
||||
gulp.task('serve:start', ['serve:static'], () => {
|
||||
const config = webpackConfig(true, 'build', PORT);
|
||||
|
||||
// https://webpack.github.io/docs/webpack-dev-server.html
|
||||
return new WebpackDevServer(webpack(config), {
|
||||
contentBase: 'build',
|
||||
publicPath: config.output.publicPath,
|
||||
watchDelay: 100,
|
||||
historyApiFallback: true,
|
||||
//proxy: {
|
||||
// "*": "http://localhost:8080"
|
||||
//}
|
||||
|
||||
proxy: {
|
||||
'/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'
|
||||
}
|
||||
}
|
||||
})
|
||||
.listen(PORT, '0.0.0.0', (err) => {
|
||||
if (err) throw new $.util.PluginError('webpack-dev-server', err);
|
||||
|
||||
$.util.log(`[${packageJson.name} serve]`, `Listening at 0.0.0.0:${PORT}`);
|
||||
});
|
||||
});
|
||||
|
||||
// Create a distributable package
|
||||
gulp.task('dist:build', ['dist:static'], cb => {
|
||||
const config = webpackConfig(false, 'dist-intermediate');
|
||||
|
||||
webpack(config, (err, stats) => {
|
||||
if (err) throw new $.util.PluginError('dist', err);
|
||||
|
||||
$.util.log(`[${packageJson.name} dist]`, stats.toString({colors: true}));
|
||||
|
||||
cb();
|
||||
});
|
||||
});
|
||||
@@ -18,7 +18,6 @@
|
||||
"autoprefixer-loader": "^2.0.0",
|
||||
"babel-plugin-add-module-exports": "^0.1.2",
|
||||
"babel-plugin-transform-runtime": "^6.12.0",
|
||||
|
||||
"babel-cli": "^6.7.7",
|
||||
"babel-core": "^6.10.4",
|
||||
"babel-eslint": "^4.1.6",
|
||||
@@ -34,13 +33,6 @@
|
||||
"extract-text-webpack-plugin": "^0.8.1",
|
||||
"file-loader": "^0.8.4",
|
||||
"fill-range": "^2.2.2",
|
||||
"gulp": "^3.9.0",
|
||||
"gulp-changed": "^1.2.1",
|
||||
"gulp-inject": "^1.3.1",
|
||||
"gulp-inject-string": "0.0.2",
|
||||
"gulp-load-plugins": "^0.10.0",
|
||||
"gulp-size": "^1.2.1",
|
||||
"gulp-util": "^3.0.5",
|
||||
"html-webpack-plugin": "^2.22.0",
|
||||
"json-loader": "^0.5.4",
|
||||
"less": "^2.5.3",
|
||||
@@ -65,13 +57,11 @@
|
||||
"invariant": "^2.1.1",
|
||||
"isomorphic-fetch": "^2.2.1",
|
||||
"js-cookie": "^2.1.0",
|
||||
"object-pick": "^0.1.1",
|
||||
"querystring": "^0.2.0",
|
||||
"react": "^0.14.7",
|
||||
"react-bootstrap": "^0.28.3",
|
||||
"react-dom": "^0.14.0",
|
||||
"react-loader": "^2.4.0",
|
||||
"react-pacomo": "^0.5.1",
|
||||
"react-redux": "^4.4.0",
|
||||
"react-router": "^2.7.0",
|
||||
"react-router-bootstrap": "^0.20.1",
|
||||
@@ -83,7 +73,6 @@
|
||||
"redux-logger": "^2.6.0",
|
||||
"redux-multi": "^0.1.91",
|
||||
"redux-router": "^1.0.0-beta7",
|
||||
"redux-thunk": "^1.0.3",
|
||||
"uniloc": "^0.2.0"
|
||||
"redux-thunk": "^1.0.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Provider, connect} from "react-redux";
|
||||
import thunk from "redux-thunk";
|
||||
import createLogger from 'redux-logger';
|
||||
import { Route, IndexRoute, Link, IndexLink } from "react-router";
|
||||
import { RouterContext } from 'react-router';
|
||||
import { ReduxRouter} from "redux-router";
|
||||
import { createHistory, createHashHistory, createMemoryHistory } from "history";
|
||||
import { pushState, routerStateReducer, reduxReactRouter as clientRouter} from "redux-router";
|
||||
@@ -16,6 +17,7 @@ import { reduxReactRouter as serverRouter } from "redux-router/server";
|
||||
import mainReducer from './reducers';
|
||||
|
||||
import { configure as endpointsConfig } from './actions/configure';
|
||||
import { visitLocation } from './actions/navigate';
|
||||
import { requireAuthentication } from './components/AuthComponent';
|
||||
import Container from "./components/partials/Container";
|
||||
import MyAccounts from "./views/MyAccounts";
|
||||
@@ -25,7 +27,8 @@ import SignUp from "./views/SignUp";
|
||||
|
||||
class App extends React.Component {
|
||||
render() {
|
||||
return (<Container>
|
||||
return (
|
||||
<Container>
|
||||
{this.props.children}
|
||||
</Container>);
|
||||
}
|
||||
@@ -38,12 +41,19 @@ export function initialize({cookies, isServer, currentLocation, userAgent} = {})
|
||||
router: routerStateReducer
|
||||
});
|
||||
|
||||
let dispatch = null;
|
||||
|
||||
const onEnter = (nextState) => {
|
||||
const { location } = nextState;
|
||||
dispatch && dispatch(visitLocation(location));
|
||||
};
|
||||
|
||||
const routes = (
|
||||
<Route path="/" component={App}>
|
||||
<IndexRoute component={requireAuthentication(MyAccounts)} />
|
||||
<Route path="signin" component={SignIn} />
|
||||
<Route path="register" component={SignUp} />
|
||||
<Route path="account/:accountId" component={requireAuthentication(Account)} />
|
||||
<Route path="/" component={ App }>
|
||||
<IndexRoute component={ requireAuthentication(MyAccounts) } />
|
||||
<Route path="signin" component={ SignIn } onEnter={ onEnter } />
|
||||
<Route path="register" component={ SignUp } onEnter={ onEnter } />
|
||||
<Route path="account/:accountId" component={ requireAuthentication(Account) } />
|
||||
</Route>
|
||||
);
|
||||
|
||||
@@ -60,6 +70,7 @@ export function initialize({cookies, isServer, currentLocation, userAgent} = {})
|
||||
})
|
||||
)(createStore)(reducer);
|
||||
|
||||
dispatch = store.dispatch;
|
||||
|
||||
/**
|
||||
* The React Router 1.0 routes for both the server and the client.
|
||||
@@ -85,13 +96,11 @@ export function initialize({cookies, isServer, currentLocation, userAgent} = {})
|
||||
},
|
||||
handleLoginResponse: function(resp) {
|
||||
debugger;
|
||||
|
||||
return resp.data;
|
||||
},
|
||||
|
||||
handleAccountUpdateResponse: function(resp) {
|
||||
debugger;
|
||||
|
||||
return resp.data;
|
||||
},
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import React, {PropTypes} from 'react'
|
||||
import ApplicationLayout from './components/ApplicationLayout'
|
||||
import DocumentContainer from './containers/DocumentContainer'
|
||||
import DocumentListContainer from './containers/DocumentListContainer'
|
||||
|
||||
|
||||
// Application is the root component for your application.
|
||||
export default function Application(props) {
|
||||
return (
|
||||
<ApplicationLayout locationName={props.state.navigation.location.name}>
|
||||
{selectChildContainer(props)}
|
||||
</ApplicationLayout>
|
||||
)
|
||||
}
|
||||
Application.propTypes = {
|
||||
state: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
|
||||
// Define this as a separate function to allow us to use the switch statement
|
||||
// with `return` statements instead of `break`
|
||||
const selectChildContainer = props => {
|
||||
const location = props.state.navigation.location
|
||||
|
||||
let child
|
||||
switch (location.name) {
|
||||
case 'documentEdit':
|
||||
child = <DocumentContainer {...props} id={location.options.id} />
|
||||
case 'documentList':
|
||||
return <DocumentListContainer {...props} id={location.options.id}>{child}</DocumentListContainer>
|
||||
|
||||
default:
|
||||
return "Not Found"
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/**
|
||||
* Created by andrew on 25/02/16.
|
||||
*/
|
||||
|
||||
export function configureStart({...props} = {}) {
|
||||
return {
|
||||
...props,
|
||||
type: T.AUTH.CONFIGURE_START
|
||||
};
|
||||
}
|
||||
export function configureComplete({config, ...props} = {}) {
|
||||
return {
|
||||
...props,
|
||||
type: T.AUTH.CONFIGURE_COMPLETE,
|
||||
config
|
||||
};
|
||||
}
|
||||
export function configureError({errors, ...props} = {}) {
|
||||
return {
|
||||
...props,
|
||||
type: T.AUTH.CONFIGURE_ERROR,
|
||||
error: errors
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
import T from '../constants/ACTION_TYPES';
|
||||
import { makeActionCreator } from '../utils/actions';
|
||||
import * as U from '../utils/sessionStorage';
|
||||
|
||||
import { apiGetCurrentUser } from '../utils/api';
|
||||
import { entityReceived } from './entities';
|
||||
|
||||
|
||||
@@ -1,48 +1,24 @@
|
||||
/**
|
||||
* Created by andrew on 26/02/16.
|
||||
*/
|
||||
import * as C from "../utils/constants";
|
||||
import {
|
||||
authenticate,
|
||||
authenticateStart,
|
||||
authenticateComplete,
|
||||
authenticateError
|
||||
} from "./authenticate";
|
||||
|
||||
import {
|
||||
retrieveData,
|
||||
} from "../utils/sessionStorage";
|
||||
|
||||
|
||||
import {applyConfig} from "../utils/clientSettings";
|
||||
|
||||
//import {
|
||||
// showFirstTimeLoginSuccessModal,
|
||||
// showFirstTimeLoginErrorModal,
|
||||
// showPasswordResetSuccessModal,
|
||||
// showPasswordResetErrorModal
|
||||
//} from "./ui";
|
||||
|
||||
import getRedirectInfo from "../utils/parseUrl";
|
||||
import { pushState } from "redux-router";
|
||||
import root from '../utils/root';
|
||||
import { authenticate } from "./authenticate";
|
||||
import { applyConfig } from "../utils/clientSettings";
|
||||
|
||||
export const SET_ENDPOINT_KEYS = "SET_ENDPOINT_KEYS";
|
||||
export const STORE_CURRENT_ENDPOINT_KEY = "STORE_CURRENT_ENDPOINT_KEY";
|
||||
|
||||
export function setEndpointKeys(endpoints, currentEndpointKey, defaultEndpointKey) {
|
||||
return { type: SET_ENDPOINT_KEYS, endpoints, currentEndpointKey, defaultEndpointKey };
|
||||
}
|
||||
|
||||
export function storeCurrentEndpointKey(currentEndpointKey) {
|
||||
return { type: STORE_CURRENT_ENDPOINT_KEY, currentEndpointKey };
|
||||
return {
|
||||
type: SET_ENDPOINT_KEYS,
|
||||
endpoints,
|
||||
currentEndpointKey,
|
||||
defaultEndpointKey
|
||||
};
|
||||
}
|
||||
|
||||
export function configure(endpoint={}, settings={}) {
|
||||
|
||||
return dispatch => {
|
||||
|
||||
|
||||
return applyConfig({ dispatch, endpoint, settings })
|
||||
.then(() => {
|
||||
return dispatch(authenticate());
|
||||
|
||||
@@ -26,17 +26,17 @@ export const accountRefCreateComplete = makeActionCreator(T.ACCOUNTS.CREATE_REF_
|
||||
export const accountRefCreateError = makeActionCreator(T.ACCOUNTS.CREATE_REF_ERROR, 'error');
|
||||
export const accountRefCreateFormUpdate = makeActionCreator(T.ACCOUNTS.CREATE_REF_FORM_UPDATE, 'key', 'value');
|
||||
|
||||
export const accountRequested = makeActionCreator(T.ACCOUNT.SINGLE_START);
|
||||
export const accountComplete = makeActionCreator(T.ACCOUNT.SINGLE_COMPLETE, 'payload');
|
||||
export const accountError = makeActionCreator(T.ACCOUNT.SINGLE_ERROR, 'error');
|
||||
export const accountRequested = makeActionCreator(T.ACCOUNT.SINGLE_START, 'id');
|
||||
export const accountComplete = makeActionCreator(T.ACCOUNT.SINGLE_COMPLETE, 'id', 'payload');
|
||||
export const accountError = makeActionCreator(T.ACCOUNT.SINGLE_ERROR, 'id', 'error');
|
||||
|
||||
|
||||
export function accountsList(userId) {
|
||||
export function accountsList(customerId) {
|
||||
return dispatch => {
|
||||
dispatch(accountsListRequested());
|
||||
return api.apiRetrieveAccounts(userId)
|
||||
.then(list => {
|
||||
dispatch(accountsListReceived(list));
|
||||
return api.apiRetrieveAccounts(customerId)
|
||||
.then(({ accounts = []}) => {
|
||||
dispatch(accountsListReceived(accounts));
|
||||
})
|
||||
.catch(err => {
|
||||
dispatch(accountsListError(err));
|
||||
@@ -45,21 +45,23 @@ export function accountsList(userId) {
|
||||
};
|
||||
}
|
||||
|
||||
function readUntilChanged(initialData, customerId) {
|
||||
function readUntilChanged(initialData, promisedFn, leftCalls) {
|
||||
if (!leftCalls) {
|
||||
return Promise.reject('Data not changed')
|
||||
}
|
||||
const initialDataFlat = root['JSON'].stringify(initialData);
|
||||
debugger;
|
||||
return new Promise((rs, rj) => {
|
||||
setTimeout(() => {
|
||||
api.apiRetrieveAccounts(customerId)
|
||||
promisedFn()
|
||||
.then(data => {
|
||||
debugger;
|
||||
if (initialDataFlat == root['JSON'].stringify(data)) {
|
||||
return readUntilChanged.call(this, data, customerId).then(rs, rj); // Promise
|
||||
return readUntilChanged.call(this, data, promisedFn, leftCalls - 1).then(rs, rj); // Promise
|
||||
}
|
||||
rs(data);
|
||||
})
|
||||
.catch(rj)
|
||||
}, 500);
|
||||
}, 500 * Math.pow(2, 4 - leftCalls));
|
||||
})
|
||||
}
|
||||
|
||||
@@ -78,8 +80,9 @@ export function accountCreate(customerId, payload) {
|
||||
dispatch(authenticate(true));
|
||||
return accountId;
|
||||
} else {
|
||||
return readUntilChanged(data, customerId)
|
||||
return readUntilChanged(data, () => api.apiRetrieveAccounts(customerId), 4)
|
||||
.then(() => {
|
||||
debugger;
|
||||
dispatch(accountCreateComplete({
|
||||
id: ''
|
||||
}));
|
||||
@@ -130,13 +133,13 @@ export function fetchOwnAccounts(customerId) {
|
||||
|
||||
export function fetchAccount(accountId) {
|
||||
return dispatch => {
|
||||
dispatch(accountRequested());
|
||||
dispatch(accountRequested(accountId));
|
||||
return api.apiRetrieveAccount(accountId)
|
||||
.then(data => {
|
||||
dispatch(accountComplete(data));
|
||||
dispatch(accountComplete(accountId, data));
|
||||
})
|
||||
.catch(err => {
|
||||
dispatch(accountError(err));
|
||||
dispatch(accountError(accountId, err));
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -145,17 +148,21 @@ export const deleteAccountRequested = makeActionCreator(T.ACCOUNT.DELETE_START);
|
||||
export const deleteAccountComplete = makeActionCreator(T.ACCOUNT.DELETE_COMPLETE);
|
||||
export const deleteAccountError = makeActionCreator(T.ACCOUNT.DELETE_ERROR);
|
||||
|
||||
export function deleteAccount(customerId, accountId) {
|
||||
export function deleteAccount(customerId, accountId, isRef) {
|
||||
return dispatch => {
|
||||
dispatch(deleteAccountRequested());
|
||||
return api.apiDeleteAccount(accountId)
|
||||
|
||||
const deleteApiAction = (isRef ?
|
||||
api.apiDeleteRefAccount(customerId, accountId) :
|
||||
api.apiDeleteAccount(customerId, accountId));
|
||||
|
||||
return deleteApiAction
|
||||
.then(data => {
|
||||
//debugger;
|
||||
dispatch(deleteAccountComplete());
|
||||
return Promise.resolve('ok');
|
||||
dispatch(deleteAccountComplete(data));
|
||||
return Promise.resolve(data);
|
||||
})
|
||||
.catch(err => {
|
||||
dispatch(deleteAccountError());
|
||||
dispatch(deleteAccountError(err));
|
||||
return Promise.reject(err);
|
||||
})
|
||||
};
|
||||
@@ -208,7 +215,7 @@ export const createRefOwnerLookup = lookup => {
|
||||
|
||||
export const createRefAccountLookup = customerId => {
|
||||
return dispatch => {
|
||||
dispatch(createRefAccountLookupStart());
|
||||
dispatch(createRefAccountLookupStart(customerId));
|
||||
return api.apiRetrieveAccounts(customerId)
|
||||
.then(({ accounts }) => {
|
||||
const arr = accounts.map(({ accountId, title }) => ({
|
||||
@@ -256,7 +263,7 @@ export const getTransfers = (accountId) => {
|
||||
dispatch(getTransfersRequested(accountId));
|
||||
return api.apiRetrieveTransfers(accountId)
|
||||
.then(data => {
|
||||
dispatch(getTransfersComplete(accountId, data.transactionsHistory));
|
||||
dispatch(getTransfersComplete(accountId, data['transactionsHistory']));
|
||||
return data;
|
||||
})
|
||||
.catch(err => {
|
||||
|
||||
7
js-frontend/src/actions/navigate.js
Normal file
7
js-frontend/src/actions/navigate.js
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Created by andrew on 26/02/16.
|
||||
*/
|
||||
import T from '../constants/ACTION_TYPES';
|
||||
import { makeActionCreator } from '../utils/actions';
|
||||
|
||||
export const visitLocation = makeActionCreator(T.LOCATION.ENTER, 'location');
|
||||
@@ -1,29 +0,0 @@
|
||||
import T from '../constants/ACTION_TYPES'
|
||||
import ROUTES from '../constants/ROUTES'
|
||||
|
||||
|
||||
// `navigate` is used to facilitate changing routes within another action
|
||||
// without rendering any other changes first
|
||||
export function start(name, options) {
|
||||
return dispatch => {
|
||||
const currentURI = window.location.hash.substr(1)
|
||||
const newURI = ROUTES.generate(name, options)
|
||||
|
||||
if (currentURI != newURI) {
|
||||
dispatch({
|
||||
type: T.NAVIGATION.START,
|
||||
})
|
||||
|
||||
window.location.replace(
|
||||
window.location.pathname + window.location.search + '#' + newURI
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function complete() {
|
||||
return {
|
||||
type: T.NAVIGATION.COMPLETE,
|
||||
location: ROUTES.lookup(window.location.hash.substr(1)),
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,11 @@
|
||||
/**
|
||||
* Created by andrew on 26/02/16.
|
||||
*/
|
||||
import {
|
||||
setCurrentEndpointKey,
|
||||
getCurrentEndpointKey,
|
||||
persistUserData
|
||||
} from "../utils/sessionStorage";
|
||||
|
||||
import { entityReceived } from './entities';
|
||||
import { storeCurrentEndpointKey } from "./configure";
|
||||
//import { parseResponse } from "../utils/handleFetchResponse";
|
||||
//import fetch from "../utils/fetch";
|
||||
|
||||
import { apiSignIn } from '../utils/api';
|
||||
import { makeActionCreator } from '../utils/actions';
|
||||
|
||||
import T from '../constants/ACTION_TYPES';
|
||||
|
||||
//import root from '../utils/root';
|
||||
import { makeActionCreator } from '../utils/actions';
|
||||
import { persistUserData } from "../utils/sessionStorage";
|
||||
import { entityReceived } from './entities';
|
||||
import { apiSignIn } from '../utils/api';
|
||||
|
||||
export const emailSignInFormUpdate = makeActionCreator(T.AUTH.SIGN_IN_FORM_UPDATE, 'key', 'value');
|
||||
export const emailSignInStart = makeActionCreator(T.AUTH.SIGN_IN_START);
|
||||
|
||||
@@ -1,40 +1,18 @@
|
||||
/**
|
||||
* Created by andrew on 11/03/16.
|
||||
*/
|
||||
import {
|
||||
getEmailSignInUrl,
|
||||
setCurrentEndpointKey,
|
||||
getCurrentEndpointKey
|
||||
} from "../utils/sessionStorage";
|
||||
|
||||
import {destroySession} from "../utils/sessionStorage";
|
||||
|
||||
|
||||
import { entityReceived } from './entities';
|
||||
import { storeCurrentEndpointKey } from "./configure";
|
||||
import { parseResponse } from "../utils/handleFetchResponse";
|
||||
import fetch from "../utils/fetch";
|
||||
|
||||
import T from '../constants/ACTION_TYPES';
|
||||
import { makeActionCreator } from '../utils/actions';
|
||||
import { destroySession } from "../utils/sessionStorage";
|
||||
|
||||
import root from '../utils/root';
|
||||
|
||||
export function signOutStart() {
|
||||
return { type: T.AUTH.SIGN_OUT_START };
|
||||
}
|
||||
|
||||
export function signOutComplete() {
|
||||
return { type: T.AUTH.SIGN_OUT_COMPLETE };
|
||||
}
|
||||
|
||||
export function signOut() {
|
||||
return dispatch => {
|
||||
export const signOutStart = makeActionCreator(T.AUTH.SIGN_OUT_START);
|
||||
export const signOutComplete = makeActionCreator(T.AUTH.SIGN_OUT_COMPLETE);
|
||||
|
||||
export const signOut = () =>
|
||||
dispatch => {
|
||||
dispatch(signOutStart());
|
||||
|
||||
destroySession();
|
||||
|
||||
dispatch(signOutComplete());
|
||||
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -1,48 +1,34 @@
|
||||
/**
|
||||
* Created by andrew on 11/03/16.
|
||||
*/
|
||||
import {
|
||||
getEmailSignUpUrl
|
||||
} from "../utils/sessionStorage";
|
||||
|
||||
|
||||
import { entityReceived } from './entities';
|
||||
import { storeCurrentEndpointKey } from "./configure";
|
||||
//import { parseResponse } from "../utils/handleFetchResponse";
|
||||
import { push } from 'redux-router';
|
||||
import T from '../constants/ACTION_TYPES';
|
||||
import { makeActionCreator } from '../utils/actions';
|
||||
import { apiSignUp } from "../utils/api";
|
||||
import { emailSignInFormUpdate } from './signIn';
|
||||
import { push } from 'redux-router';
|
||||
|
||||
import T from '../constants/ACTION_TYPES';
|
||||
export const emailSignUpFormUpdate = makeActionCreator(T.AUTH.SIGN_UP_FORM_UPDATE, 'key', 'value');
|
||||
export const emailSignUpStart = makeActionCreator(T.AUTH.SIGN_UP_START);
|
||||
export const emailSignUpComplete = makeActionCreator(T.AUTH.SIGN_UP_COMPLETE, 'user');
|
||||
export const emailSignUpError = makeActionCreator(T.AUTH.SIGN_UP_ERROR, 'error');
|
||||
|
||||
export function emailSignUpFormUpdate(key, value) {
|
||||
return { type: T.AUTH.SIGN_UP_FORM_UPDATE, key, value };
|
||||
}
|
||||
|
||||
export function emailSignUpStart() {
|
||||
return { type: T.AUTH.SIGN_UP_START };
|
||||
}
|
||||
|
||||
export function emailSignUpComplete(user) {
|
||||
return { type: T.AUTH.SIGN_UP_COMPLETE, user };
|
||||
}
|
||||
|
||||
export function emailSignUpError(errors) {
|
||||
return { type: T.AUTH.SIGN_UP_ERROR, errors };
|
||||
}
|
||||
|
||||
export function emailSignUp(body) {
|
||||
return dispatch => {
|
||||
dispatch(emailSignUpStart());
|
||||
|
||||
return apiSignUp(body)
|
||||
.then(({data}) => {
|
||||
.then(({ data }) => {
|
||||
dispatch(emailSignUpComplete(data));
|
||||
const { email } = body;
|
||||
dispatch(emailSignInFormUpdate('email', email));
|
||||
dispatch(push('/signin'));
|
||||
})
|
||||
.catch(({errors}) => dispatch(emailSignUpError(errors)));
|
||||
.catch(({ errors }) => {
|
||||
dispatch(emailSignUpError({
|
||||
errors
|
||||
}))
|
||||
});
|
||||
|
||||
};
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import redirector from './redirector'
|
||||
import renderer from './renderer'
|
||||
|
||||
export default [
|
||||
redirector,
|
||||
renderer,
|
||||
]
|
||||
@@ -1,20 +0,0 @@
|
||||
import * as navigation from '../actions/navigation'
|
||||
import ROUTES from '../constants/ROUTES'
|
||||
|
||||
|
||||
export default function redirector(state, dispatch) {
|
||||
const {name, options} = state.navigation.location || {}
|
||||
const currentURI = window.location.hash.substr(1)
|
||||
const canonicalURI = name && ROUTES.generate(name, options)
|
||||
|
||||
if (canonicalURI && canonicalURI !== currentURI) {
|
||||
// If the URL entered includes extra `/` characters, or otherwise
|
||||
// differs from the canonical URL, navigate the user to the
|
||||
// canonical URL (which will result in `complete` being called again)
|
||||
dispatch(navigation.start(name, options))
|
||||
}
|
||||
else if (name == 'root') {
|
||||
// If we've hit the root location, redirect the user to the main page
|
||||
dispatch(navigation.start('documentList'))
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import Application from '../App'
|
||||
|
||||
|
||||
// Store a reference to our application's root DOM node to prevent repeating
|
||||
// this on every state update
|
||||
const APP_NODE = document.getElementById('react-app')
|
||||
|
||||
export default function renderer(state, dispatch) {
|
||||
// Don't re-render if we're in the process of navigating to a new page
|
||||
if (!state.navigation.transitioning) {
|
||||
ReactDOM.render(
|
||||
<Application state={state} dispatch={dispatch} />,
|
||||
APP_NODE
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,8 @@ import { initialize } from "./app";
|
||||
/**
|
||||
* Fire-up React Router.
|
||||
*/
|
||||
const reactRoot = window.document.getElementById("root");
|
||||
initialize().then(({ provider }) => {
|
||||
const reactRoot = window.document.getElementById("root");
|
||||
ReactDOM.render(provider, reactRoot);
|
||||
});
|
||||
|
||||
@@ -17,6 +17,7 @@ initialize().then(({ provider }) => {
|
||||
* Detect whether the server-side render has been discarded due to an invalid checksum.
|
||||
*/
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
const reactRoot = window.document.getElementById("root");
|
||||
if (!reactRoot.firstChild || !reactRoot.firstChild.attributes ||
|
||||
!reactRoot.firstChild.attributes["data-react-checksum"]) {
|
||||
console.error("Server-side React render was discarded. Make sure that your initial render does not contain any client-side code.");
|
||||
|
||||
@@ -31,8 +31,12 @@ export class AccountInfo extends React.Component {
|
||||
const account = entities[accountId];
|
||||
|
||||
if (!account || !accountId) {
|
||||
return (<div title={ `${accountId}` }>{ accountId } <Spinner loaded={false} /></div>);
|
||||
// {/*return (<Link to={ `/account/${accountId}` }>{ accountId } <Spinner loaded={false} /></Link>)*/}
|
||||
return (<div className="text-info" title={ `${accountId}` }>Loading.. <Spinner loaded={false} /></div>);
|
||||
}
|
||||
|
||||
const { errors } = account;
|
||||
if (errors) {
|
||||
return (<div className="text-danger">{ errors }</div>);
|
||||
}
|
||||
|
||||
const { title, owner } = account;
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
//import './ApplicationLayout.less'
|
||||
|
||||
import React, {PropTypes} from 'react'
|
||||
//import { pacomoTransformer } from '../utils/pacomo'
|
||||
import Link from './Link'
|
||||
|
||||
|
||||
const ApplicationLayout = ({
|
||||
children,
|
||||
locationName,
|
||||
}) =>
|
||||
(<div>
|
||||
<nav className='navbar'>
|
||||
<Link
|
||||
name='documentList'
|
||||
className={{
|
||||
'link': true,
|
||||
'link-active': locationName == 'documentList' || locationName == 'documentEdit',
|
||||
}}
|
||||
>
|
||||
Documents
|
||||
</Link>
|
||||
</nav>
|
||||
<main className='content'>
|
||||
{children}
|
||||
</main>
|
||||
</div>);
|
||||
|
||||
ApplicationLayout.propTypes = {
|
||||
children: PropTypes.element.isRequired,
|
||||
locationName: PropTypes.string
|
||||
};
|
||||
|
||||
export default ApplicationLayout;
|
||||
//export default pacomoTransformer(ApplicationLayout)
|
||||
@@ -1,26 +0,0 @@
|
||||
.app-ApplicationLayout {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
|
||||
&-navbar {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 192px;
|
||||
|
||||
border-right: 1px solid black;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
&-content {
|
||||
position: relative;
|
||||
padding-left: 192px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&-link-active {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { pushState } from 'redux-router';
|
||||
|
||||
import read from '../utils/readProp';
|
||||
|
||||
export function requireAuthentication(Component) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user