mirror of
https://github.com/mvvasilev/personal-finances.git
synced 2025-04-19 14:19:52 +03:00
Split off statements and widgets APIs into own microservices
This commit is contained in:
parent
b63d099562
commit
b2cee1d1c2
131 changed files with 705 additions and 281 deletions
4
.idea/gradle.xml
generated
4
.idea/gradle.xml
generated
|
@ -12,8 +12,10 @@
|
|||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/pefi-api-gateway" />
|
||||
<option value="$PROJECT_DIR$/pefi-common" />
|
||||
<option value="$PROJECT_DIR$/pefi-core-api" />
|
||||
<option value="$PROJECT_DIR$/pefi-frontend" />
|
||||
<option value="$PROJECT_DIR$/pefi-monolith" />
|
||||
<option value="$PROJECT_DIR$/pefi-statements-api" />
|
||||
<option value="$PROJECT_DIR$/pefi-widgets-api" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
|
|
1
.idea/sqldialects.xml
generated
1
.idea/sqldialects.xml
generated
|
@ -1,7 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="SqlDialectMappings">
|
||||
<file url="file://$PROJECT_DIR$/pefi-monolith/src/main/java/dev/mvvasilev/finances/persistence/RawTransactionValueGroupRepository.java" dialect="GenericSQL" />
|
||||
<file url="PROJECT" dialect="PostgreSQL" />
|
||||
</component>
|
||||
</project>
|
|
@ -11,9 +11,16 @@ repositories {
|
|||
|
||||
dependencies {
|
||||
implementation 'jakarta.persistence:jakarta.persistence-api:3.1.0'
|
||||
implementation 'org.springframework:spring-web:6.1.1'
|
||||
implementation 'org.springframework:spring-web:6.1.3'
|
||||
implementation 'org.springframework.data:spring-data-jpa:3.2.0'
|
||||
|
||||
implementation 'org.springframework.security:spring-security-oauth2-jose:6.2.0'
|
||||
implementation 'org.springframework.security:spring-security-oauth2-resource-server:6.2.0'
|
||||
implementation 'org.springframework.security:spring-security-web:6.2.0'
|
||||
implementation 'org.springframework.security:spring-security-config:6.2.0'
|
||||
implementation 'io.swagger.core.v3:swagger-models-jakarta:2.2.19'
|
||||
implementation 'org.apache.commons:commons-lang3:3.13.0'
|
||||
|
||||
testImplementation platform('org.junit:junit-bom:5.9.1')
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
package dev.mvvasilev.common.configuration;
|
||||
|
||||
import dev.mvvasilev.common.web.APIErrorDTO;
|
||||
import dev.mvvasilev.common.web.APIResponseDTO;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
public class CommonControllerConfiguration {
|
||||
|
||||
@RestControllerAdvice(basePackages = {"dev.mvvasilev"})
|
||||
public static class APIResponseAdvice {
|
||||
|
||||
@Value("${debug}")
|
||||
private boolean isDebug = false;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseEntity<APIResponseDTO<Object>> processGenericException(Exception ex) {
|
||||
List<APIErrorDTO> errors = List.of(
|
||||
new APIErrorDTO(
|
||||
ex.getMessage(),
|
||||
isDebug ? ex.getClass().getCanonicalName() : null,
|
||||
isDebug ? ExceptionUtils.getStackTrace(ex) : null
|
||||
)
|
||||
);
|
||||
|
||||
logger.error("Exception", ex);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body(new APIResponseDTO<>(
|
||||
null,
|
||||
errors,
|
||||
HttpStatus.INTERNAL_SERVER_ERROR.value(),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package dev.mvvasilev.finances.configuration;
|
||||
package dev.mvvasilev.common.configuration;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
@ -16,7 +16,7 @@ import org.springframework.web.filter.CommonsRequestLoggingFilter;
|
|||
|
||||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
public class SecurityConfiguration {
|
||||
public class CommonSecurityConfiguration {
|
||||
|
||||
@Value("${jwt.issuer-url}")
|
||||
public String jwtIssuerUrl;
|
||||
|
@ -28,17 +28,6 @@ public class SecurityConfiguration {
|
|||
"/swagger-resources/**"
|
||||
};
|
||||
|
||||
@Bean
|
||||
public CommonsRequestLoggingFilter requestLoggingFilter() {
|
||||
CommonsRequestLoggingFilter loggingFilter = new CommonsRequestLoggingFilter();
|
||||
loggingFilter.setIncludeClientInfo(true);
|
||||
loggingFilter.setIncludeHeaders(true);
|
||||
loggingFilter.setIncludeQueryString(true);
|
||||
loggingFilter.setIncludePayload(true);
|
||||
loggingFilter.setMaxPayloadLength(64000);
|
||||
return loggingFilter;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity, BearerTokenResolver bearerTokenResolver) throws Exception {
|
||||
return httpSecurity
|
|
@ -1,4 +1,4 @@
|
|||
package dev.mvvasilev.finances.configuration;
|
||||
package dev.mvvasilev.common.configuration;
|
||||
|
||||
import io.swagger.v3.oas.models.Components;
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
|
@ -10,10 +10,10 @@ import org.springframework.context.annotation.Configuration;
|
|||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
public class SwaggerConfiguration {
|
||||
public class CommonSwaggerConfiguration {
|
||||
|
||||
@Bean
|
||||
public OpenAPI customizeOpenAPI() {
|
||||
public OpenAPI jwtAuth() {
|
||||
final String securitySchemeName = "bearerAuth";
|
||||
return new OpenAPI()
|
||||
.components(
|
|
@ -0,0 +1,69 @@
|
|||
package dev.mvvasilev.common.dto;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class CreateProcessedTransactionDTO {
|
||||
|
||||
private String description;
|
||||
|
||||
private Integer userId;
|
||||
|
||||
private Double amount;
|
||||
|
||||
private boolean isInflow;
|
||||
|
||||
private LocalDateTime timestamp;
|
||||
|
||||
private Long statementId;
|
||||
|
||||
public CreateProcessedTransactionDTO() {
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Integer getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(Integer userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public Double getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(Double amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public boolean isInflow() {
|
||||
return isInflow;
|
||||
}
|
||||
|
||||
public void setInflow(boolean inflow) {
|
||||
isInflow = inflow;
|
||||
}
|
||||
|
||||
public LocalDateTime getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(LocalDateTime timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public Long getStatementId() {
|
||||
return statementId;
|
||||
}
|
||||
|
||||
public void setStatementId(Long statementId) {
|
||||
this.statementId = statementId;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package dev.mvvasilev.common.dto;
|
||||
|
||||
|
||||
import dev.mvvasilev.common.enums.ProcessedTransactionField;
|
||||
import dev.mvvasilev.common.enums.RawTransactionValueType;
|
||||
|
||||
public record ProcessedTransactionFieldDTO(
|
||||
ProcessedTransactionField field,
|
||||
RawTransactionValueType type
|
||||
) {
|
||||
}
|
|
@ -1,10 +1,7 @@
|
|||
package dev.mvvasilev.finances.enums;
|
||||
package dev.mvvasilev.common.enums;
|
||||
|
||||
import dev.mvvasilev.common.data.AbstractEnumConverter;
|
||||
import dev.mvvasilev.common.data.PersistableEnum;
|
||||
import dev.mvvasilev.finances.entity.ProcessedTransaction;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public enum ProcessedTransactionField implements PersistableEnum<String> {
|
||||
DESCRIPTION(RawTransactionValueType.STRING),
|
|
@ -1,4 +1,4 @@
|
|||
package dev.mvvasilev.finances.enums;
|
||||
package dev.mvvasilev.common.enums;
|
||||
|
||||
import dev.mvvasilev.common.data.PersistableEnum;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package dev.mvvasilev.finances.services;
|
||||
package dev.mvvasilev.common.services;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
@ -1,5 +1,13 @@
|
|||
package dev.mvvasilev.common.web;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public record APIResponseDTO<T>(T result, Collection<APIErrorDTO> errors, int statusCode, String statusText) { }
|
||||
public record APIResponseDTO<T>(
|
||||
T result,
|
||||
Collection<APIErrorDTO> errors,
|
||||
int statusCode,
|
||||
String statusText
|
||||
)
|
||||
{ }
|
||||
|
|
|
@ -24,23 +24,19 @@ ext['spring-security.version']='6.2.0'
|
|||
dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
|
||||
// implementation 'org.springframework.boot:spring-boot-starter-security'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-validation'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||
|
||||
implementation 'org.flywaydb:flyway-core'
|
||||
implementation 'org.springdoc:springdoc-openapi-starter-common:2.3.0'
|
||||
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'
|
||||
implementation 'org.apache.poi:poi:5.2.5'
|
||||
implementation 'org.apache.poi:poi-ooxml:5.2.5'
|
||||
implementation 'org.apache.commons:commons-lang3:3.14.0'
|
||||
|
||||
implementation project(":pefi-common")
|
||||
|
||||
runtimeOnly 'com.h2database:h2'
|
||||
runtimeOnly 'org.postgresql:postgresql'
|
||||
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
testImplementation 'org.springframework.security:spring-security-test'
|
||||
testImplementation platform('org.junit:junit-bom:5.9.1')
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
testImplementation 'org.mockito:mockito-core:5.7.0'
|
||||
}
|
||||
|
||||
dependencyManagement {
|
1
pefi-core-api/settings.gradle
Normal file
1
pefi-core-api/settings.gradle
Normal file
|
@ -0,0 +1 @@
|
|||
rootProject.name = 'pefi-core-api'
|
|
@ -1,17 +1,18 @@
|
|||
package dev.mvvasilev.finances;
|
||||
|
||||
import dev.mvvasilev.common.services.AuthorizationService;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
|
||||
@SpringBootApplication
|
||||
@SpringBootApplication(scanBasePackageClasses = { AuthorizationService.class })
|
||||
@EnableJpaRepositories("dev.mvvasilev.finances.*")
|
||||
@EntityScan("dev.mvvasilev.finances.*")
|
||||
public class PersonalFinancesServiceApplication {
|
||||
public class PefiCoreAPI {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(PersonalFinancesServiceApplication.class, args);
|
||||
SpringApplication.run(PefiCoreAPI.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package dev.mvvasilev.finances.configuration;
|
||||
|
||||
import dev.mvvasilev.common.configuration.CommonControllerConfiguration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
@Import(CommonControllerConfiguration.class)
|
||||
public class ControllerConfiguration {
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package dev.mvvasilev.finances.configuration;
|
||||
|
||||
import dev.mvvasilev.common.configuration.CommonSecurityConfiguration;
|
||||
import dev.mvvasilev.common.configuration.CommonSwaggerConfiguration;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
import org.springframework.web.filter.CommonsRequestLoggingFilter;
|
||||
|
||||
@Configuration
|
||||
@Import(CommonSwaggerConfiguration.class)
|
||||
@EnableTransactionManagement
|
||||
public class SecurityConfiguration {
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package dev.mvvasilev.finances.configuration;
|
||||
|
||||
import dev.mvvasilev.common.configuration.CommonSwaggerConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
@Configuration
|
||||
@Import(CommonSwaggerConfiguration.class)
|
||||
public class SwaggerConfiguration {
|
||||
|
||||
}
|
|
@ -35,16 +35,6 @@ public class CategoriesController extends AbstractRestController {
|
|||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
@GetMapping("/rules")
|
||||
public ResponseEntity<APIResponseDTO<Collection<CategorizationRuleDTO>>> fetchCategorizationRules() {
|
||||
return ok(
|
||||
Arrays.stream(CategorizationRule.values()).map(r -> new CategorizationRuleDTO(
|
||||
r,
|
||||
r.applicableForType()
|
||||
)).toList()
|
||||
);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<APIResponseDTO<CrudResponseDTO>> createCategory(
|
||||
@RequestBody CreateCategoryDTO dto,
|
|
@ -0,0 +1,40 @@
|
|||
package dev.mvvasilev.finances.controllers;
|
||||
|
||||
import dev.mvvasilev.common.controller.AbstractRestController;
|
||||
import dev.mvvasilev.common.enums.ProcessedTransactionField;
|
||||
import dev.mvvasilev.common.web.APIResponseDTO;
|
||||
import dev.mvvasilev.finances.dtos.CategorizationRuleDTO;
|
||||
import dev.mvvasilev.finances.dtos.ProcessedTransactionFieldDTO;
|
||||
import dev.mvvasilev.finances.enums.CategorizationRule;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/enums")
|
||||
public class EnumsController extends AbstractRestController {
|
||||
|
||||
@GetMapping("/category-rules")
|
||||
public ResponseEntity<APIResponseDTO<Collection<CategorizationRuleDTO>>> fetchCategorizationRules() {
|
||||
return ok(
|
||||
Arrays.stream(CategorizationRule.values()).map(r -> new CategorizationRuleDTO(
|
||||
r,
|
||||
r.applicableForType()
|
||||
)).toList()
|
||||
);
|
||||
}
|
||||
|
||||
@GetMapping("/processed-transaction-fields")
|
||||
public ResponseEntity<APIResponseDTO<Collection<ProcessedTransactionFieldDTO>>> fetchFields() {
|
||||
return ok(
|
||||
Arrays.stream(ProcessedTransactionField.values())
|
||||
.map(field -> new ProcessedTransactionFieldDTO(field, field.type()))
|
||||
.toList()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,26 +3,17 @@ package dev.mvvasilev.finances.controllers;
|
|||
import dev.mvvasilev.common.controller.AbstractRestController;
|
||||
import dev.mvvasilev.common.web.APIResponseDTO;
|
||||
import dev.mvvasilev.finances.dtos.ProcessedTransactionDTO;
|
||||
import dev.mvvasilev.finances.dtos.ProcessedTransactionFieldDTO;
|
||||
import dev.mvvasilev.finances.enums.ProcessedTransactionField;
|
||||
import dev.mvvasilev.finances.services.ProcessedTransactionService;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/processed-transactions")
|
||||
public class ProcessedTransactionsController extends AbstractRestController {
|
||||
|
@ -34,15 +25,6 @@ public class ProcessedTransactionsController extends AbstractRestController {
|
|||
this.processedTransactionService = processedTransactionService;
|
||||
}
|
||||
|
||||
@GetMapping("/fields")
|
||||
public ResponseEntity<APIResponseDTO<Collection<ProcessedTransactionFieldDTO>>> fetchFields() {
|
||||
return ok(
|
||||
Arrays.stream(ProcessedTransactionField.values())
|
||||
.map(field -> new ProcessedTransactionFieldDTO(field, field.type()))
|
||||
.toList()
|
||||
);
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<APIResponseDTO<Page<ProcessedTransactionDTO>>> fetchProcessedTransactions(
|
||||
Authentication authentication,
|
|
@ -1,7 +1,7 @@
|
|||
package dev.mvvasilev.finances.dtos;
|
||||
|
||||
import dev.mvvasilev.common.enums.RawTransactionValueType;
|
||||
import dev.mvvasilev.finances.enums.CategorizationRule;
|
||||
import dev.mvvasilev.finances.enums.RawTransactionValueType;
|
||||
|
||||
public record CategorizationRuleDTO(
|
||||
CategorizationRule rule,
|
|
@ -1,8 +1,6 @@
|
|||
package dev.mvvasilev.finances.dtos;
|
||||
|
||||
import dev.mvvasilev.finances.enums.CategorizationRule;
|
||||
import dev.mvvasilev.finances.enums.ProcessedTransactionField;
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import org.hibernate.validator.constraints.Length;
|
|
@ -1,7 +1,7 @@
|
|||
package dev.mvvasilev.finances.dtos;
|
||||
|
||||
import dev.mvvasilev.finances.enums.ProcessedTransactionField;
|
||||
import dev.mvvasilev.finances.enums.RawTransactionValueType;
|
||||
import dev.mvvasilev.common.enums.ProcessedTransactionField;
|
||||
import dev.mvvasilev.common.enums.RawTransactionValueType;
|
||||
|
||||
public record ProcessedTransactionFieldDTO(
|
||||
ProcessedTransactionField field,
|
|
@ -3,7 +3,6 @@ package dev.mvvasilev.finances.entity;
|
|||
import dev.mvvasilev.common.data.AbstractEntity;
|
||||
import dev.mvvasilev.common.data.UserOwned;
|
||||
import dev.mvvasilev.finances.enums.CategorizationRule;
|
||||
import dev.mvvasilev.finances.enums.ProcessedTransactionField;
|
||||
import jakarta.persistence.Convert;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
|
@ -2,29 +2,15 @@ package dev.mvvasilev.finances.entity;
|
|||
|
||||
import dev.mvvasilev.common.data.AbstractEntity;
|
||||
import dev.mvvasilev.common.data.UserOwned;
|
||||
import dev.mvvasilev.finances.enums.ProcessedTransactionField;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
@Entity
|
||||
@Table(schema = "transactions")
|
||||
public class ProcessedTransaction extends AbstractEntity implements UserOwned {
|
||||
|
||||
// This const is a result of the limitations of the JVM.
|
||||
// It is impossible to refer to either a field, or method of a class statically.
|
||||
// Because of this, it is very difficult to tie the ProcessedTransactionField values to the actual class fields they represent.
|
||||
// To resolve this imperfection, this const lives here, in plain view, so when one of the fields is changed,
|
||||
// hopefully the programmer remembers to change the value inside as well.
|
||||
public static final Map<ProcessedTransactionField, String> FIELD_NAMES = Map.of(
|
||||
ProcessedTransactionField.DESCRIPTION, "description",
|
||||
ProcessedTransactionField.AMOUNT, "amount",
|
||||
ProcessedTransactionField.IS_INFLOW, "isInflow",
|
||||
ProcessedTransactionField.TIMESTAMP, "timestamp"
|
||||
);
|
||||
|
||||
private String description;
|
||||
|
||||
private Integer userId;
|
|
@ -2,6 +2,7 @@ package dev.mvvasilev.finances.enums;
|
|||
|
||||
import dev.mvvasilev.common.data.AbstractEnumConverter;
|
||||
import dev.mvvasilev.common.data.PersistableEnum;
|
||||
import dev.mvvasilev.common.enums.RawTransactionValueType;
|
||||
|
||||
// TODO: Create custom converter for JPA
|
||||
public enum CategorizationRule implements PersistableEnum<String> {
|
|
@ -9,7 +9,6 @@ import dev.mvvasilev.finances.persistence.CategorizationRepository;
|
|||
import dev.mvvasilev.finances.persistence.ProcessedTransactionCategoryRepository;
|
||||
import dev.mvvasilev.finances.persistence.ProcessedTransactionRepository;
|
||||
import dev.mvvasilev.finances.persistence.TransactionCategoryRepository;
|
||||
import org.apache.commons.compress.utils.Lists;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
|
@ -5,7 +5,6 @@ import dev.mvvasilev.finances.dtos.TransactionCategoryDTO;
|
|||
import dev.mvvasilev.finances.entity.ProcessedTransaction;
|
||||
import dev.mvvasilev.finances.persistence.ProcessedTransactionRepository;
|
||||
import dev.mvvasilev.finances.persistence.TransactionCategoryRepository;
|
||||
import org.apache.commons.compress.utils.Lists;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.*;
|
||||
import org.springframework.stereotype.Service;
|
|
@ -2,7 +2,6 @@ package dev.mvvasilev.finances;
|
|||
|
||||
import dev.mvvasilev.finances.entity.Categorization;
|
||||
import dev.mvvasilev.finances.enums.CategorizationRule;
|
||||
import dev.mvvasilev.finances.enums.ProcessedTransactionField;
|
||||
import org.apache.commons.lang3.RandomUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
|
@ -1 +0,0 @@
|
|||
rootProject.name = 'pefi-monolith'
|
|
@ -1,43 +0,0 @@
|
|||
package dev.mvvasilev.finances.advice;
|
||||
|
||||
import dev.mvvasilev.common.web.APIErrorDTO;
|
||||
import dev.mvvasilev.common.web.APIResponseDTO;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestControllerAdvice(basePackages = {"dev.mvvasilev"})
|
||||
public class APIResponseAdvice {
|
||||
|
||||
@Value("${debug}")
|
||||
private boolean isDebug;
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseEntity<APIResponseDTO<Object>> processGenericException(Exception ex) {
|
||||
List<APIErrorDTO> errors = List.of(
|
||||
new APIErrorDTO(
|
||||
ex.getMessage(),
|
||||
isDebug ? ex.getClass().getCanonicalName() : null,
|
||||
isDebug ? ExceptionUtils.getStackTrace(ex) : null
|
||||
)
|
||||
);
|
||||
|
||||
logger.error("Exception", ex);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body(new APIResponseDTO<>(
|
||||
null,
|
||||
errors,
|
||||
HttpStatus.INTERNAL_SERVER_ERROR.value(),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase()
|
||||
));
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
package dev.mvvasilev.finances.persistence.dtos;
|
||||
|
||||
public interface RawTransactionDTO {
|
||||
}
|
7
pefi-statements-api/.env.example
Normal file
7
pefi-statements-api/.env.example
Normal file
|
@ -0,0 +1,7 @@
|
|||
PROFILE= production/development
|
||||
|
||||
AUTHENTIK_ISSUER_URL= auth server configuration url for fetching JWKs ( dev: https://auth.mvvasilev.dev/application/o/personal-finances/ )
|
||||
|
||||
DATASOURCE_URL= database jdbc url ( postgres only, example: jdbc:postgresql://localhost:5432/mydatabase )
|
||||
DATASOURCE_USER= database user
|
||||
DATASOURCE_PASSWORD= database password
|
0
pefi-statements-api/Dockerfile
Normal file
0
pefi-statements-api/Dockerfile
Normal file
36
pefi-statements-api/build.gradle
Normal file
36
pefi-statements-api/build.gradle
Normal file
|
@ -0,0 +1,36 @@
|
|||
plugins {
|
||||
id 'java'
|
||||
id 'org.springframework.boot' version '3.2.0'
|
||||
id 'io.spring.dependency-management' version '1.1.3'
|
||||
}
|
||||
|
||||
group = 'dev.mvvasilev.statements'
|
||||
version = '0.0.1-SNAPSHOT'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-validation'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||
|
||||
implementation 'org.flywaydb:flyway-core'
|
||||
implementation 'org.springdoc:springdoc-openapi-starter-common:2.3.0'
|
||||
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'
|
||||
implementation 'org.apache.poi:poi:5.2.5'
|
||||
implementation 'org.apache.poi:poi-ooxml:5.2.5'
|
||||
|
||||
implementation project(":pefi-common")
|
||||
|
||||
runtimeOnly 'org.postgresql:postgresql'
|
||||
|
||||
testImplementation platform('org.junit:junit-bom:5.9.1')
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
1
pefi-statements-api/settings.gradle
Normal file
1
pefi-statements-api/settings.gradle
Normal file
|
@ -0,0 +1 @@
|
|||
rootProject.name = 'pefi-statements-api'
|
|
@ -0,0 +1,16 @@
|
|||
package dev.mvvasilev.statements;
|
||||
|
||||
import dev.mvvasilev.common.services.AuthorizationService;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
|
||||
@SpringBootApplication(scanBasePackageClasses = { AuthorizationService.class })
|
||||
@EnableJpaRepositories("dev.mvvasilev.statements.*")
|
||||
@EntityScan("dev.mvvasilev.statements.*")
|
||||
public class PefiStatementsAPI {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(PefiStatementsAPI.class, args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package dev.mvvasilev.statements.configuration;
|
||||
|
||||
import dev.mvvasilev.common.configuration.CommonControllerConfiguration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
@Import(CommonControllerConfiguration.class)
|
||||
public class ControllerConfiguration {
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package dev.mvvasilev.statements.configuration;
|
||||
|
||||
import dev.mvvasilev.common.configuration.CommonSwaggerConfiguration;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
@Configuration
|
||||
@Import(CommonSwaggerConfiguration.class)
|
||||
@EnableTransactionManagement
|
||||
public class SecurityConfiguration {
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package dev.mvvasilev.statements.configuration;
|
||||
|
||||
import dev.mvvasilev.common.configuration.CommonSwaggerConfiguration;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
@Configuration
|
||||
@Import(CommonSwaggerConfiguration.class)
|
||||
public class SwaggerConfiguration {
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package dev.mvvasilev.statements.controllers;
|
||||
|
||||
import dev.mvvasilev.common.controller.AbstractRestController;
|
||||
import dev.mvvasilev.common.web.APIResponseDTO;
|
||||
import dev.mvvasilev.statements.dto.SupportedMappingConversionDTO;
|
||||
import dev.mvvasilev.statements.enums.MappingConversionType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/enums")
|
||||
public class EnumsController extends AbstractRestController {
|
||||
|
||||
@GetMapping("/supported-conversions")
|
||||
public ResponseEntity<APIResponseDTO<Collection<SupportedMappingConversionDTO>>> fetchTransactionMappings() {
|
||||
return ok(Arrays.stream(MappingConversionType.values()).map(conv -> new SupportedMappingConversionDTO(
|
||||
conv,
|
||||
conv.getFrom(),
|
||||
conv.getTo()
|
||||
)).toList());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,11 +1,13 @@
|
|||
package dev.mvvasilev.finances.controllers;
|
||||
package dev.mvvasilev.statements.controllers;
|
||||
|
||||
import dev.mvvasilev.common.controller.AbstractRestController;
|
||||
import dev.mvvasilev.common.web.APIResponseDTO;
|
||||
import dev.mvvasilev.common.web.CrudResponseDTO;
|
||||
import dev.mvvasilev.finances.dtos.*;
|
||||
import dev.mvvasilev.finances.enums.MappingConversionType;
|
||||
import dev.mvvasilev.finances.services.StatementsService;
|
||||
import dev.mvvasilev.statements.dto.CreateTransactionMappingDTO;
|
||||
import dev.mvvasilev.statements.dto.TransactionMappingDTO;
|
||||
import dev.mvvasilev.statements.dto.TransactionValueGroupDTO;
|
||||
import dev.mvvasilev.statements.dto.UploadedStatementDTO;
|
||||
import dev.mvvasilev.statements.service.StatementsService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
@ -15,7 +17,6 @@ import org.springframework.web.bind.annotation.*;
|
|||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
@RestController
|
||||
|
@ -50,15 +51,6 @@ public class StatementsController extends AbstractRestController {
|
|||
return ok(statementsService.fetchMappingsForStatement(statementId));
|
||||
}
|
||||
|
||||
@GetMapping("/supported-conversions")
|
||||
public ResponseEntity<APIResponseDTO<Collection<SupportedMappingConversionDTO>>> fetchTransactionMappings() {
|
||||
return ok(Arrays.stream(MappingConversionType.values()).map(conv -> new SupportedMappingConversionDTO(
|
||||
conv,
|
||||
conv.getFrom(),
|
||||
conv.getTo()
|
||||
)).toList());
|
||||
}
|
||||
|
||||
@PostMapping("/{statementId}/mappings")
|
||||
@PreAuthorize("@authService.isOwner(#statementId, T(dev.mvvasilev.finances.entity.RawStatement))")
|
||||
public ResponseEntity<APIResponseDTO<Collection<CrudResponseDTO>>> createTransactionMappings(
|
|
@ -1,7 +1,7 @@
|
|||
package dev.mvvasilev.finances.dtos;
|
||||
package dev.mvvasilev.statements.dto;
|
||||
|
||||
import dev.mvvasilev.finances.enums.MappingConversionType;
|
||||
import dev.mvvasilev.finances.enums.ProcessedTransactionField;
|
||||
import dev.mvvasilev.common.enums.ProcessedTransactionField;
|
||||
import dev.mvvasilev.statements.enums.MappingConversionType;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
package dev.mvvasilev.finances.dtos;
|
||||
package dev.mvvasilev.statements.dto;
|
||||
|
||||
import dev.mvvasilev.finances.enums.MappingConversionType;
|
||||
import dev.mvvasilev.finances.enums.RawTransactionValueType;
|
||||
|
||||
import dev.mvvasilev.common.enums.RawTransactionValueType;
|
||||
import dev.mvvasilev.statements.enums.MappingConversionType;
|
||||
|
||||
public record SupportedMappingConversionDTO(
|
||||
MappingConversionType type,
|
|
@ -1,7 +1,6 @@
|
|||
package dev.mvvasilev.finances.dtos;
|
||||
package dev.mvvasilev.statements.dto;
|
||||
|
||||
import dev.mvvasilev.finances.enums.MappingConversionType;
|
||||
import dev.mvvasilev.finances.enums.ProcessedTransactionField;
|
||||
import dev.mvvasilev.common.dto.ProcessedTransactionFieldDTO;
|
||||
|
||||
public record TransactionMappingDTO(
|
||||
Long id,
|
|
@ -1,6 +1,7 @@
|
|||
package dev.mvvasilev.finances.dtos;
|
||||
package dev.mvvasilev.statements.dto;
|
||||
|
||||
import dev.mvvasilev.finances.enums.RawTransactionValueType;
|
||||
|
||||
import dev.mvvasilev.common.enums.RawTransactionValueType;
|
||||
|
||||
public record TransactionValueGroupDTO(
|
||||
Long id,
|
|
@ -1,4 +1,4 @@
|
|||
package dev.mvvasilev.finances.dtos;
|
||||
package dev.mvvasilev.statements.dto;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package dev.mvvasilev.finances.entity;
|
||||
package dev.mvvasilev.statements.entity;
|
||||
|
||||
import dev.mvvasilev.common.data.AbstractEntity;
|
||||
import dev.mvvasilev.common.data.UserOwned;
|
|
@ -1,11 +1,10 @@
|
|||
package dev.mvvasilev.finances.entity;
|
||||
package dev.mvvasilev.statements.entity;
|
||||
|
||||
import dev.mvvasilev.common.data.AbstractEntity;
|
||||
import dev.mvvasilev.finances.enums.ProcessedTransactionField;
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
@Entity
|
||||
@Table(schema = "transactions")
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue