From 38c6a6572f439a0b7351e7f5a4428a4dd715db0c Mon Sep 17 00:00:00 2001 From: David Randolph Phillips Date: Fri, 27 Oct 2023 14:33:32 -0400 Subject: [PATCH 1/4] [BI-1915] ontology export/download --- .../api/v1/controller/TraitController.java | 25 +++- .../model/imports/DataTypeTranslator.java | 35 ++++++ .../model/imports/TermTypeTranslator.java | 13 ++ .../services/OntologyService.java | 116 ++++++++++++++++++ .../parsers/trait/TraitFileColumns.java | 62 ++++++---- .../parsers/trait/TraitFileParser.java | 4 +- 6 files changed, 225 insertions(+), 30 deletions(-) create mode 100644 src/main/java/org/breedinginsight/brapps/importer/model/imports/DataTypeTranslator.java diff --git a/src/main/java/org/breedinginsight/api/v1/controller/TraitController.java b/src/main/java/org/breedinginsight/api/v1/controller/TraitController.java index 7f44398cd..46775d974 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/TraitController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/TraitController.java @@ -17,10 +17,12 @@ package org.breedinginsight.api.v1.controller; +import io.micronaut.http.HttpHeaders; import io.micronaut.http.HttpResponse; import io.micronaut.http.HttpStatus; import io.micronaut.http.MediaType; import io.micronaut.http.annotation.*; +import io.micronaut.http.server.types.files.StreamedFile; import lombok.extern.slf4j.Slf4j; import org.breedinginsight.api.auth.*; import org.breedinginsight.api.model.v1.request.query.QueryParams; @@ -35,6 +37,8 @@ import org.breedinginsight.api.model.v1.validators.QueryValid; import org.breedinginsight.api.model.v1.validators.SearchValid; import org.breedinginsight.api.v1.controller.metadata.AddMetadata; +import org.breedinginsight.brapps.importer.model.exports.FileType; +import org.breedinginsight.model.DownloadFile; import org.breedinginsight.model.Editable; import org.breedinginsight.model.Program; import org.breedinginsight.model.Trait; @@ -52,7 +56,6 @@ import java.util.List; import java.util.Optional; import java.util.UUID; -import java.util.concurrent.atomic.AtomicReference; @Slf4j @Controller("/${micronaut.bi.api.version}") @@ -88,6 +91,26 @@ public HttpResponse>> getTraits( } } + @Get("/programs/{programId}/traits/export{?fileExtension,isActive}") + @Produces(value = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") + @ProgramSecured(roleGroups = {ProgramSecuredRoleGroup.ALL}) + public HttpResponse getTraitsExport( + @PathVariable("programId") UUID programId, @QueryValue(defaultValue = "XLSX") String fileExtension, @QueryValue(defaultValue = "true") Boolean isActive) { + String downloadErrorMessage = "An error occurred while generating the download file. Contact the development team at bidevteam@cornell.edu."; + try { + FileType extension = Enum.valueOf(FileType.class, fileExtension); + DownloadFile ontologyFile = ontologyService.exportOntology(programId, extension, isActive); + HttpResponse ontologyExport = HttpResponse.ok(ontologyFile.getStreamedFile()).header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename="+ontologyFile.getFileName()+extension.getExtension()); + return ontologyExport; + } + catch (Exception e) { + log.info(e.getMessage(), e); + e.printStackTrace(); + HttpResponse response = HttpResponse.status(HttpStatus.INTERNAL_SERVER_ERROR, downloadErrorMessage).contentType(MediaType.TEXT_PLAIN).body(downloadErrorMessage); + return response; + } + } + @Post("/programs/{programId}/traits/search{?queryParams*}") @Produces(MediaType.APPLICATION_JSON) @ProgramSecured(roleGroups = {ProgramSecuredRoleGroup.ALL}) diff --git a/src/main/java/org/breedinginsight/brapps/importer/model/imports/DataTypeTranslator.java b/src/main/java/org/breedinginsight/brapps/importer/model/imports/DataTypeTranslator.java new file mode 100644 index 000000000..d0861edb7 --- /dev/null +++ b/src/main/java/org/breedinginsight/brapps/importer/model/imports/DataTypeTranslator.java @@ -0,0 +1,35 @@ +package org.breedinginsight.brapps.importer.model.imports; + +import org.breedinginsight.dao.db.enums.DataType; +import org.breedinginsight.dao.db.enums.TermType; + +import java.util.Map; +import java.util.Optional; + +public class DataTypeTranslator { + + private static final Map displayToTypeMap = Map.of( + "Date YYYY-MM-DD", DataType.DATE, + "Numerical", DataType.NUMERICAL, + "Nominal", DataType.NOMINAL, + "Ordinal", DataType.ORDINAL, + "Text", DataType.TEXT); + + + public static Optional getTypeFromUserDisplayName(String displayName) { + return Optional.ofNullable(displayToTypeMap.get(displayName)); + } + + public static String getDisplayNameFromType(DataType type){ + String displayName = ""; + if(type!=null) { + for (String key : displayToTypeMap.keySet()) { + if (type == displayToTypeMap.get(key)) { + displayName = key; + break; + } + } + } + return displayName; + } +} diff --git a/src/main/java/org/breedinginsight/brapps/importer/model/imports/TermTypeTranslator.java b/src/main/java/org/breedinginsight/brapps/importer/model/imports/TermTypeTranslator.java index b53af17d7..225ba7ee6 100644 --- a/src/main/java/org/breedinginsight/brapps/importer/model/imports/TermTypeTranslator.java +++ b/src/main/java/org/breedinginsight/brapps/importer/model/imports/TermTypeTranslator.java @@ -14,4 +14,17 @@ public class TermTypeTranslator { public static Optional getTermTypeFromUserDisplayName(String userDisplayName) { return Optional.ofNullable(userDisplayToTermTypeMap.get(userDisplayName)); } + + public static String getDisplayNameFromTermType(TermType termType){ + String displayName = ""; + if(termType!=null) { + for (String key : userDisplayToTermTypeMap.keySet()) { + if (termType == userDisplayToTermTypeMap.get(key)) { + displayName = key; + break; + } + } + } + return displayName; + } } diff --git a/src/main/java/org/breedinginsight/services/OntologyService.java b/src/main/java/org/breedinginsight/services/OntologyService.java index 702073a54..71508155a 100644 --- a/src/main/java/org/breedinginsight/services/OntologyService.java +++ b/src/main/java/org/breedinginsight/services/OntologyService.java @@ -4,21 +4,34 @@ import io.micronaut.http.exceptions.HttpStatusException; import io.micronaut.http.multipart.CompletedFileUpload; import io.micronaut.http.server.exceptions.InternalServerException; +import io.micronaut.http.server.types.files.StreamedFile; +import org.apache.commons.lang3.StringUtils; import org.brapi.v2.model.core.BrAPIProgram; +import org.brapi.v2.model.pheno.BrAPIScaleValidValuesCategories; import org.breedinginsight.api.auth.AuthenticatedUser; import org.breedinginsight.api.model.v1.request.SharedOntologyProgramRequest; import org.breedinginsight.api.model.v1.response.ValidationError; import org.breedinginsight.api.model.v1.response.ValidationErrors; +import org.breedinginsight.brapps.importer.model.exports.FileType; +import org.breedinginsight.brapps.importer.model.imports.DataTypeTranslator; +import org.breedinginsight.brapps.importer.model.imports.TermTypeTranslator; import org.breedinginsight.dao.db.tables.pojos.ProgramSharedOntologyEntity; import org.breedinginsight.daos.ProgramDAO; import org.breedinginsight.daos.ProgramOntologyDAO; import org.breedinginsight.daos.TraitDAO; import org.breedinginsight.model.*; import org.breedinginsight.services.exceptions.*; +import org.breedinginsight.services.parsers.trait.TraitFileColumns; +import org.breedinginsight.services.writers.CSVWriter; +import org.breedinginsight.services.writers.ExcelWriter; +import org.jooq.DataType; +import org.jooq.exception.IOException; import javax.inject.Inject; import javax.inject.Singleton; import javax.validation.constraints.NotNull; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; @@ -342,6 +355,43 @@ public List updateTraits(UUID programId, List traits, Authenticate return traitService.updateTraits(lookupId, traits, actingUser); } + + public DownloadFile exportOntology(UUID programId, FileType fileExtension, boolean isActive) throws IllegalArgumentException, IOException, java.io.IOException { + List columns = TraitFileColumns.getOrderedColumns(); + + //Retrieve trait list data + List traits = traitDAO.getTraitsFullByProgramId(programId); + //Filter traits for Active or Archived + traits = traits.stream().filter(trait -> trait.getActive()==isActive).collect(Collectors.toList()); + //Sort list in default (trait name) order. + traits.sort(Comparator.comparing(trait -> trait.getObservationVariableName().toLowerCase())); + + // make file Name + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd:hh-mm-ssZ"); + String timestamp = formatter.format(OffsetDateTime.now()); + Program program = null; + try { + program = getProgram(programId); + } catch (DoesNotExistException e) { + e.printStackTrace(); + } + String activeOrArchive = isActive ? "Active" : "Archive"; + String programName = program.getName(); + String fileName = programName + "_" + activeOrArchive + "_Ontology_" + timestamp; + + StreamedFile downloadFile; + + //Convert traits list to List> data to pass into file writer + List> processedData = processData(traits); + + if (fileExtension == FileType.CSV){ + downloadFile = CSVWriter.writeToDownload(columns, processedData, fileExtension); + } else { + downloadFile = ExcelWriter.writeToDownload("Data", columns, processedData, fileExtension); + } + return new DownloadFile(fileName, downloadFile); + } + public List createTraits(UUID programId, List traits, AuthenticatedUser actingUser, Boolean throwDuplicateErrors) throws DoesNotExistException, ValidatorException, BadRequestException { UUID lookupId = getSubscribedOntologyProgramId(programId); @@ -408,5 +458,71 @@ public List getSubscribeOntologyOptions(UUID programId) thro ).collect(Collectors.toList()); return subscriptionOptions; } + public List> processData(List traits) { + List> processedData = new ArrayList<>(); + + for (Trait trait : traits) { + HashMap row = new HashMap<>(); + row.put(TraitFileColumns.NAME.toString(), trait.getObservationVariableName()); + row.put(TraitFileColumns.FULL_NAME.toString(), trait.getFullName()); + row.put(TraitFileColumns.TERM_TYPE.toString(), TermTypeTranslator.getDisplayNameFromTermType( trait.getTermType() )); + row.put(TraitFileColumns.DESCRIPTION.toString(), trait.getTraitDescription()); + //SYNONYMS + String synonymsAsStr = null; + if(trait.getSynonyms() != null) { + synonymsAsStr = String.join("; ", trait.getSynonyms()); + } + row.put(TraitFileColumns.SYNONYMS.toString(), synonymsAsStr); + //STATUS + if(trait.getActive()) { + row.put(TraitFileColumns.STATUS.toString(), "active"); + } else { + row.put(TraitFileColumns.STATUS.toString(), "archived"); + + } + //TAGS + String tagsAsStr = null; + if(trait.getTags() != null) { + tagsAsStr = String.join("; ", trait.getTags()); + } + row.put(TraitFileColumns.TAGS.toString(), tagsAsStr); + + row.put(TraitFileColumns.TRAIT_ENTITY.toString(), trait.getEntity()); + row.put(TraitFileColumns.TRAIT_ATTRIBUTE.toString(), trait.getAttribute()); + Method method = trait.getMethod(); + if(method!=null) { + row.put(TraitFileColumns.METHOD_DESCRIPTION.toString(), method.getDescription()); + row.put(TraitFileColumns.METHOD_CLASS.toString(), method.getMethodClass()); + row.put(TraitFileColumns.METHOD_FORMULA.toString(), method.getFormula()); + } + Scale scale = trait.getScale(); + if(scale!=null) { + + row.put(TraitFileColumns.SCALE_CLASS.toString(), DataTypeTranslator.getDisplayNameFromType(scale.getDataType())); + row.put(TraitFileColumns.SCALE_NAME.toString(), scale.getScaleName()); + row.put(TraitFileColumns.SCALE_DECIMAL_PLACES.toString(), scale.getDecimalPlaces()); + row.put(TraitFileColumns.SCALE_LOWER_LIMIT.toString(), scale.getValidValueMin()); + row.put(TraitFileColumns.SCALE_UPPER_LIMIT.toString(), scale.getValidValueMax()); + //SCALE_CATEGORIES + String categoriesAsStr = null; + if(scale.getCategories() != null) { + categoriesAsStr = scale.getCategories().stream() + .map(this::makeCategoryString) + .collect(Collectors.joining("; ")); + } + row.put(TraitFileColumns.SCALE_CATEGORIES.toString(), categoriesAsStr); + } + processedData.add(row); + } + return processedData; + } + private String makeCategoryString(BrAPIScaleValidValuesCategories category){ + StringBuilder stringBuilder = new StringBuilder( category.getValue() ); + if( StringUtils.isNotBlank( category.getLabel() ) ){ + stringBuilder.append("="); + stringBuilder.append( category.getLabel() ); + } + return stringBuilder.toString(); + } } diff --git a/src/main/java/org/breedinginsight/services/parsers/trait/TraitFileColumns.java b/src/main/java/org/breedinginsight/services/parsers/trait/TraitFileColumns.java index a9d7d1e45..f3782adf7 100644 --- a/src/main/java/org/breedinginsight/services/parsers/trait/TraitFileColumns.java +++ b/src/main/java/org/breedinginsight/services/parsers/trait/TraitFileColumns.java @@ -16,46 +16,54 @@ */ package org.breedinginsight.services.parsers.trait; +import org.breedinginsight.model.Column; + import java.util.Arrays; +import java.util.List; import java.util.Set; import java.util.stream.Collectors; public enum TraitFileColumns { - NAME("Name"), - SYNONYMS("Synonyms"), - TRAIT_ENTITY("Trait entity"), - TRAIT_ATTRIBUTE("Trait attribute"), - DESCRIPTION("Description"), - STATUS("Status"), - METHOD_DESCRIPTION("Method description"), - METHOD_CLASS("Method class"), - METHOD_FORMULA("Method formula"), - SCALE_NAME("Units"), - SCALE_CLASS("Scale class"), - SCALE_DECIMAL_PLACES("Scale decimal places"), - SCALE_LOWER_LIMIT("Scale lower limit"), - SCALE_UPPER_LIMIT("Scale upper limit"), - SCALE_CATEGORIES("Scale categories"), - TAGS("Tags"), - FULL_NAME("Full name"), - TERM_TYPE("Term Type"); - - - private String value; - - TraitFileColumns(String value) { - this.value = value; + NAME("Name", Column.ColumnDataType.STRING), + FULL_NAME("Full name", Column.ColumnDataType.STRING), + TERM_TYPE("Term Type", Column.ColumnDataType.STRING), + DESCRIPTION("Description", Column.ColumnDataType.STRING), + SYNONYMS("Synonyms", Column.ColumnDataType.STRING), + STATUS("Status",Column.ColumnDataType.STRING), + TAGS("Tags", Column.ColumnDataType.STRING), + TRAIT_ENTITY("Trait entity", Column.ColumnDataType.STRING), + TRAIT_ATTRIBUTE("Trait attribute", Column.ColumnDataType.STRING), + METHOD_DESCRIPTION("Method description", Column.ColumnDataType.STRING), + METHOD_CLASS("Method class", Column.ColumnDataType.STRING), + METHOD_FORMULA("Method formula", Column.ColumnDataType.STRING), + SCALE_CLASS("Scale class", Column.ColumnDataType.STRING), + SCALE_NAME("Units", Column.ColumnDataType.STRING), + SCALE_DECIMAL_PLACES("Scale decimal places", Column.ColumnDataType.INTEGER), + SCALE_LOWER_LIMIT("Scale lower limit", Column.ColumnDataType.INTEGER), + SCALE_UPPER_LIMIT("Scale upper limit", Column.ColumnDataType.INTEGER), + SCALE_CATEGORIES("Scale categories", Column.ColumnDataType.STRING); + + private final Column column; + + TraitFileColumns(String value, Column.ColumnDataType dataType) { + this.column = new Column(value, dataType); } @Override public String toString() { - return value; + return column.getValue(); } - public static Set getColumns() { + public static Set getColumnNames() { return Arrays.stream(TraitFileColumns.values()) - .map(value -> value.toString()) + .map(value -> value.column.getValue()) .collect(Collectors.toSet()); } + + public static List getOrderedColumns() { + return Arrays.stream(TraitFileColumns.values()) + .map(value -> value.column) + .collect(Collectors.toList()); + } } \ No newline at end of file diff --git a/src/main/java/org/breedinginsight/services/parsers/trait/TraitFileParser.java b/src/main/java/org/breedinginsight/services/parsers/trait/TraitFileParser.java index 3d81eac24..771518e71 100644 --- a/src/main/java/org/breedinginsight/services/parsers/trait/TraitFileParser.java +++ b/src/main/java/org/breedinginsight/services/parsers/trait/TraitFileParser.java @@ -95,7 +95,7 @@ public List parseExcel(@NonNull InputStream inputStream) throws ParsingEx throw new ParsingException(ParsingExceptionType.MISSING_SHEET); } - List records = ExcelParser.parse(sheet, TraitFileColumns.getColumns()); + List records = ExcelParser.parse(sheet, TraitFileColumns.getColumnNames()); return excelRecordsToTraits(records); } @@ -117,7 +117,7 @@ public List parseCsv(@NonNull InputStream inputStream) throws ParsingExce } Sheet excelSheet = convertCsvToExcel(records); - List excelRecords = ExcelParser.parse(excelSheet, TraitFileColumns.getColumns()); + List excelRecords = ExcelParser.parse(excelSheet, TraitFileColumns.getColumnNames()); return excelRecordsToTraits(excelRecords); } From fe5aed9f7c145115f625c58605403f824b5f0a70 Mon Sep 17 00:00:00 2001 From: David Randolph Phillips Date: Wed, 1 Nov 2023 08:23:00 -0400 Subject: [PATCH 2/4] [BI-1915]fixed text for scale class DATE --- .../brapps/importer/model/imports/DataTypeTranslator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/breedinginsight/brapps/importer/model/imports/DataTypeTranslator.java b/src/main/java/org/breedinginsight/brapps/importer/model/imports/DataTypeTranslator.java index d0861edb7..39a93639f 100644 --- a/src/main/java/org/breedinginsight/brapps/importer/model/imports/DataTypeTranslator.java +++ b/src/main/java/org/breedinginsight/brapps/importer/model/imports/DataTypeTranslator.java @@ -9,7 +9,7 @@ public class DataTypeTranslator { private static final Map displayToTypeMap = Map.of( - "Date YYYY-MM-DD", DataType.DATE, + "Date", DataType.DATE, "Numerical", DataType.NUMERICAL, "Nominal", DataType.NOMINAL, "Ordinal", DataType.ORDINAL, From fe6eb4737b2ffe01561d2d038f13c55f5d6f7d51 Mon Sep 17 00:00:00 2001 From: David Randolph Phillips Date: Wed, 8 Nov 2023 10:24:47 -0500 Subject: [PATCH 3/4] [BI-1915] Fixed IntellaJ 'problems' ade code more readable --- .../api/v1/controller/TraitController.java | 14 ++--- .../model/imports/DataTypeTranslator.java | 1 - .../services/OntologyService.java | 57 ++++++++++--------- .../parsers/trait/TraitFileParser.java | 12 ++-- 4 files changed, 43 insertions(+), 41 deletions(-) diff --git a/src/main/java/org/breedinginsight/api/v1/controller/TraitController.java b/src/main/java/org/breedinginsight/api/v1/controller/TraitController.java index 46775d974..3e6e1869c 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/TraitController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/TraitController.java @@ -61,10 +61,10 @@ @Controller("/${micronaut.bi.api.version}") public class TraitController { - private TraitService traitService; - private SecurityService securityService; - private TraitQueryMapper traitQueryMapper; - private OntologyService ontologyService; + private final TraitService traitService; + private final SecurityService securityService; + private final TraitQueryMapper traitQueryMapper; + private final OntologyService ontologyService; @Inject public TraitController(TraitService traitService, SecurityService securityService, @@ -94,7 +94,7 @@ public HttpResponse>> getTraits( @Get("/programs/{programId}/traits/export{?fileExtension,isActive}") @Produces(value = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") @ProgramSecured(roleGroups = {ProgramSecuredRoleGroup.ALL}) - public HttpResponse getTraitsExport( + public HttpResponse getTraitsExport( @PathVariable("programId") UUID programId, @QueryValue(defaultValue = "XLSX") String fileExtension, @QueryValue(defaultValue = "true") Boolean isActive) { String downloadErrorMessage = "An error occurred while generating the download file. Contact the development team at bidevteam@cornell.edu."; try { @@ -163,7 +163,7 @@ public HttpResponse> getTraitEditable(@PathVariable UUID prog @Post("/programs/{programId}/traits") @Produces(MediaType.APPLICATION_JSON) @ProgramSecured(roles = {ProgramSecuredRole.BREEDER}) - public HttpResponse>> createTraits(@PathVariable UUID programId, @Body @Valid List traits) { + public HttpResponse createTraits(@PathVariable UUID programId, @Body @Valid List traits) { AuthenticatedUser actingUser = securityService.getUser(); try { List createdTraits = ontologyService.createTraits(programId, traits, actingUser, true); @@ -191,7 +191,7 @@ public HttpResponse>> createTraits(@PathVariable UU @Put("/programs/{programId}/traits") @Produces(MediaType.APPLICATION_JSON) @ProgramSecured(roles = {ProgramSecuredRole.BREEDER}) - public HttpResponse>> updateTraits(@PathVariable UUID programId, @Body @Valid List traits) { + public HttpResponse updateTraits(@PathVariable UUID programId, @Body @Valid List traits) { AuthenticatedUser actingUser = securityService.getUser(); try { List updatedTraits = ontologyService.updateTraits(programId, traits, actingUser); diff --git a/src/main/java/org/breedinginsight/brapps/importer/model/imports/DataTypeTranslator.java b/src/main/java/org/breedinginsight/brapps/importer/model/imports/DataTypeTranslator.java index 39a93639f..17fb4a178 100644 --- a/src/main/java/org/breedinginsight/brapps/importer/model/imports/DataTypeTranslator.java +++ b/src/main/java/org/breedinginsight/brapps/importer/model/imports/DataTypeTranslator.java @@ -1,7 +1,6 @@ package org.breedinginsight.brapps.importer.model.imports; import org.breedinginsight.dao.db.enums.DataType; -import org.breedinginsight.dao.db.enums.TermType; import java.util.Map; import java.util.Optional; diff --git a/src/main/java/org/breedinginsight/services/OntologyService.java b/src/main/java/org/breedinginsight/services/OntologyService.java index 71508155a..58cb5175f 100644 --- a/src/main/java/org/breedinginsight/services/OntologyService.java +++ b/src/main/java/org/breedinginsight/services/OntologyService.java @@ -16,6 +16,7 @@ import org.breedinginsight.brapps.importer.model.imports.DataTypeTranslator; import org.breedinginsight.brapps.importer.model.imports.TermTypeTranslator; import org.breedinginsight.dao.db.tables.pojos.ProgramSharedOntologyEntity; +import org.breedinginsight.dao.db.tables.pojos.TraitEntity; import org.breedinginsight.daos.ProgramDAO; import org.breedinginsight.daos.ProgramOntologyDAO; import org.breedinginsight.daos.TraitDAO; @@ -24,7 +25,7 @@ import org.breedinginsight.services.parsers.trait.TraitFileColumns; import org.breedinginsight.services.writers.CSVWriter; import org.breedinginsight.services.writers.ExcelWriter; -import org.jooq.DataType; + import org.jooq.exception.IOException; import javax.inject.Inject; @@ -38,11 +39,11 @@ @Singleton public class OntologyService { - private ProgramDAO programDAO; - private ProgramOntologyDAO programOntologyDAO; - private TraitDAO traitDAO; - private TraitService traitService; - private TraitUploadService traitUploadService; + private final ProgramDAO programDAO; + private final ProgramOntologyDAO programOntologyDAO; + private final TraitDAO traitDAO; + private final TraitService traitService; + private final TraitUploadService traitUploadService; @Inject public OntologyService(ProgramDAO programDAO, ProgramOntologyDAO programOntologyDAO, TraitDAO traitDAO, TraitService traitService, TraitUploadService traitUploadService) { @@ -59,7 +60,7 @@ public OntologyService(ProgramDAO programDAO, ProgramOntologyDAO programOntology * @param sharedOnly -- True = return only shared programs, False = get all shareable programs * @return List */ - public List getSharedOntology(@NotNull UUID programId, @NotNull Boolean sharedOnly) throws DoesNotExistException { + public List getSharedOntology(@NotNull UUID programId, @NotNull Boolean sharedOnly) throws DoesNotExistException { // Get program with that id Program program = getProgram(programId); @@ -100,7 +101,7 @@ public List getSharedOntology(@NotNull UUID programId, @NotNull Boolean sharedOn unsharableIds.addAll(shareTargetIds); formattedPrograms.addAll(matchingPrograms.stream() .filter(matchingProgram -> !unsharableIds.contains(matchingProgram.getId())) - .map(matchingProgram -> formatResponse(matchingProgram)) + .map(this::formatResponse) .collect(Collectors.toList())); } @@ -115,7 +116,7 @@ private List getSharedProgramsFormatted(Program program) { sharedOntologies.stream().map(ProgramSharedOntologyEntity::getSharedProgramId).collect(Collectors.toList())); // Get the programs in a lookup map Map sharedProgramsMap = new HashMap<>(); - sharedPrograms.stream().forEach(sharedProgram -> sharedProgramsMap.put(sharedProgram.getId(), sharedProgram)); + sharedPrograms.forEach(sharedProgram -> sharedProgramsMap.put(sharedProgram.getId(), sharedProgram)); // Format shared programs response return sharedOntologies.stream().map(sharedOntology -> @@ -170,7 +171,7 @@ private Boolean ontologyIsEditable(ProgramSharedOntologyEntity sharedOntologyEnt if (sharedOntologyEntity.getActive()) { // Get all trait ids for the program List traitIds = traitService.getSubscribedOntologyTraits(sharedOntologyEntity.getSharedProgramId()).stream() - .map(trait -> trait.getId()) + .map(TraitEntity::getId) .collect(Collectors.toList()); // Get the brapi program id @@ -216,7 +217,7 @@ public List shareOntology(@NotNull UUID programId, Authenticated // Check shareability, same brapi server, same species List matchingPrograms = getMatchingPrograms(program); Set matchingProgramsSet = new HashSet<>(); - matchingPrograms.stream().forEach(matchingProgram -> matchingProgramsSet.add(matchingProgram.getId())); + matchingPrograms.forEach(matchingProgram -> matchingProgramsSet.add(matchingProgram.getId())); Set shareProgramIdsSet = new HashSet<>(); ValidationErrors validationErrors = new ValidationErrors(); @@ -262,7 +263,7 @@ public List shareOntology(@NotNull UUID programId, Authenticated */ public void revokeOntology(@NotNull UUID programId, @NotNull UUID sharedProgramId) throws UnprocessableEntityException, DoesNotExistException { // Check that program exists - Program program = getProgram(programId); + getProgram(programId); // Check that shared program exists Optional optionalSharedOntology = programOntologyDAO.getSharedOntologyById(programId, sharedProgramId); @@ -324,7 +325,7 @@ public SubscribedOntology subscribeOntology(UUID programId, UUID sharingProgramI public void unsubscribeOntology(UUID programId, UUID sharingProgramId) throws DoesNotExistException, UnprocessableEntityException { // Check that program exists - Program program = getProgram(programId); + getProgram(programId); // Check that shared program exists Optional optionalSharedOntology = programOntologyDAO.getSharedOntologyById(sharingProgramId, programId); @@ -367,17 +368,7 @@ public DownloadFile exportOntology(UUID programId, FileType fileExtension, boole traits.sort(Comparator.comparing(trait -> trait.getObservationVariableName().toLowerCase())); // make file Name - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd:hh-mm-ssZ"); - String timestamp = formatter.format(OffsetDateTime.now()); - Program program = null; - try { - program = getProgram(programId); - } catch (DoesNotExistException e) { - e.printStackTrace(); - } - String activeOrArchive = isActive ? "Active" : "Archive"; - String programName = program.getName(); - String fileName = programName + "_" + activeOrArchive + "_Ontology_" + timestamp; + String fileName = makeFileName(programId, isActive); StreamedFile downloadFile; @@ -392,6 +383,20 @@ public DownloadFile exportOntology(UUID programId, FileType fileExtension, boole return new DownloadFile(fileName, downloadFile); } + private String makeFileName(UUID programId, boolean isActive) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd:hh-mm-ssZ"); + String timestamp = formatter.format(OffsetDateTime.now()); + Program program = null; + try { + program = getProgram(programId); + } catch (DoesNotExistException e) { + e.printStackTrace(); + } + String activeOrArchive = isActive ? "Active" : "Archive"; + String programName = program==null? "program" : program.getName(); + return programName + "_" + activeOrArchive + "_Ontology_" + timestamp; + } + public List createTraits(UUID programId, List traits, AuthenticatedUser actingUser, Boolean throwDuplicateErrors) throws DoesNotExistException, ValidatorException, BadRequestException { UUID lookupId = getSubscribedOntologyProgramId(programId); @@ -440,8 +445,8 @@ public UUID getSubscribedOntologyProgramId(UUID programId) throws DoesNotExistEx } public List getSubscribeOntologyOptions(UUID programId) throws DoesNotExistException { - - Program program = getProgram(programId); + // Check that program exists + getProgram(programId); List sharedOntologies = programOntologyDAO.getSubscriptionOptions(programId); List programs = programDAO.get(sharedOntologies.stream().map(ProgramSharedOntologyEntity::getProgramId).collect(Collectors.toList())); diff --git a/src/main/java/org/breedinginsight/services/parsers/trait/TraitFileParser.java b/src/main/java/org/breedinginsight/services/parsers/trait/TraitFileParser.java index 771518e71..66c7134f6 100644 --- a/src/main/java/org/breedinginsight/services/parsers/trait/TraitFileParser.java +++ b/src/main/java/org/breedinginsight/services/parsers/trait/TraitFileParser.java @@ -65,10 +65,9 @@ public class TraitFileParser { private static final String TRAIT_STATUS_ACTIVE = "active"; private static final String TRAIT_STATUS_ARCHIVED = "archived"; - private final static Set TRAIT_STATUS_VALID_VALUES = Collections.unmodifiableSet( - Set.of(TRAIT_STATUS_ACTIVE, TRAIT_STATUS_ARCHIVED)); + private final static Set TRAIT_STATUS_VALID_VALUES = Set.of(TRAIT_STATUS_ACTIVE, TRAIT_STATUS_ARCHIVED); - private TraitFileValidatorError traitValidatorError; + private final TraitFileValidatorError traitValidatorError; @Inject public TraitFileParser(TraitFileValidatorError traitValidatorError){ @@ -103,7 +102,6 @@ public List parseExcel(@NonNull InputStream inputStream) throws ParsingEx // no sheets RFC4180 public List parseCsv(@NonNull InputStream inputStream) throws ParsingException, ValidatorException { - ArrayList traits = new ArrayList<>(); InputStreamReader in = new InputStreamReader(inputStream); Iterable records = null; @@ -135,7 +133,7 @@ private List excelRecordsToTraits(List records) throws Valid .build(); - Boolean active; + boolean active; String traitStatus = parseExcelValueAsString(record, TraitFileColumns.STATUS); if (traitStatus == null) { active = true; @@ -145,7 +143,7 @@ private List excelRecordsToTraits(List records) throws Valid ParsingExceptionType.INVALID_TRAIT_STATUS.toString(), HttpStatus.UNPROCESSABLE_ENTITY); validationErrors.addError(traitValidatorError.getRowNumber(i), error); } - active = !traitStatus.toLowerCase().equals(TRAIT_STATUS_ARCHIVED); + active = !traitStatus.equalsIgnoreCase(TRAIT_STATUS_ARCHIVED); } // Normalize and capitalize method class @@ -354,7 +352,7 @@ private BrAPIScaleValidValuesCategories parseCategory(String value) throws Unpro else if (labelMeaning.length == 1) { category.setValue(labelMeaning[0].trim()); } else if (labelMeaning.length > 2){ - // The case where there are multiple category delimiters in a value. Could be cause by bad list delimeter. + // The case where there are multiple category delimiters in a value. Could be cause by bad list delimiter. throw new UnprocessableEntityException("Unable to parse categories"); } From 7582bd0ba3d070b55c40693a87444db4c0c68cf4 Mon Sep 17 00:00:00 2001 From: David Randolph Phillips Date: Wed, 8 Nov 2023 12:14:53 -0500 Subject: [PATCH 4/4] [BI-1915] only include caigories in ontology export, if the scale class is ORDINA or NOMINAL --- .../services/OntologyService.java | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/breedinginsight/services/OntologyService.java b/src/main/java/org/breedinginsight/services/OntologyService.java index 58cb5175f..90de17ec8 100644 --- a/src/main/java/org/breedinginsight/services/OntologyService.java +++ b/src/main/java/org/breedinginsight/services/OntologyService.java @@ -15,6 +15,7 @@ import org.breedinginsight.brapps.importer.model.exports.FileType; import org.breedinginsight.brapps.importer.model.imports.DataTypeTranslator; import org.breedinginsight.brapps.importer.model.imports.TermTypeTranslator; +import org.breedinginsight.dao.db.enums.DataType; import org.breedinginsight.dao.db.tables.pojos.ProgramSharedOntologyEntity; import org.breedinginsight.dao.db.tables.pojos.TraitEntity; import org.breedinginsight.daos.ProgramDAO; @@ -509,12 +510,7 @@ public List> processData(List traits) { row.put(TraitFileColumns.SCALE_LOWER_LIMIT.toString(), scale.getValidValueMin()); row.put(TraitFileColumns.SCALE_UPPER_LIMIT.toString(), scale.getValidValueMax()); //SCALE_CATEGORIES - String categoriesAsStr = null; - if(scale.getCategories() != null) { - categoriesAsStr = scale.getCategories().stream() - .map(this::makeCategoryString) - .collect(Collectors.joining("; ")); - } + String categoriesAsStr = makeCategoriesString(scale); row.put(TraitFileColumns.SCALE_CATEGORIES.toString(), categoriesAsStr); } @@ -522,9 +518,21 @@ public List> processData(List traits) { } return processedData; } - private String makeCategoryString(BrAPIScaleValidValuesCategories category){ + + private String makeCategoriesString(Scale scale) { + String categoriesAsStr = null; + if(scale.getCategories() != null && + (scale.getDataType()==DataType.ORDINAL || scale.getDataType() == DataType.NOMINAL) ) { + categoriesAsStr = scale.getCategories().stream() + .map(cat -> makeCategoryString(cat, scale.getDataType()) ) + .collect(Collectors.joining("; ")); + } + return categoriesAsStr; + } + + private String makeCategoryString(BrAPIScaleValidValuesCategories category, DataType scaleClass){ StringBuilder stringBuilder = new StringBuilder( category.getValue() ); - if( StringUtils.isNotBlank( category.getLabel() ) ){ + if( StringUtils.isNotBlank( category.getLabel() ) && scaleClass == DataType.ORDINAL ){ stringBuilder.append("="); stringBuilder.append( category.getLabel() ); }