RED-9010: Remove redaction log

This commit is contained in:
Maverick Studer 2024-09-19 11:34:42 +02:00
parent a96372e542
commit 62719aec6f
12 changed files with 0 additions and 619 deletions

View File

@ -1,156 +0,0 @@
package com.iqser.red.persistence.service.v1.external.api.impl.controller;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_REDACTION_LOG;
import static com.iqser.red.service.persistence.management.v1.processor.service.FeignExceptionHandler.processFeignException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService;
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService;
import com.iqser.red.service.persistence.management.v1.processor.service.RedactionLogService;
import com.iqser.red.service.persistence.management.v1.processor.utils.StringEncodingUtils;
import com.iqser.red.service.persistence.service.v1.api.external.resource.RedactionLogResource;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.FilteredRedactionLogRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.section.SectionGrid;
import com.iqser.red.storage.commons.exception.StorageObjectDoesNotExist;
import com.knecon.fforesight.tenantcommons.TenantContext;
import feign.FeignException;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
@RestController
@RequiredArgsConstructor
@Deprecated(forRemoval = true)
public class RedactionLogController implements RedactionLogResource {
private final RedactionLogService redactionLogService;
private final FileStatusService fileStatusService;
private final FileManagementStorageService fileManagementStorageService;
@Deprecated(forRemoval = true)
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
public RedactionLog getRedactionLog(@PathVariable(DOSSIER_ID) String dossierId,
@PathVariable(FILE_ID) String fileId,
@RequestParam(value = "excludedType", required = false) List<String> excludedTypes,
@RequestParam(value = "withManualRedactions", required = false, defaultValue = "true") boolean withManualRedactions,
@RequestParam(value = "includeFalsePositives", required = false, defaultValue = "false") boolean includeFalsePositives) {
try {
return redactionLogService.getRedactionLog(dossierId, fileId, excludedTypes);
} catch (FeignException e) {
throw processFeignException(e);
}
}
@Deprecated(forRemoval = true)
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
public SectionGrid getSectionGrid(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
try {
return redactionLogService.getSectionGrid(dossierId, fileId);
} catch (FeignException e) {
throw processFeignException(e);
}
}
@Deprecated(forRemoval = true)
@SneakyThrows
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
public ResponseEntity<?> getSectionText(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
try {
return buildZipFileResponseEntity(fileId, dossierId, FileType.TEXT);
} catch (FeignException e) {
throw processFeignException(e);
}
}
private ResponseEntity<byte[]> buildZipFileResponseEntity(String fileId, String dossierId, FileType fileType) throws IOException {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.parseMediaType("application/zip"));
var fileStatus = fileStatusService.getStatus(fileId);
String filename = fileStatus.getFilename();
if (filename != null) {
var index = filename.lastIndexOf(".");
String prefix = filename.substring(0, index);
filename = prefix + ".json";
httpHeaders.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename*=utf-8''" + StringEncodingUtils.urlEncode(prefix) + ".zip");
}
byte[] zipBytes = getZippedBytes(dossierId, fileId, filename, fileType);
httpHeaders.setContentLength(zipBytes.length);
return new ResponseEntity<>(zipBytes, httpHeaders, HttpStatus.OK);
}
@Deprecated(forRemoval = true)
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
public RedactionLog getFilteredRedactionLog(@PathVariable(DOSSIER_ID) String dossierId,
@PathVariable(FILE_ID) String fileId,
@RequestBody FilteredRedactionLogRequest filteredRedactionLogRequest) {
try {
return redactionLogService.getFilteredRedactionLog(dossierId, fileId, filteredRedactionLogRequest);
} catch (FeignException e) {
throw processFeignException(e);
}
}
private byte[] getZippedBytes(String dossierId, String fileId, String filename, FileType fileType) throws IOException {
try {
String objectId = dossierId + "/" + fileId + "." + fileType.name() + fileType.getExtension();
try (var inputStream = fileManagementStorageService.getObject(TenantContext.getTenantId(), objectId)) {
byte[] input = inputStream.readAllBytes();
inputStream.close();
return zipBytes(filename, input);
}
} catch (StorageObjectDoesNotExist e) {
throw new RuntimeException(String.format("%s is not available", fileType.name()), e);
}
}
public static byte[] zipBytes(String filename, byte[] input) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos);
ZipEntry entry = new ZipEntry(filename);
entry.setSize(input.length);
zos.putNextEntry(entry);
zos.write(input);
zos.closeEntry();
zos.close();
return baos.toByteArray();
}
}

