Skip to content

Commit

Permalink
Merge pull request #64 from onesimus-wiafe/SCRUM-65-frontend-portfoli…
Browse files Browse the repository at this point in the history
…o-list-page

Scrum 65 frontend portfolio list page
  • Loading branch information
djangbahevans authored Aug 8, 2024
2 parents 0ca3535 + 16bd7b3 commit 0553be2
Show file tree
Hide file tree
Showing 68 changed files with 1,050 additions and 443 deletions.
8 changes: 8 additions & 0 deletions GatewayService/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@
"Path": "/api/v1/orders/{**catch-all}"
}
},
"/portfolios": {
"ClusterId": "orderService",
"CorsPolicy": "AllowAll",
"AuthorizationPolicy": "default",
"Match": {
"Path": "/api/v1/portfolios/{**catch-all}"
}
},
"/users": {
"ClusterId": "userService",
"CorsPolicy": "AllowAll",
Expand Down
2 changes: 2 additions & 0 deletions OrderProcessingService/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,15 @@ dependencies {
implementation(project(":shared"))
implementation("org.springframework.boot:spring-boot-starter-data-redis")
implementation("io.lettuce:lettuce-core")
implementation("org.mapstruct:mapstruct:1.5.5.Final")
compileOnly("org.projectlombok:lombok")
runtimeOnly("org.postgresql:postgresql")
runtimeOnly("io.jsonwebtoken:jjwt-impl:0.12.6")
runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.12.6")
runtimeOnly("io.micrometer:micrometer-registry-prometheus")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
annotationProcessor("org.projectlombok:lombok")
annotationProcessor("org.mapstruct:mapstruct-processor:1.5.5.Final")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("com.h2database:h2")
testImplementation("org.springframework.security:spring-security-test")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ public OrderController(OrderValidationService validationService, OrderService or
@PreAuthorize("hasRole('USER')")
public ResponseEntity<OrderResponseDTO> sendOrder(@RequestBody OrderRequestDTO request) {
var auth = SecurityContextHolder.getContext().getAuthentication();

var principal = (User) auth.getPrincipal();

OrderResponseDTO response = new OrderResponseDTO();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,83 @@
package com.joe.trading.order_processing.controllers;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.joe.trading.order_processing.entities.dto.PortfolioRequestDTO;
import com.joe.trading.order_processing.entities.dto.PortfolioResponseDTO;
import com.joe.trading.order_processing.services.PortfolioService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.joe.trading.order_processing.entities.User;
import com.joe.trading.order_processing.entities.dto.CreatePortfolioRequestDTO;
import com.joe.trading.order_processing.entities.dto.PortfolioFilterRequestDto;
import com.joe.trading.order_processing.entities.dto.PortfolioResponseDTO;
import com.joe.trading.order_processing.mappers.PortfolioMapper;
import com.joe.trading.order_processing.services.PortfolioService;
import com.joe.trading.shared.dtos.PaginatedResponseDto;
import com.joe.trading.shared.exceptions.ResourceNotFoundException;

import lombok.AllArgsConstructor;

@RestController
@RequestMapping("/api/v1/portfolio")
@AllArgsConstructor
@RequestMapping("/api/v1/portfolios")
public class PortfolioController {

private final PortfolioService portfolioService;
private final PortfolioMapper portfolioMapper;

@PostMapping
@PreAuthorize("hasRole('USER')")
public ResponseEntity<PortfolioResponseDTO> createPortfolio(@RequestBody CreatePortfolioRequestDTO request) {
var auth = SecurityContextHolder.getContext().getAuthentication();
var principal = (User) auth.getPrincipal();

@Autowired
public PortfolioController(PortfolioService portfolioService) {
this.portfolioService = portfolioService;
var portfolio = portfolioService.createPortfolio(principal.getId(), request);

return ResponseEntity.status(HttpStatus.CREATED)
.body(portfolioMapper.toPortfolioResponseDTO(portfolio));
}

@PostMapping
public ResponseEntity<PortfolioResponseDTO> createPortfolio(@RequestBody PortfolioRequestDTO request) throws JsonProcessingException {
@DeleteMapping("/{id}")
@PreAuthorize("hasRole('USER')")
public ResponseEntity<Boolean> deletePortfolio(@PathVariable("id") Long portfolioId) throws ResourceNotFoundException {
var auth = SecurityContextHolder.getContext().getAuthentication();
var principal = (User) auth.getPrincipal();

return ResponseEntity.ok(portfolioService.deletePortfolio(principal.getId(), portfolioId));
}

return ResponseEntity.status(HttpStatus.CREATED).body(portfolioService.saveNewPortfolio(request.getUserId(), request.getPortfolioName()));
@GetMapping("/{id}")
@PreAuthorize("isAuthenticated()")
public ResponseEntity<PortfolioResponseDTO> getPortfolio(@PathVariable("id") Long portfolioId) throws ResourceNotFoundException {
var auth = SecurityContextHolder.getContext().getAuthentication();
var principal = (User) auth.getPrincipal();

var portfolio = portfolioService.getPortfolio(principal.getId(), portfolioId);

return ResponseEntity.ok(portfolioMapper.toPortfolioResponseDTO(portfolio));
}

@DeleteMapping
public ResponseEntity<Boolean> deletePortfolio(PortfolioRequestDTO request){
@GetMapping
@PreAuthorize("isAuthenticated()")
public ResponseEntity<PaginatedResponseDto<PortfolioResponseDTO>> getPortfolios(PortfolioFilterRequestDto filter) throws ResourceNotFoundException {
var auth = SecurityContextHolder.getContext().getAuthentication();
var principal = (User) auth.getPrincipal();

var portfolios = portfolioService.getPortfoliosByUserId(principal.getId(), filter);

var response = new PaginatedResponseDto<>(
portfolioMapper.toPortfolioResponseDTOs(portfolios.getContent()),
portfolios.getTotalPages(),
portfolios.getTotalElements(),
portfolios.getNumber() + 1
);

return ResponseEntity.ok(portfolioService.deletePortfolio(request));
return ResponseEntity.ok(response);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class OrderBook {
private String exchange;

@OneToMany(cascade = CascadeType.ALL, mappedBy = "orderBook", orphanRemoval = true)
private List<Executions> executions = new ArrayList();
private List<Executions> executions = new ArrayList<>();

@OneToOne
private Trade trade;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.joe.trading.order_processing.entities.dto.PortfolioResponseDTO;
import com.joe.trading.order_processing.entities.enums.PortfolioState;
import com.joe.trading.shared.dtos.PortfolioEventDto;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
Expand All @@ -26,64 +28,77 @@ public class Portfolio {
@OneToMany(cascade = CascadeType.ALL, mappedBy = "portfolio")
private List<Stock> stocks = new ArrayList<>();

private Double portfolioValue = (double) 0;
private String portfolioName;
@Column(name = "value", nullable = false)
private Double value = (double) 0;

@Column(name = "name", nullable = false)
private String name;

@Column(name = "description", nullable = true)
private String description;

@Enumerated(EnumType.STRING)
private PortfolioState state;
@Column(name = "state", nullable = false)
private PortfolioState state = PortfolioState.ACTIVE;

@ManyToOne
@JoinColumn(name = "user_id")
private User user;

@CreationTimestamp
private LocalDateTime createdDate;
@Column(name = "created_at", nullable = false)
private LocalDateTime createdAt;

@Column(name = "updated_at", nullable = false)
@UpdateTimestamp
private LocalDateTime updatedOn;
private LocalDateTime updatedAt;

public Portfolio(String portfolioName){
this.portfolioName = portfolioName;
public Portfolio(String name) {
this.name = name;
this.state = PortfolioState.ACTIVE;
}

public Portfolio(String portfolioName, PortfolioState state){
this.portfolioName = portfolioName;
public Portfolio(String name, PortfolioState state) {
this.name = name;
this.state = state;
}

public void addStock(Stock stock) {
this.stocks.add(stock);
}

public void updateValue(Double value){
this.portfolioValue += value;
public void updateValue(Double value) {
this.value += value;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Portfolio portfolio = (Portfolio) o;
return Objects.equals(id, portfolio.id) && Objects.equals(portfolioValue, portfolio.portfolioValue) && Objects.equals(portfolioName, portfolio.portfolioName) && state == portfolio.state && Objects.equals(user, portfolio.user);
return Objects.equals(id, portfolio.id) && Objects.equals(value, portfolio.value)
&& Objects.equals(name, portfolio.name) && state == portfolio.state
&& Objects.equals(user, portfolio.user);
}

@Override
public String toString() {
return "Portfolio{" +
"state=" + state +
", portfolioName='" + portfolioName + '\'' +
", portfolioValue=" + portfolioValue +
", name='" + name + '\'' +
", portfolioValue=" + value +
", stocks=" + stocks +
'}';
}

public PortfolioResponseDTO toPortfolioResponseDTO(){
return new PortfolioResponseDTO(this.id, this.portfolioName, this.portfolioValue, this.stocks);
public PortfolioEventDto toPortfolioEventDto() {
return new PortfolioEventDto(id, name, description, user.getId(), createdAt);
}

@Override
public int hashCode() {
return Objects.hash(id, portfolioValue, portfolioName, state, user);
return Objects.hash(id, value, name, state, user);
}
}
35 changes: 19 additions & 16 deletions ...ing/entities/dto/PortfolioRequestDTO.java → ...tities/dto/CreatePortfolioRequestDTO.java
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package com.joe.trading.order_processing.entities.dto;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class PortfolioRequestDTO {
private Long userId;
private String portfolioName;
private Long portfolioId;
}
package com.joe.trading.order_processing.entities.dto;

import jakarta.validation.constraints.NotEmpty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class CreatePortfolioRequestDTO {
@NotEmpty(message = "Name is required")
private String name;
private String description;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ public class OrderResponseDTO {
private String ticker;
private Integer quantity;
private Double unitPrice;
private String Side;
private String Strategy;
private String side;
private String strategy;
private String orderType;
private String message;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.joe.trading.order_processing.entities.dto;

import java.time.LocalDateTime;

import jakarta.validation.constraints.Min;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class PortfolioFilterRequestDto {
private String name;
private String description;
private LocalDateTime createdFrom;
private LocalDateTime createdTo;

@Min(value = 1, message = "Page number must be greater than 0")
private int page = 1;

@Min(value = 1, message = "Page size must be greater than 0")
private int size = 10;
private String sortBy = "id";

private String sortDir = "asc";
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
package com.joe.trading.order_processing.entities.dto;

import java.time.LocalDateTime;
import java.util.List;

import com.joe.trading.order_processing.entities.Stock;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.List;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class PortfolioResponseDTO {
private Long portfolioId;
private String portfolioName;
private Double portfolioValue;
private Long id;
private String name;
private String description;
private Double value;
private String state;
private LocalDateTime createdAt;
private List<Stock> stocks;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.joe.trading.order_processing.mappers;

import java.util.List;

import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

import com.joe.trading.order_processing.entities.Portfolio;
import com.joe.trading.order_processing.entities.dto.PortfolioResponseDTO;
import com.joe.trading.shared.dtos.PortfolioEventDto;

@Mapper(componentModel = "spring")
public interface PortfolioMapper {
PortfolioMapper INSTANCE = Mappers.getMapper(PortfolioMapper.class);

Portfolio toPortfolio(PortfolioEventDto portfolioEventDto);

Portfolio toPortfolio(PortfolioResponseDTO portfolioResponseDTO);

PortfolioResponseDTO toPortfolioResponseDTO(Portfolio portfolio);

List<PortfolioResponseDTO> toPortfolioResponseDTOs(List<Portfolio> portfolios);

PortfolioEventDto toPortfolioEventDto(Portfolio portfolio);
}
Loading

0 comments on commit 0553be2

Please sign in to comment.