Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Download the search result as a file in a selected format #2581

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ public Long getId() {
public DatasetFieldType getDatasetFieldType() {
return datasetFieldType;
}

public boolean isOfType(final DatasetFieldType type) {

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This empty line do not fit Dataverse coding style. Should be removed.

return getDatasetFieldType().equals(type);
}

public DatasetVersion getDatasetVersion() {
return datasetVersion;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ public class DatasetFieldType implements Serializable, Comparable<DatasetFieldTy
private int displayOrder;

private String displayFormat;

private boolean exportToFile = false;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant assignment as false is be default.


/** Determines whether an instance of this field type may have multiple values. */
private boolean allowMultiples;
Expand Down Expand Up @@ -184,6 +186,12 @@ public boolean isRequiredInDataverse() {
public String getDisplayFormat() {
return displayFormat;
}


public boolean isExportToFile() {

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty line do not fit overall code style. Please remove it.

return this.exportToFile;
}

public int getDisplayOrder() {
return this.displayOrder;
Expand Down Expand Up @@ -506,6 +514,11 @@ public void setRequiredInDataverse(boolean requiredInDataverse) {
public void setDisplayFormat(String displayFormat) {
this.displayFormat = displayFormat;
}

public void setExportToFile(final boolean exportToFile) {

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty line, as above's. Please remove it.

this.exportToFile = exportToFile;
}

public void setDisplayOrder(int displayOrder) {
this.displayOrder = displayOrder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,18 @@ public List<DatasetField> getDatasetFields() {
public List<DatasetField> getDatasetFieldsOptional() {
return datasetFieldsOptional;
}

public List<DatasetField> getDatasetFieldsAll() {

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty line. Please remove it.

if (getDatasetFieldsOptional().isEmpty()) {
return getDatasetFields();
} else {
final List<DatasetField> result = new ArrayList<DatasetField>(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the point of that final declaration? Seems redundant.
Also this variable seems redundant. Would not be better to inline the return statement? Like:
getDatasetFields().addAll(getDatasetFieldsOptional())?

getDatasetFields());
result.addAll(getDatasetFieldsOptional());
return result;
}
}

public Date getArchiveTime() {
return archiveTime;
Expand Down
8 changes: 8 additions & 0 deletions dataverse-persistence/src/main/resources/Bundle_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,13 @@ dashboard.card.maximumembargo.save.success=Maximum embargo length settings have
dashboard.card.maximumembargo.save.failure=Maximum embargo length settings have not been saved.
dashboard.card.maximumembargo.notSet.header=Not Set
dashboard.card.maximumembargo.notSet.text=No Maximum
dashboard.card.exportsearchresults.header=Export search results
dashboard.card.exportsearchresults.button=Manage
dashboard.card.exportsearchresults.manage=Manage exported metadata
dashboard.card.exportsearchresults.name=Name
dashboard.card.exportsearchresults.desc=Description
dashboard.card.exportsearchresults.exported=Exported to file

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove empty line.


#dasboard-licenses.xhtml
dashboard.license.header=Licenses
Expand Down Expand Up @@ -1052,6 +1059,7 @@ dataverse.results.header=Search results
dataverse.results.btn.addData=Add Data
dataverse.results.btn.addData.newDataverse=New Dataverse
dataverse.results.btn.addData.newDataset=New Dataset
dataverse.results.btn.saveToFile=Safe to file
dataverse.results.dialog.addDataGuest.header=Add Data
dataverse.results.dialog.addDataGuest.msg=You need to <a href="/loginpage.xhtml{0}" title="Log into your Dataverse Account">Log In</a> to create a dataverse or add a dataset.
dataverse.results.dialog.addDataGuest.msg.signup=You need to <a href="/loginpage.xhtml{0}" title="Log into or sign up for your Dataverse Account">Log In/Sign Up</a> to create a dataverse or add a dataset.
Expand Down
7 changes: 7 additions & 0 deletions dataverse-persistence/src/main/resources/Bundle_pl.properties
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,12 @@ dashboard.card.maximumembargo.save.success=Ustawienia maksymalnej d\u0142ugo\u01
dashboard.card.maximumembargo.save.failure=Ustawienia maksymalnej d\u0142ugo\u015Bci embarga nie zosta\u0142y zapisane.
dashboard.card.maximumembargo.notSet.header=Nie ustawiono
dashboard.card.maximumembargo.notSet.text=Brak maksimum
dashboard.card.exportsearchresults.header=Eksport wynik\u00f3w wyszukiwania
dashboard.card.exportsearchresults.button=Zarz\u0105dzaj
dashboard.card.exportsearchresults.manage=Zarz\u0105dzaj eksportowanymi metadanymi
dashboard.card.exportsearchresults.name=Nazwa
dashboard.card.exportsearchresults.desc=Opis
dashboard.card.exportsearchresults.exported=Eksportuj do pliku

#dasboard-licenses.xhtml
dashboard.license.header=Licencje
Expand Down Expand Up @@ -1031,6 +1037,7 @@ dataverse.results.header=Wyniki wyszukiwania
dataverse.results.btn.addData=Dodaj dane
dataverse.results.btn.addData.newDataverse=Nowa kolekcja
dataverse.results.btn.addData.newDataset=Nowy zbi\u00F3r danych
dataverse.results.btn.saveToFile=Zapisz do pliku
dataverse.results.dialog.addDataGuest.header=Dodaj dane
dataverse.results.dialog.addDataGuest.msg=By utworzy\u0107 kolekcj\u0119 lub doda\u0107 zbi\u00F3r danych musisz si\u0119 <a href="/loginpage.xhtml{0}" title="Zaloguj si\u0119 na swoje konto w repozytorium">zalogowa\u0107</a> .
dataverse.results.dialog.addDataGuest.msg.signup=By utworzy\u0107 kolekcj\u0119 lub doda\u0107 zbi\u00F3r danych, musisz si\u0119 <a href="/loginpage.xhtml{0}" title="Zaloguj si\u0119 lub za\u0142\u00F3\u017C konto w repozytorium">zalogowa\u0107/zarejestrowa\u0107</a>.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
alter table datasetfieldtype add column exportToFile boolean not null default false;
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package edu.harvard.iq.dataverse.dashboard;

import static java.lang.Boolean.FALSE;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;
import static org.apache.commons.lang.StringUtils.EMPTY;

import java.io.Serializable;
import java.util.List;

import javax.inject.Inject;
import javax.inject.Named;

import org.omnifaces.cdi.ViewScoped;

import edu.harvard.iq.dataverse.DataverseDao;
import edu.harvard.iq.dataverse.DataverseSession;
import edu.harvard.iq.dataverse.PermissionsWrapper;
import edu.harvard.iq.dataverse.persistence.dataset.DatasetFieldType;
import edu.harvard.iq.dataverse.persistence.dataset.DatasetFieldTypeRepository;
import edu.harvard.iq.dataverse.util.SystemConfig;

@ViewScoped
@Named("ExportSearchResultsPage")
public class DashboardExportSearchResultsPage implements Serializable {

// -------------------------------------------------------------------------
public static class Metadata {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Private? End on the bottom of class?


private final Long id;
private final String title;
private final String description;
private boolean exportable;

// ---------------------------------------------------------------------
private Metadata(final DatasetFieldType fieldType) {

this.id = fieldType.getId();
this.title = fieldType.getTitle();
this.description = fieldType.getDescription();
this.exportable = fieldType.isExportToFile();
}

// ---------------------------------------------------------------------
public boolean isExportable() {

return this.exportable;
}

// ---------------------------------------------------------------------
public void setExportable(final boolean exportable) {

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove empty lines in each case here.

this.exportable = exportable;
}

// ---------------------------------------------------------------------
public Long getId() {

return this.id;
}

// ---------------------------------------------------------------------
public String getTitle() {

return this.title;
}

// ---------------------------------------------------------------------
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whats is the purpose of comments like: // ---------------------------------------------------------------------?
Please remove those.

public String getDescription() {

return this.description;
}
}

// -------------------------------------------------------------------------
private final DataverseSession session;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those fields belongs main class, should be at the top?

private final PermissionsWrapper permissionsWrapper;
private final DataverseDao dataverseDao;
private final SystemConfig systemConfig;
private final DatasetFieldTypeRepository datasetFiledTypeRepo;

private List<Metadata> metadataTypes;

// -------------------------------------------------------------------------
@Inject
public DashboardExportSearchResultsPage(final DataverseSession session,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for constructor should be at the top of class after fields right?

final PermissionsWrapper permissionsWrapper,
final DataverseDao dataverseDao, final SystemConfig systemConfig,
final DatasetFieldTypeRepository datasetFiledTypeRepo) {

this.session = session;
this.permissionsWrapper = permissionsWrapper;
this.dataverseDao = dataverseDao;
this.systemConfig = systemConfig;
this.datasetFiledTypeRepo = datasetFiledTypeRepo;
}

// -------------------------------------------------------------------------
public List<Metadata> getMetadataTypes() {

return this.metadataTypes;
}

// -------------------------------------------------------------------------
public String init() {

if (canEdit()) {
initMetadataTypes();
return EMPTY;
} else {
return this.permissionsWrapper.notAuthorized();
}
}

// -------------------------------------------------------------------------
private void initMetadataTypes() {

this.metadataTypes = this.datasetFiledTypeRepo.findAll().stream()
.map(Metadata::new).sorted(comparing(Metadata::getTitle))
.collect(toList());
}

// -------------------------------------------------------------------------
private boolean canEdit() {

return !this.systemConfig.isReadonlyMode()
&& this.session.getUser().isSuperuser();
}

// -------------------------------------------------------------------------
public String save() {

for (final DatasetFieldType fieldType : this.datasetFiledTypeRepo.findAll()) {
fieldType.setExportToFile(isExportedToFile(fieldType.getId()));
this.datasetFiledTypeRepo.save(fieldType);
}

return EMPTY;
}

// -------------------------------------------------------------------------
private boolean isExportedToFile(final Long id) {

return this.metadataTypes.stream().filter(mt -> mt.getId().equals(id))
.findFirst().map(Metadata::isExportable).orElse(FALSE);
}

// -------------------------------------------------------------------------
public String cancel() {

return "/dashboard.xhtml?faces-redirect=true&dataverseId="
+ this.dataverseDao.findRootDataverse().getId();
}
// -------------------------------------------------------------------------
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package edu.harvard.iq.dataverse.search;

import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.List;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.StreamedContent;

import edu.harvard.iq.dataverse.persistence.dataset.DatasetField;
import edu.harvard.iq.dataverse.persistence.dataset.DatasetFieldType;
import edu.harvard.iq.dataverse.persistence.dataset.DatasetFieldTypeRepository;
import edu.harvard.iq.dataverse.persistence.dataset.DatasetRepository;
import edu.harvard.iq.dataverse.search.response.SolrSearchResult;

public final class CSVResultPrinter {

private final DatasetRepository datasetRepo;
private final List<DatasetFieldType> exportedFields;

private final static CSVFormat format = CSVFormat.DEFAULT.builder().build();

// -------------------------------------------------------------------------
public CSVResultPrinter(final DatasetRepository datasetRepo,
final DatasetFieldTypeRepository datasetFieldTypeRepo) {

this.datasetRepo = datasetRepo;
this.exportedFields = datasetFieldTypeRepo.findAll().stream()
.filter(DatasetFieldType::isExportToFile)
.sorted(comparing(DatasetFieldType::getTitle)).collect(toList());
}

// -------------------------------------------------------------------------
public StreamedContent print(final List<SolrSearchResult> results) {

try {
final ByteArrayOutputStream content = new ByteArrayOutputStream(4000);

try (final CSVPrinter printer = newPrinter(content)) {
printHeaders(printer);
printer.println();

for (final SolrSearchResult result : results) {
printer.print(result.getId());
printer.print(result.getName());
printer.print(result.getTitle());
if (result.isDataset()) {
printMetadata(printer, result);
}
printer.println();
}
}

return DefaultStreamedContent.builder().name("searchResults.csv")
.contentLength(content.size()).contentEncoding("utf-8")
.contentType("text/csv")
.stream(() -> new ByteArrayInputStream(content.toByteArray()))
.build();
} catch (final IOException e) {
throw new RuntimeException(e);
}
}

// -------------------------------------------------------------------------
private void printHeaders(final CSVPrinter printer) throws IOException {

printer.print("Id");
printer.print("Name");
printer.print("Title");
for (final DatasetFieldType type : this.exportedFields) {
printer.print(type.getTitle());
}
}

// -------------------------------------------------------------------------
private void printMetadata(final CSVPrinter printer, final SolrSearchResult result)
throws IOException {

final List<DatasetField> fields = getAllFieldsOfLatestVersionOf(
result.getEntityId());

for (final DatasetFieldType type : this.exportedFields) {
printer.print(get(fields, type));
}
}

// -------------------------------------------------------------------------
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

private List<DatasetField> getAllFieldsOfLatestVersionOf(final Long datasetId) {

return this.datasetRepo.getById(datasetId).getLatestVersion()
.getDatasetFieldsAll();
}

// -------------------------------------------------------------------------
private static String get(final List<DatasetField> fields,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Get of what? Better name please.

final DatasetFieldType type) {

return fields.stream().filter(f -> f.isOfType(type)).findAny()
.map(DatasetField::getDisplayValue).orElse(null);
}

// -------------------------------------------------------------------------
private CSVPrinter newPrinter(final OutputStream output) throws IOException {

return new CSVPrinter(new OutputStreamWriter(output, "utf-8"), format);
}
}
Loading
Loading