View File

@ -1,71 +0,0 @@
package com.iqser.red.service.persistence.service.v1.api.external.resource;
import java.util.List;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
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.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.FilteredRedactionLogRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.section.SectionGrid;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
@Deprecated(forRemoval = true)
@ResponseStatus(value = HttpStatus.OK)
public interface RedactionLogResource {
String REDACTION_LOG_PATH = ExternalApi.BASE_PATH + "/redactionLog";
String SECTION_GRID_PATH = ExternalApi.BASE_PATH + "/sectionGrid";
String SECTION_TEXT_PATH = ExternalApi.BASE_PATH + "/sectionText";
String FILE_ID = "fileId";
String FILE_ID_PATH_VARIABLE = "/{" + FILE_ID + "}";
String DOSSIER_ID = "dossierId";
String DOSSIER_ID_PATH_VARIABLE = "/{" + DOSSIER_ID + "}";
@Deprecated(forRemoval = true)
@GetMapping(value = REDACTION_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Gets the redaction log for a fileId", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The redaction log is not found.")})
RedactionLog getRedactionLog(@PathVariable(DOSSIER_ID) String dossierId,
@PathVariable(FILE_ID) String fileId,
@RequestParam(value = "excludedType", required = false) List<String> excludedTypes,
@RequestParam(value = "withManualRedactions", required = false, defaultValue = "true") boolean withManualRedactions,
@RequestParam(value = "includeFalsePositives", required = false, defaultValue = "false") boolean includeFalsePositives);
@Deprecated(forRemoval = true)
@GetMapping(value = SECTION_GRID_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Gets the section grid for a fileId", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The section grid is not found.")})
SectionGrid getSectionGrid(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
@Deprecated(forRemoval = true)
@GetMapping(value = SECTION_TEXT_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE)
@Operation(summary = "Gets the text blocks of a document for a fileId", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The section text is not found.")})
ResponseEntity<?> getSectionText(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
@Deprecated(forRemoval = true)
@PostMapping(value = REDACTION_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE + "/filtered", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Gets the redaction log for a fileId grater than the specified date", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The redaction log is not found.")})
RedactionLog getFilteredRedactionLog(@PathVariable(DOSSIER_ID) String dossierId,
@PathVariable(FILE_ID) String fileId,
@RequestBody FilteredRedactionLogRequest filteredRedactionLogRequest);
}

View File

@ -1,31 +0,0 @@
package com.iqser.red.service.persistence.v1.internal.api.controller;
import java.util.List;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.iqser.red.service.persistence.management.v1.processor.service.RedactionLogService;
import com.iqser.red.service.persistence.service.v1.api.internal.resources.RedactionLogResource;
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog;
import lombok.RequiredArgsConstructor;
@RestController
@RequiredArgsConstructor
public class RedactionLogInternalController implements RedactionLogResource {
private final RedactionLogService redactionLogService;
public RedactionLog getRedactionLog(@PathVariable(DOSSIER_ID_PARAM) String dossierId,
@PathVariable(FILE_ID) String fileId,
@RequestParam(value = "excludedType", required = false) List<String> excludedTypes,
@RequestParam(value = "withManualRedactions", required = false, defaultValue = "true") boolean withManualRedactions,
@RequestParam(value = "includeFalsePositives", required = false, defaultValue = "false") boolean includeFalsePositives) {
return redactionLogService.getRedactionLog(dossierId, fileId, excludedTypes);
}
}

View File

