Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ hs_err_pid*
build/
.gradle/
out/
src/test/resources/db/migration/*.sql
6 changes: 6 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ dependencies {

// JasperReport's export to XLS uses Apache POI and openpdf for PDF export
implementation(libs.apache.poi)
implementation(libs.apache.poi.ooxml)
implementation(libs.apache.commons.commonscsv)
implementation(libs.openpdf)
implementation(libs.jakarta.inject.api)
implementation(libs.jakarta.mail)
Expand All @@ -125,6 +127,10 @@ dependencies {
compileOnly(libs.lombok)
annotationProcessor(libs.lombok)

//mapstruct
implementation(libs.mapstruct)
annotationProcessor(libs.mapstruct.processor)

// Tests
testImplementation(libs.bundles.test.libs)
testCompileOnly(libs.lombok)
Expand Down
10 changes: 8 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ springdoc-openapi = "2.8.14"
tika = "3.2.3"
thumbnailator = "0.4.21"
xerces = "2.12.2"

mapstruct = "1.5.5.Final"
apache-commons-csv = "1.10.0"

[libraries]
# Development libs
Expand Down Expand Up @@ -85,6 +86,7 @@ rabbitmq-http-client = { group = "com.rabbitmq", name = "http-client", version.r
httpclient5 = { group = "org.apache.httpcomponents.client5", name = "httpclient5", version.ref = "httpclient5" }
jasperreports = { group = "net.sf.jasperreports", name = "jasperreports", version.ref = "jasperreports" }
apache-poi = { group = "org.apache.poi", name = "poi", version.ref = "apache-poi" }
apache-poi-ooxml = { group = "org.apache.poi", name = "poi-ooxml", version.ref = "apache-poi" }
openpdf = { group = "com.github.librepdf", name = "openpdf", version.ref = "openpdf" }
jakarta-inject-api = { group = "jakarta.inject", name = "jakarta.inject-api", version.ref = "jakarta-inject" }
jakarta-mail = { group = "com.sun.mail", name = "jakarta.mail", version.ref = "jakarta-mail" }
Expand Down Expand Up @@ -123,11 +125,15 @@ spring-security-core = { group = "org.springframework.security", name = "spring-
spring-data-commons = { group = "org.springframework.data", name = "spring-data-commons" }
hibernate-core = { group = "org.hibernate.orm", name = "hibernate-core" }
jakarta-validation = { group = "jakarta.validation", name = "jakarta.validation-api" }

apache-commons-commonscsv = { group = "org.apache.commons", name = "commons-csv", version.ref = "apache-commons-csv" }

# Lombok
lombok = { group = "org.projectlombok", name = "lombok", version.ref = "lombok" }

# Mapstruct
mapstruct = { group = "org.mapstruct", name = "mapstruct", version.ref = "mapstruct" }
mapstruct-processor = { group = "org.mapstruct", name = "mapstruct-processor", version.ref = "mapstruct" }

# Test libraries
spring-test = { group = "org.springframework", name = "spring-test" }
flyway-spring-test = { group = "org.flywaydb.flyway-test-extensions", name = "flyway-spring-test", version.ref = "flyway-spring-test" }
Expand Down
3 changes: 2 additions & 1 deletion project-properties.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ project.ext {
isDebugMode = System.getProperty("DEBUG", "false") == "true"
releaseMode = project.hasProperty("releaseMode") ? project.releaseMode.toBoolean() : false
scriptsUrl = commonScriptsUrl + (releaseMode ? '5.14.0' : 'develop')
migrationsUrl = migrationsScriptsUrl + (releaseMode ? '5.14.0' : 'develop')
migrationsUrl = migrationsScriptsUrl + (releaseMode ? '5.14.0' : 'feature/EPMRPP-migrate-tms-to-develop')
manifestSchemaUrl = schemaUrl + ('manifest.schema.json')
//TODO refactor with archive download
testScriptsSrc = [
Expand Down Expand Up @@ -92,6 +92,7 @@ project.ext {
(migrationsUrl + '/migrations/209_add_activity_org_id.up.sql') : 'V209__add_activity_org_id.sql',
(migrationsUrl + '/migrations/210_organization_settings_table.up.sql') : 'V210__organization_settings_table.sql',
(migrationsUrl + '/migrations/212_update_default_users.up.sql') : 'V212__update_default_users.sql',
(migrationsUrl + '/migrations/1000_tms_initial.up.sql') : 'V1000__tms_initial.up.sql',
]
excludeTests = ['**/entity/**',
'**/aop/**',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import com.epam.reportportal.infrastructure.persistence.filesystem.DataStore;
import com.epam.reportportal.infrastructure.persistence.filesystem.LocalDataStore;
import com.epam.reportportal.infrastructure.persistence.filesystem.distributed.s3.S3DataStore;
import com.epam.reportportal.infrastructure.persistence.filesystem.tms.LocalTmsDataStore;
import com.epam.reportportal.infrastructure.persistence.filesystem.tms.TmsDataStore;
import com.epam.reportportal.infrastructure.persistence.util.FeatureFlagHandler;
import com.google.common.base.Optional;
import com.google.common.base.Supplier;
Expand All @@ -42,10 +44,12 @@
import org.jclouds.rest.ConfiguresHttpApi;
import org.jclouds.s3.S3Client;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
* @author Dzianis_Shybeka
Expand Down Expand Up @@ -137,6 +141,7 @@ public String toString() {

@Bean
@ConditionalOnProperty(name = "datastore.type", havingValue = "filesystem")
@Primary
public BlobStore filesystemBlobStore(
@Value("${datastore.path:/data/store}") String baseDirectory) {

Expand Down Expand Up @@ -171,6 +176,7 @@ public DataStore localDataStore(@Autowired BlobStore blobStore,
*/
@Bean
@ConditionalOnProperty(name = "datastore.type", havingValue = "s3-compatible")
@Primary
public BlobStore minioBlobStore(@Value("${datastore.accessKey}") String accessKey,
@Value("${datastore.secretKey}") String secretKey,
@Value("${datastore.endpoint}") String endpoint) {
Expand Down Expand Up @@ -213,6 +219,7 @@ public DataStore minioDataStore(@Autowired BlobStore blobStore,
*/
@Bean
@ConditionalOnProperty(name = "datastore.type", havingValue = "aws-s3")
@Primary
public BlobStore s3BlobStore(
@Value("${datastore.accessKey:}") String accessKey,
@Value("${datastore.secretKey:}") String secretKey,
Expand Down Expand Up @@ -247,6 +254,33 @@ public DataStore s3DataStore(@Autowired BlobStore blobStore,
);
}

@Bean
@ConditionalOnProperty(name = "rp.tms.datastore.type", havingValue = "filesystem")
public BlobStore tmsFilesystemBlobStore(
@Value("${rp.tms.datastore.path:/data/store}") String baseDirectory) {

Properties properties = new Properties();
properties.setProperty(FilesystemConstants.PROPERTY_BASEDIR, baseDirectory);

BlobStoreContext blobStoreContext =
ContextBuilder.newBuilder("filesystem").overrides(properties)
.buildView(BlobStoreContext.class);

return blobStoreContext.getBlobStore();
}

@Bean
@ConditionalOnProperty(name = "rp.tms.datastore.type", havingValue = "filesystem")
public TmsDataStore tmsLocalDataStore(
@Autowired @Qualifier("tmsFilesystemBlobStore") BlobStore tmsFilesystemBlobStore,
FeatureFlagHandler featureFlagHandler,
@Value("${rp.tms.datastore.bucketPrefix:tms-prj-}") String bucketPrefix,
@Value("${rp.tms.datastore.bucketPostfix:}") String bucketPostfix,
@Value("${rp.tms.datastore.defaultBucketName:tms-rp-bucket}") String defaultBucketName) {
return new LocalTmsDataStore(
tmsFilesystemBlobStore, featureFlagHandler, bucketPrefix, bucketPostfix, defaultBucketName);
}

@Bean("attachmentThumbnailator")
public Thumbnailator attachmentThumbnailator(
@Value("${datastore.thumbnail.attachment.width}") int width,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.epam.reportportal.ws.resolver.ActiveUserWebArgumentResolver;
import com.epam.reportportal.ws.resolver.FilterCriteriaResolver;
import com.epam.reportportal.ws.resolver.JsonViewSupportFactoryBean;
import com.epam.reportportal.ws.resolver.OffsetArgumentResolver;
import com.epam.reportportal.ws.resolver.PagingHandlerMethodArgumentResolver;
import com.epam.reportportal.ws.resolver.PredefinedFilterCriteriaResolver;
import com.epam.reportportal.ws.resolver.SortArgumentResolver;
Expand Down Expand Up @@ -97,6 +98,7 @@ public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentRes
argumentResolvers.add(new ActiveUserWebArgumentResolver());
argumentResolvers.add(new FilterCriteriaResolver());
argumentResolvers.add(new PredefinedFilterCriteriaResolver());
argumentResolvers.add(new OffsetArgumentResolver());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.epam.reportportal.core.configs;

import com.epam.reportportal.core.tms.scheduled.TmsAttachmentCleanupJob;
import com.epam.reportportal.extension.classloader.ReportPortalResourceLoader;
import com.epam.reportportal.job.CleanExpiredCreationBidsJob;
import com.epam.reportportal.job.FlushingDataJob;
Expand Down Expand Up @@ -71,6 +72,9 @@ public class SchedulerConfiguration {
@Autowired
private ReportPortalResourceLoader resourceLoader;

@Autowired
private TmsAttachmentCleanupJob tmsAttachmentCleanupJob;

@Bean
@Primary
public SchedulerFactoryBean schedulerFactoryBean() {
Expand Down Expand Up @@ -163,6 +167,18 @@ public SimpleTriggerFactoryBean createTrigger(JobDetail jobDetail, long pollFreq
return factoryBean;
}

@Bean
public SimpleTriggerFactoryBean tmsAttachmentCleanupTrigger(
@Named("tmsAttachmentCleanupJobBean") JobDetail jobDetail,
@Value("${rp.tms.attachment.cleanup.cleanup.cron}") String cleanupCron) {
return createTrigger(jobDetail, Duration.parse(cleanupCron).toMillis());
}

@Bean("tmsAttachmentCleanupJobBean")
public JobDetailFactoryBean tmsAttachmentCleanupJob() {
return createJobDetail(TmsAttachmentCleanupJob.class);
}

public SimpleTriggerFactoryBean createTriggerDelayed(JobDetail jobDetail, long pollFrequencyMs) {
SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
factoryBean.setJobDetail(jobDetail);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package com.epam.reportportal.core.tms.controller;

import com.epam.reportportal.infrastructure.persistence.commons.EntityUtils;
import com.epam.reportportal.infrastructure.persistence.commons.ReportPortalUser;
import com.epam.reportportal.core.tms.dto.ProductVersionRQ;
import com.epam.reportportal.core.tms.dto.TmsProductVersionRS;
import com.epam.reportportal.core.tms.service.ProductVersionService;
import com.epam.reportportal.util.ProjectExtractor;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
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.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* Controller for managing product versions within a project. Each endpoint
* in this controller is secured and requires the user to have administrator
* privileges. Operations supported include creating, retrieving, updating,
* and deleting product versions associated with a specific project.
*/
@RestController
@RequestMapping("/v1/project/{projectKey}/tms/productversion")
@Tag(name = "Product Version", description = "Product Version API collection")
@RequiredArgsConstructor
public class ProductVersionController {

private final ProductVersionService productVersionService;
private final ProjectExtractor projectExtractor;

/**
* Retrieves a specific product version by its ID within a project.
*
* @param projectKey The key of the project to which the product version belongs.
* @param productVersionId The ID of the product version to retrieve.
* @return A data transfer object ({@link TmsProductVersionRS}) containing details of the product version.
*/
@GetMapping("/{productVersionId}")
TmsProductVersionRS getById(@PathVariable("projectKey") String projectKey,
@PathVariable("productVersionId") final long productVersionId,
@AuthenticationPrincipal ReportPortalUser user) {
return productVersionService.getById(
projectExtractor
.extractMembershipDetails(user, EntityUtils.normalizeId(projectKey))
.getProjectId(),
productVersionId);
}

/**
* Creates a new product version in the specified project.
*
* @param projectKey The key of the project to which the new product version will be added.
* @param inputDto A request payload ({@link ProductVersionRQ}) containing information
* about the product version to create.
* @return A data transfer object ({@link TmsProductVersionRS}) with details of the created product version.
*/
@PostMapping
TmsProductVersionRS createVersion(@PathVariable("projectKey") String projectKey,
@RequestBody final ProductVersionRQ inputDto,
@AuthenticationPrincipal ReportPortalUser user) {
return productVersionService.create(
projectExtractor
.extractMembershipDetails(user, EntityUtils.normalizeId(projectKey))
.getProjectId(),
inputDto);
}

/**
* Updates the details of an existing product version in a project.
*
* @param projectKey The key of the project to which the product version belongs.
* @param productVersionId The ID of the product version to update.
* @param inputDto A request payload ({@link ProductVersionRQ}) containing updated information
* for the product version.
* @return A data transfer object ({@link TmsProductVersionRS}) with updated details of the product version.
*/
@PutMapping("/{productVersionId}")
TmsProductVersionRS updateVersion(@PathVariable("projectKey") String projectKey,
@PathVariable("productVersionId") final long productVersionId,
@RequestBody final ProductVersionRQ inputDto,
@AuthenticationPrincipal ReportPortalUser user) {
return productVersionService.update(
projectExtractor
.extractMembershipDetails(user, EntityUtils.normalizeId(projectKey))
.getProjectId(),
productVersionId,
inputDto);
}

/**
* Deletes a specific product version from a project.
*
* @param projectKey The key of the project to which the product version belongs.
* @param productVersionId The ID of the product version to delete.
*/
@DeleteMapping("/{productVersionId}")
void deleteVersion(@PathVariable("projectKey") String projectKey,
@PathVariable("productVersionId") final long productVersionId,
@AuthenticationPrincipal ReportPortalUser user) {
productVersionService.delete(
projectExtractor
.extractMembershipDetails(user, EntityUtils.normalizeId(projectKey))
.getProjectId(),
productVersionId);
}
}
Loading