Compare commits
28
Commits
68bc14198e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b08fbf3b03 | ||
|
|
51382d0bd1 | ||
|
|
a55270f6d5 | ||
|
|
7f6fd4259b | ||
|
|
46a86f15d8 | ||
|
|
78b6e04db6 | ||
|
|
3fed8a4ea2 | ||
|
|
5b0c2d6d02 | ||
|
|
ee2685aa07 | ||
|
|
12fc7909fd | ||
|
|
9bbf2fd098 | ||
|
|
9c2cbd1608 | ||
|
|
fffdd2a575 | ||
|
|
8c18d7ff73 | ||
|
|
4318fc13f6 | ||
|
|
a2e110d3dd | ||
|
|
adb51584e7 | ||
|
|
048120688f | ||
|
|
b356682175 | ||
|
|
bdbfece62c | ||
|
|
597c941994 | ||
|
|
8183bf61ea | ||
|
|
5838084b73 | ||
|
|
77ee6f68c6 | ||
|
|
5c58fe43d9 | ||
|
|
7652645f42 | ||
|
|
2ea346651f | ||
|
|
6b5a3b5687 |
@@ -0,0 +1,61 @@
|
|||||||
|
name: SonarQube Analysis
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Build and Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:18.4
|
||||||
|
env:
|
||||||
|
POSTGRES_USER: vaessl
|
||||||
|
POSTGRES_PASSWORD: vaessl
|
||||||
|
POSTGRES_DB: vaessl_test
|
||||||
|
options: >-
|
||||||
|
--health-cmd pg_isready
|
||||||
|
--health-interval 10s
|
||||||
|
--health-timeout 5s
|
||||||
|
--health-retries 5
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
||||||
|
|
||||||
|
- name: Set up JDK 25
|
||||||
|
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0
|
||||||
|
with:
|
||||||
|
java-version: "25"
|
||||||
|
distribution: "zulu" # Alternative distribution options are available.
|
||||||
|
|
||||||
|
- name: Make Gradle Executable
|
||||||
|
run: chmod +x ./gradlew
|
||||||
|
working-directory: backend
|
||||||
|
|
||||||
|
- name: Build and Analyze
|
||||||
|
env:
|
||||||
|
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||||
|
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
|
||||||
|
|
||||||
|
DB_URL: jdbc:postgresql://postgres:5432/vaessl_test
|
||||||
|
DB_TEST_URL: jdbc:postgresql://postgres:5432/vaessl_test
|
||||||
|
DB_USERNAME: vaessl
|
||||||
|
DB_PASSWORD: vaessl
|
||||||
|
PG_DRIVER_CLASS_NAME: org.postgresql.Driver
|
||||||
|
|
||||||
|
OPENAI_BASE_URL: https://api.openai.com/v1
|
||||||
|
OPENAI_KEY: ${{ secrets.OPENAI_KEY }}
|
||||||
|
ALLOWED_ORIGINS: http://localhost:3000
|
||||||
|
run: ./gradlew build sonar --info
|
||||||
|
working-directory: backend
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
|
val wiremockVersion = "3.12.0"
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
java
|
java
|
||||||
|
jacoco
|
||||||
id("org.springframework.boot") version "4.1.0"
|
id("org.springframework.boot") version "4.1.0"
|
||||||
id("io.spring.dependency-management") version "1.1.7"
|
id("io.spring.dependency-management") version "1.1.7"
|
||||||
|
id("org.sonarqube") version "7.3.0.8198"
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "com.vaessl"
|
group = "com.vaessl"
|
||||||
@@ -13,6 +17,15 @@ java {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sonar {
|
||||||
|
properties {
|
||||||
|
property("sonar.projectKey", "Vaessl")
|
||||||
|
property("sonar.projectName", "Vaessl")
|
||||||
|
property("sonar.coverage.jacoco.xmlReportPaths",
|
||||||
|
"${layout.buildDirectory.get()}/reports/jacoco/test/jacocoTestReport.xml")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
compileOnly {
|
compileOnly {
|
||||||
extendsFrom(configurations.annotationProcessor.get())
|
extendsFrom(configurations.annotationProcessor.get())
|
||||||
@@ -25,6 +38,7 @@ repositories {
|
|||||||
|
|
||||||
extra["springAiVersion"] = "2.0.0"
|
extra["springAiVersion"] = "2.0.0"
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||||
implementation("org.springframework.boot:spring-boot-starter-session-jdbc")
|
implementation("org.springframework.boot:spring-boot-starter-session-jdbc")
|
||||||
@@ -32,17 +46,24 @@ dependencies {
|
|||||||
implementation("org.springframework.boot:spring-boot-starter-validation")
|
implementation("org.springframework.boot:spring-boot-starter-validation")
|
||||||
implementation("org.springframework.boot:spring-boot-starter-webmvc")
|
implementation("org.springframework.boot:spring-boot-starter-webmvc")
|
||||||
implementation("org.springframework.ai:spring-ai-starter-model-openai")
|
implementation("org.springframework.ai:spring-ai-starter-model-openai")
|
||||||
|
|
||||||
compileOnly("org.projectlombok:lombok")
|
compileOnly("org.projectlombok:lombok")
|
||||||
|
|
||||||
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
||||||
|
|
||||||
runtimeOnly("org.postgresql:postgresql")
|
runtimeOnly("org.postgresql:postgresql")
|
||||||
|
|
||||||
annotationProcessor("org.projectlombok:lombok")
|
annotationProcessor("org.projectlombok:lombok")
|
||||||
|
|
||||||
testImplementation("org.springframework.boot:spring-boot-starter-data-jpa-test")
|
testImplementation("org.springframework.boot:spring-boot-starter-data-jpa-test")
|
||||||
// testImplementation("org.springframework.boot:spring-boot-starter-security-test")
|
// testImplementation("org.springframework.boot:spring-boot-starter-security-test")
|
||||||
testImplementation("org.springframework.boot:spring-boot-starter-validation-test")
|
testImplementation("org.springframework.boot:spring-boot-starter-validation-test")
|
||||||
testImplementation("org.springframework.boot:spring-boot-starter-webmvc-test")
|
testImplementation("org.springframework.boot:spring-boot-starter-webmvc-test")
|
||||||
|
testImplementation("org.wiremock:wiremock-standalone:$wiremockVersion")
|
||||||
|
testImplementation("org.springframework.boot:spring-boot-starter-session-jdbc-test")
|
||||||
|
|
||||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||||
testImplementation("org.wiremock:wiremock-standalone:3.12.0")
|
}
|
||||||
testImplementation("org.springframework.boot:spring-boot-starter-session-jdbc-test")}
|
|
||||||
|
|
||||||
dependencyManagement {
|
dependencyManagement {
|
||||||
imports {
|
imports {
|
||||||
@@ -55,5 +76,20 @@ tasks.withType<JavaCompile> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<Test> {
|
tasks.withType<Test> {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
|
finalizedBy(tasks.jacocoTestReport)
|
||||||
|
testLogging {
|
||||||
|
events("failed", "standardError")
|
||||||
|
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
|
||||||
|
showExceptions = true
|
||||||
|
showCauses = true
|
||||||
|
showStackTraces = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.jacocoTestReport {
|
||||||
|
dependsOn(tasks.withType<Test>())
|
||||||
|
reports {
|
||||||
|
xml.required = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package com.vaessl.app.connection;
|
package com.vaessl.app.connection;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.EnumMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@@ -18,8 +18,11 @@ public class ConnectionService {
|
|||||||
private final ConnectionRepository cRepository;
|
private final ConnectionRepository cRepository;
|
||||||
|
|
||||||
public ConnectionService(List<ConnectionProvider> providers, ConnectionRepository cRepository) {
|
public ConnectionService(List<ConnectionProvider> providers, ConnectionRepository cRepository) {
|
||||||
this.providerRegistry = providers.stream()
|
Map<ServiceType, ConnectionProvider> registry = new EnumMap<>(ServiceType.class);
|
||||||
.collect(Collectors.toMap(ConnectionProvider::getServiceType, p -> p));
|
for (ConnectionProvider provider : providers) {
|
||||||
|
registry.put(provider.getServiceType(), provider);
|
||||||
|
}
|
||||||
|
this.providerRegistry = registry;
|
||||||
this.cRepository = cRepository;
|
this.cRepository = cRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +52,8 @@ public class ConnectionService {
|
|||||||
return new LoginResult(saved.getId(), response.expiresAt());
|
return new LoginResult(saved.getId(), response.expiresAt());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConnectionStatusResponse getConnectionStatus(ServiceType serviceType, Long connectionId) {
|
public ConnectionStatusResponse getConnectionStatus(ServiceType serviceType,
|
||||||
|
Long connectionId) {
|
||||||
ConnectionEntity entity = cRepository.findById(connectionId).orElse(null);
|
ConnectionEntity entity = cRepository.findById(connectionId).orElse(null);
|
||||||
if (entity == null)
|
if (entity == null)
|
||||||
return null;
|
return null;
|
||||||
@@ -58,7 +62,7 @@ public class ConnectionService {
|
|||||||
Instant expiresAt = (provider != null) ? provider.getTokenExpiry(entity) : null;
|
Instant expiresAt = (provider != null) ? provider.getTokenExpiry(entity) : null;
|
||||||
boolean connected = expiresAt == null || expiresAt.isAfter(Instant.now());
|
boolean connected = expiresAt == null || expiresAt.isAfter(Instant.now());
|
||||||
|
|
||||||
return new ConnectionStatusResponse(serviceType.name(), entity.getAppUrl(), entity.getUsername(),
|
return new ConnectionStatusResponse(serviceType.name(), entity.getAppUrl(),
|
||||||
expiresAt, connected);
|
entity.getUsername(), expiresAt, connected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.vaessl.app.exception;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.ProblemDetail;
|
import org.springframework.http.ProblemDetail;
|
||||||
import org.springframework.validation.FieldError;
|
|
||||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
@@ -24,7 +23,7 @@ public class GlobalExceptionHandler {
|
|||||||
public ProblemDetail handleEmptyCredentialInput(MethodArgumentNotValidException e) {
|
public ProblemDetail handleEmptyCredentialInput(MethodArgumentNotValidException e) {
|
||||||
|
|
||||||
String defaultMessages = e.getBindingResult().getFieldErrors().stream()
|
String defaultMessages = e.getBindingResult().getFieldErrors().stream()
|
||||||
.map(FieldError::getDefaultMessage).collect(Collectors.joining(", "));
|
.map(field -> field.getDefaultMessage()).collect(Collectors.joining(", "));
|
||||||
|
|
||||||
return ProblemDetail.forStatusAndDetail(BAD_REQUEST_EMPTY_FIELDS.getStatus(),
|
return ProblemDetail.forStatusAndDetail(BAD_REQUEST_EMPTY_FIELDS.getStatus(),
|
||||||
BAD_REQUEST_EMPTY_FIELDS.getMessage() + " [" + defaultMessages + "]");
|
BAD_REQUEST_EMPTY_FIELDS.getMessage() + " [" + defaultMessages + "]");
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ public interface SearchProvider extends ServiceProvider {
|
|||||||
* Executes a search query against the remote service and returns matching results.
|
* Executes a search query against the remote service and returns matching results.
|
||||||
*
|
*
|
||||||
* @param request the search request containing the query string, app URL, and user credentials
|
* @param request the search request containing the query string, app URL, and user credentials
|
||||||
|
* @param pageable the Pageable interface
|
||||||
* @return a list of Page<SearchResponse> items matching the query
|
* @return a list of Page<SearchResponse> items matching the query
|
||||||
*/
|
*/
|
||||||
Page<SearchResponse> getSearchResults(SearchRequest request, Pageable pageable);
|
Page<SearchResponse> getSearchResults(SearchRequest request, Pageable pageable);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.vaessl.app.search;
|
package com.vaessl.app.search;
|
||||||
|
|
||||||
|
import java.util.EnumMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
@@ -16,8 +16,12 @@ public class SearchService {
|
|||||||
private final Map<ServiceType, SearchProvider> providerRegistry;
|
private final Map<ServiceType, SearchProvider> providerRegistry;
|
||||||
|
|
||||||
public SearchService(List<SearchProvider> providers) {
|
public SearchService(List<SearchProvider> providers) {
|
||||||
this.providerRegistry = Map.copyOf(providers.stream()
|
Map<ServiceType, SearchProvider> registry = new EnumMap<>(ServiceType.class);
|
||||||
.collect(Collectors.toMap(SearchProvider::getServiceType, p -> p)));
|
for (SearchProvider provider : providers) {
|
||||||
|
registry.put(provider.getServiceType(), provider);
|
||||||
|
}
|
||||||
|
this.providerRegistry = registry;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user