@ -1,33 +0,0 @@
package com.iqser.red.service.persistence.service.v1.api.internal.resources;
import java.util.List;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog;
@ResponseStatus(value = HttpStatus.OK)
public interface RedactionLogResource {
String REDACTION_LOG_PATH = "/redactionLog";
String FILE_ID = "fileId";
String FILE_ID_PATH_VARIABLE = "/{" + FILE_ID + "}";
String DOSSIER_ID_PARAM = "dossierId";
String DOSSIER_ID_PATH_PARAM = "/{" + DOSSIER_ID_PARAM + "}";
@GetMapping(value = InternalApi.BASE_PATH + REDACTION_LOG_PATH + DOSSIER_ID_PATH_PARAM + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
RedactionLog getRedactionLog(@PathVariable(DOSSIER_ID_PARAM) String dossierId,
@PathVariable(FILE_ID) String fileId,
@RequestParam(value = "excludedType", required = false) List<String> excludedTypes,
@RequestParam(value = "withManualRedactions", required = false, defaultValue = "true") boolean withManualRedactions,
@RequestParam(value = "includeFalsePositives", required = false, defaultValue = "false") boolean includeFalsePositives);
}

View File

@ -17,7 +17,6 @@ import com.iqser.red.service.persistence.management.v1.processor.utils.StorageId
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.imported.ImportedRedactions;
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.section.SectionGrid;
import com.iqser.red.service.persistence.service.v1.api.shared.mongo.service.EntityLogMongoService;
@ -88,19 +87,6 @@ public class FileManagementStorageService {
}
public RedactionLog getRedactionLog(String dossierId, String fileId) {
try {
return storageService.readJSONObject(TenantContext.getTenantId(), StorageIdUtils.getStorageId(dossierId, fileId, FileType.REDACTION_LOG), RedactionLog.class);
} catch (StorageObjectDoesNotExist e) {
log.debug("RedactionLog does not exist");
throw new NotFoundException(String.format("RedactionLog does not exist for Dossier ID \"%s\" and File ID \"%s\"!", dossierId, fileId));
} catch (StorageException e) {
throw new InternalServerErrorException(e.getMessage());
}
}
public EntityLog getEntityLog(String dossierId, String fileId) {
return entityLogMongoService.findEntityLogByDossierIdAndFileId(dossierId, fileId)
@ -165,13 +151,6 @@ public class FileManagementStorageService {
}
public void storeRedactionLog(String dossierId, String fileId, RedactionLog redactionLog) {
storageService.storeJSONObject(TenantContext.getTenantId(), StorageIdUtils.getStorageId(dossierId, fileId, FileType.REDACTION_LOG), redactionLog);
}
public SectionGrid getSectionGrid(String dossierId, String fileId) {
try {

View File

@ -1,101 +0,0 @@
package com.iqser.red.service.persistence.management.v1.processor.service;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.springframework.stereotype.Service;
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.FilteredRedactionLogRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry;
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.section.SectionGrid;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class RedactionLogService {
private final FileManagementStorageService fileManagementStorageService;
private final FileStatusService fileStatusService;
public RedactionLog getRedactionLog(String dossierId, String fileId) {
return getRedactionLog(dossierId, fileId, Collections.emptyList());
}
public RedactionLog getRedactionLog(String dossierId, String fileId, List<String> excludedTypes) {
var fileStatus = fileStatusService.getStatus(fileId);
RedactionLog redactionLog;
redactionLog = fileManagementStorageService.getRedactionLog(dossierId, fileId);
if (fileStatus.isExcluded()) {
redactionLog.setRedactionLogEntry(new ArrayList<>());
}
if (excludedTypes != null) {
redactionLog.getRedactionLogEntry().removeIf(nextEntry -> excludedTypes.contains(nextEntry.getType()));
}
return redactionLog;
}
public SectionGrid getSectionGrid(String dossierId, String fileId) {
return fileManagementStorageService.getSectionGrid(dossierId, fileId);
}
public RedactionLog getFilteredRedactionLog(String dossierId, String fileId, FilteredRedactionLogRequest filteredRedactionLogRequest) {
if (filteredRedactionLogRequest.getSpecifiedDate() == null) {
filteredRedactionLogRequest.setSpecifiedDate(OffsetDateTime.MIN);
}
var redactionLog = getRedactionLog(dossierId, fileId, filteredRedactionLogRequest.getExcludedTypes());
var redactionLogEntries = redactionLog.getRedactionLogEntry();
Iterator<RedactionLogEntry> it = redactionLogEntries.iterator();
while (it.hasNext()) {
var redactionLogEntry = it.next();
boolean isAfterSpecifiedDate = false;
for (var change : redactionLogEntry.getChanges()) {
if (change.getDateTime() != null && change.getDateTime().isAfter(filteredRedactionLogRequest.getSpecifiedDate())) {
isAfterSpecifiedDate = true;
}
}
for (var manualChange : redactionLogEntry.getManualChanges()) {
if (manualChange.getProcessedDate() != null && manualChange.getProcessedDate().isAfter(filteredRedactionLogRequest.getSpecifiedDate())
|| manualChange.getRequestedDate() != null && manualChange.getRequestedDate().isAfter(filteredRedactionLogRequest.getSpecifiedDate())) {
isAfterSpecifiedDate = true;
}
}
var comments = redactionLogEntry.getComments();
if (comments != null) {
for (var comment : comments) {
if (comment.getSoftDeletedTime() != null && comment.getSoftDeletedTime().isAfter(filteredRedactionLogRequest.getSpecifiedDate())
|| comment.getDate() != null && comment.getDate().isAfter(filteredRedactionLogRequest.getSpecifiedDate())) {
isAfterSpecifiedDate = true;
}
}
}
if (!isAfterSpecifiedDate) {
it.remove();
}
}
return redactionLog;
}
}

View File

@ -1,10 +0,0 @@
package com.iqser.red.service.peristence.v1.server.integration.client;
import org.springframework.cloud.openfeign.FeignClient;
import com.iqser.red.service.persistence.service.v1.api.external.resource.RedactionLogResource;
@FeignClient(name = "RedactionLogClient", url = "http://localhost:${server.port}")
public interface RedactionLogClient extends RedactionLogResource {
}

View File

@ -1,35 +0,0 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog;
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Deprecated(forRemoval = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RedactionLog {
/**
* Version 0 Redaction Logs have manual redactions merged inside them
* Version 1 Redaction Logs only contain system ( rule/dictionary ) redactions. Manual Redactions are merged in at runtime.
*/
private long analysisVersion;
/**
* Which analysis created this redactionLog.
*/
private int analysisNumber;
private List<RedactionLogEntry> redactionLogEntry = new ArrayList<>();
private List<RedactionLogLegalBasis> legalBasis = new ArrayList<>();
private long dictionaryVersion = -1;
private long dossierDictionaryVersion = -1;
private long rulesVersion = -1;
private long legalBasisVersion = -1;
}

View File

@ -1,18 +0,0 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@Deprecated(forRemoval = true)
@AllArgsConstructor
@NoArgsConstructor
public class RedactionLogChanges {
private RedactionLog redactionLog;
private boolean hasChanges;
}

View File

@ -1,23 +0,0 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog;
import java.time.OffsetDateTime;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@Deprecated(forRemoval = true)
@AllArgsConstructor
public class RedactionLogComment {
private long id;
private String user;
private String text;
private String annotationId;
private String fileId;
private OffsetDateTime date;
private OffsetDateTime softDeletedTime;
}

View File

@ -1,103 +0,0 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@Deprecated(forRemoval = true)
@AllArgsConstructor
@EqualsAndHashCode
public class RedactionLogEntry {
private String id;
private String type;
private String value;
private String reason;
private String matchedRule;
private boolean rectangle;
private String legalBasis;
private boolean imported;
private boolean redacted;
private boolean isHint;
private boolean isRecommendation;
private boolean isFalsePositive;
private String section;
private float[] color;
@Builder.Default
private List<Rectangle> positions = new ArrayList<>();
private int sectionNumber;
private String textBefore;
private String textAfter;
@Builder.Default
private List<RedactionLogComment> comments = new ArrayList<>();
private int startOffset;
private int endOffset;
private boolean isImage;
private boolean imageHasTransparency;
private boolean isDictionaryEntry;
private boolean isDossierDictionaryEntry;
private boolean excluded;
private String sourceId;
@EqualsAndHashCode.Exclude
@Builder.Default
private List<Change> changes = new ArrayList<>();
@EqualsAndHashCode.Exclude
@Builder.Default
private List<ManualChange> manualChanges = new ArrayList<>();
@Builder.Default
private Set<Engine> engines = new HashSet<>();
@Builder.Default
private Set<String> reference = new HashSet<>();
@Builder.Default
private Set<String> importedRedactionIntersections = new HashSet<>();
public boolean lastChangeIsRemoved() {
return last(changes).map(c -> c.getType() == ChangeType.REMOVED)
.orElse(false);
}
public boolean isManuallyRemoved() {
return manualChanges != null && manualChanges.stream()
.anyMatch(mc -> mc.getManualRedactionType() == ManualRedactionType.REMOVE_LOCALLY);
}
private <T> Optional<T> last(List<T> list) {
return list == null || list.isEmpty() ? Optional.empty() : Optional.of(list.get(list.size() - 1));
}
}

View File

@ -1,17 +0,0 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Deprecated(forRemoval = true)
@NoArgsConstructor
@AllArgsConstructor
public class RedactionLogLegalBasis {
private String name;
private String description;
private String reason;
}