Commit 4470f0c0 authored by Matija Obreza's avatar Matija Obreza
Browse files

Merge branch 'ui-19-dashboard-subsets' into 'master'

Ui 19 dashboard subsets

See merge request genesys-pgr/genesys-server!212
parents e7317fe2 b9146d69
......@@ -17,6 +17,7 @@
package org.genesys2.server.api.v1;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
......@@ -27,7 +28,9 @@ import org.genesys.blocks.model.JsonViews;
import org.genesys.catalog.api.FilteredPage;
import org.genesys.catalog.service.ShortFilterService;
import org.genesys2.server.api.ApiBaseController;
import org.genesys2.server.api.model.AccessionHeaderJson;
import org.genesys2.server.model.genesys.Accession;
import org.genesys2.server.model.impl.AccessionIdentifier3;
import org.genesys2.server.service.AccessionService;
import org.genesys2.server.service.ElasticsearchService;
import org.genesys2.server.service.ElasticsearchService.TermResult;
......@@ -162,6 +165,17 @@ public class AccessionController {
return elasticsearchService.termStatisticsAuto(Accession.class, filter, 10, terms.toArray(new String[] {}));
}
/**
* Converts AccessionIdentifiers to UUID
* @param identifiers accession identifiers to lookup in DB
* @return map with UUIDs and related AccessionIdentifiers
*/
@PostMapping(value = "/toUUID", produces = { MediaType.APPLICATION_JSON_VALUE })
public Map<UUID, AccessionIdentifier3> toUUID(@RequestBody List<AccessionHeaderJson> identifiers) {
return accessionService.toUUID(identifiers);
}
/**
* Get term overview for filters
*
......
......@@ -121,9 +121,9 @@ public class SubsetController {
*/
@PostMapping(value = "/list", produces = { MediaType.APPLICATION_JSON_VALUE })
public FilteredPage<Subset> list(@RequestParam(name = "p", required = false, defaultValue = "0") final int page,
@RequestParam(name = "l", required = false, defaultValue = "50") final int pageSize,
@RequestParam(name = "d", required = false, defaultValue = "ASC") final Sort.Direction direction,
@RequestParam(name = "s", required = false, defaultValue = "id") final String[] sort,
@RequestParam(name = "l", required = false, defaultValue = "50") final int pageSize,
@RequestParam(name = "d", required = false, defaultValue = "ASC") final Sort.Direction direction,
@RequestParam(name = "s", required = false, defaultValue = "id") final String[] sort,
@RequestParam(name = "f", required = false) String filterCode,
@RequestBody(required = false) SubsetFilter filter) throws IOException {
......@@ -154,7 +154,7 @@ public class SubsetController {
*
* @param uuid the uuid
* @param version the version
* @param accessionsUuids the accessions UUIDs to be added
* @param accessionIds the accessions UUIDs to be added
* @return the subset
*/
@PostMapping(value = "/add-accessions/{UUID},{version}", produces = { MediaType.APPLICATION_JSON_VALUE })
......@@ -163,4 +163,43 @@ public class SubsetController {
return subsetService.addAccessions(subset, accessionIds);
}
/**
* Loads subset by uuid and version and tries to publish it.
*
* @param uuid subset UUID
* @param version record version
* @return published Subset (admin-only)
*/
@PostMapping(value = "/approve", produces = { MediaType.APPLICATION_JSON_VALUE })
public Subset approveSubset(@RequestParam(value = "uuid", required = true) final UUID uuid, @RequestParam(value = "version", required = true) final int version) {
final Subset subset = subsetService.get(uuid, version);
return subsetService.approveSubset(subset);
}
/**
* Loads subset by uuid and version and send to review.
*
* @param uuid subset UUID
* @param version record version
* @return subset in review state
*/
@PostMapping(value = "/for-review", produces = { MediaType.APPLICATION_JSON_VALUE })
public Subset reviewSubset(@RequestParam(value = "uuid", required = true) final UUID uuid, @RequestParam(value = "version", required = true) final int version) {
final Subset subset = subsetService.get(uuid, version);
return subsetService.reviewSubset(subset);
}
/**
* Loads subset by uuid and version and unpublish it.
*
* @param uuid subset UUID
* @param version record version
* @return unpublished subset
*/
@PostMapping(value = "/reject", produces = { MediaType.APPLICATION_JSON_VALUE })
public Subset rejectSubset(@RequestParam(value = "uuid", required = true) final UUID uuid, @RequestParam(value = "version", required = true) final int version) {
final Subset subset = subsetService.get(uuid, version);
return subsetService.rejectSubset(subset);
}
}
......@@ -20,6 +20,8 @@ import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
......@@ -32,6 +34,7 @@ import javax.persistence.Table;
import org.genesys.blocks.model.SelfCleaning;
import org.genesys.blocks.model.UuidModel;
import org.genesys.blocks.security.model.AclAwareModel;
import org.genesys2.server.model.PublishState;
import org.genesys2.server.model.genesys.AccessionId;
import org.hibernate.annotations.Type;
......@@ -49,10 +52,6 @@ public class Subset extends UuidModel implements AclAwareModel, SelfCleaning {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 7021405309572916429L;
/** The published. */
@Column()
protected boolean published;
/** The title. */
@Column(length = 250, nullable = false)
protected String title;
......@@ -96,6 +95,10 @@ public class Subset extends UuidModel implements AclAwareModel, SelfCleaning {
@Column(name = "accession_count", nullable = false)
private int accessionCount = 0;
/** The publish state. */
@Enumerated(EnumType.ORDINAL)
private PublishState state = PublishState.DRAFT;
/**
* Generate UUID if missing.
*/
......@@ -116,16 +119,25 @@ public class Subset extends UuidModel implements AclAwareModel, SelfCleaning {
* @return the published
*/
public boolean isPublished() {
return published;
return this.state == PublishState.PUBLISHED;
}
/**
* Gets the state.
*
* @return the state
*/
public PublishState getState() {
return state;
}
/**
* Sets the published.
* Sets the publish state.
*
* @param published the new published
* @param state the new publish state
*/
public void setPublished(final boolean published) {
this.published = published;
public void setState(final PublishState state) {
this.state = state;
}
/**
......
......@@ -23,6 +23,7 @@ import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
import org.genesys2.server.exception.NotFoundElement;
import org.genesys2.server.model.PublishState;
import org.genesys2.server.model.genesys.AccessionData;
import org.genesys2.server.model.genesys.AccessionId;
import org.genesys2.server.model.impl.Subset;
......@@ -71,7 +72,7 @@ public class SubsetController extends BaseController {
@RequestParam(value = "results", required = true, defaultValue = "50") int results) throws IOException {
final SubsetFilter filter = new SubsetFilter();
filter.published = true;
filter.state.add(PublishState.PUBLISHED);
final Page<Subset> subsets = subsetService.list(filter, new PageRequest(page - 1, Integer.min(results, maxPageSize), new Sort("id")));
model.addAttribute("pagedData", subsets);
......
......@@ -15,9 +15,12 @@
*/
package org.genesys2.server.service;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.genesys2.server.model.genesys.Accession;
import org.genesys2.server.model.impl.AccessionIdentifier3;
import org.genesys2.server.service.filter.AccessionFilter;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
......@@ -48,4 +51,11 @@ public interface AccessionService {
* @return the by doi
*/
Accession getByDoi(String doi);
/**
* Converts AccessionIdentifiers to UUID
* @param identifiers accession identifiers to lookup in DB
* @return map with UUIDs and related AccessionIdentifiers
*/
Map<UUID, AccessionIdentifier3> toUUID(List<? extends AccessionIdentifier3> identifiers);
}
......@@ -105,4 +105,30 @@ public interface SubsetService {
*/
Subset addAccessions(Subset input, Set<UUID> accessionUuids);
/**
* Puts the subset into the Review state to be reviewed by admin.
* Admin and the user with MANAGE permission - only.
*
* @param subset the subset
* @return subset in REVIEWING state
*/
Subset reviewSubset(Subset subset);
/**
* Unpublishes published subset.
* Admin and the user with MANAGE permission - only.
*
* @param subset the subset
* @return unpublished subset
*/
Subset rejectSubset(Subset subset);
/**
* Validates and publishes an unpublished subset. Admin - only
*
* @param subset the subset
* @return published subset
*/
Subset approveSubset(Subset subset);
}
......@@ -150,6 +150,9 @@ public class AccessionFilter extends UuidModelFilter<AccessionFilter, Accession>
if (CollectionUtil.isNotEmpty(list)) {
and.and(accession.accessionId.lists.any().uuid.in(list));
}
if (CollectionUtil.isNotEmpty(uuid)) {
and.and(accession.accessionId.uuid.in(uuid));
}
// TODO Do we have to change this?
if (sgsv != null) {
and.and(accession.accessionId.duplSite.any().eq("NOR051"));
......
......@@ -21,6 +21,7 @@ import java.util.Set;
import org.genesys.blocks.model.filters.StringFilter;
import org.genesys.blocks.model.filters.UuidModelFilter;
import org.genesys2.server.model.PublishState;
import org.genesys2.server.model.impl.Subset;
import com.querydsl.core.BooleanBuilder;
......@@ -34,9 +35,6 @@ import com.querydsl.core.types.Predicate;
*/
public class SubsetFilter extends UuidModelFilter<SubsetFilter, Subset> {
/** The published. */
public Boolean published;
/** The title. */
public StringFilter title;
......@@ -55,6 +53,9 @@ public class SubsetFilter extends UuidModelFilter<SubsetFilter, Subset> {
/** Institutes. */
public Set<String> institutes;
/** The publish state. */
public Set<PublishState> state;
/**
* Builds the query.
*
......@@ -67,9 +68,6 @@ public class SubsetFilter extends UuidModelFilter<SubsetFilter, Subset> {
if ((institutes != null) && !institutes.isEmpty()) {
and.and(subset.institute.code.in(institutes));
}
if (published != null) {
and.and(subset.published.eq(published));
}
if (title != null) {
and.and(title.buildQuery(subset.title));
}
......@@ -85,6 +83,9 @@ public class SubsetFilter extends UuidModelFilter<SubsetFilter, Subset> {
if ((rights != null) && !rights.isEmpty()) {
and.and(subset.rights.in(rights));
}
if (state != null && !state.isEmpty()) {
and.and(subset.state.in(state));
}
return and;
}
}
......@@ -17,10 +17,14 @@ package org.genesys2.server.service.impl;
import java.util.List;
import java.util.UUID;
import java.util.Map;
import java.util.HashMap;
import java.util.Optional;
import org.genesys2.server.model.genesys.Accession;
import org.genesys2.server.model.genesys.AccessionData;
import org.genesys2.server.model.genesys.AccessionId;
import org.genesys2.server.model.impl.AccessionIdentifier3;
import org.genesys2.server.persistence.AccessionRepository;
import org.genesys2.server.service.AccessionService;
import org.genesys2.server.service.ElasticsearchService;
......@@ -97,6 +101,24 @@ public class AccessionServiceImpl implements AccessionService {
return lazyLoad(accessionRepository.findByDoi(doi));
}
@Override
public Map<UUID, AccessionIdentifier3> toUUID(List<? extends AccessionIdentifier3> identifiers) {
Map<UUID, AccessionIdentifier3> res = new HashMap<>();
List<Accession> foundAccessions = accessionRepository.findById(identifiers);
for(Accession accession: foundAccessions) {
Optional<? extends AccessionIdentifier3> toPut = identifiers.stream()
.filter(id -> id.getAccessionNumber().equals(accession.getAccessionNumber())
&& id.getGenus().equals(accession.getGenus())
&& id.getHoldingInstitute().equals(accession.getInstCode())
).findFirst();
toPut.ifPresent(accessionIdentifier3 -> res.put(accession.getUuid(), accessionIdentifier3));
}
return res;
}
/*
* (non-Javadoc)
* @see
......
......@@ -21,13 +21,17 @@ import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import org.genesys.catalog.exceptions.InvalidApiUsageException;
import org.genesys2.server.exception.NotFoundElement;
import org.genesys2.server.model.PublishState;
import org.genesys2.server.model.UserRole;
import org.genesys2.server.model.genesys.AccessionData;
import org.genesys2.server.model.genesys.AccessionId;
import org.genesys2.server.model.impl.Subset;
import org.genesys2.server.persistence.AccessionRepository;
import org.genesys2.server.persistence.FaoInstituteRepository;
import org.genesys2.server.persistence.SubsetRepository;
import org.genesys2.server.security.SecurityUtils;
import org.genesys2.server.service.SubsetService;
import org.genesys2.server.service.filter.SubsetFilter;
import org.slf4j.Logger;
......@@ -36,6 +40,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
......@@ -59,11 +65,21 @@ public class SubsetServiceImpl implements SubsetService {
@Autowired
private FaoInstituteRepository instituteRepository;
/** The securityUtils. */
@Autowired
private SecurityUtils securityUtils;
/**
* {@inheritDoc}
*/
@Override
public Page<Subset> list(final SubsetFilter filter, final Pageable page) {
return subsetRepository.findAll(filter.buildQuery(), page);
}
/**
* {@inheritDoc}
*/
@Override
@Transactional
public Subset create(final Subset source) {
......@@ -71,6 +87,7 @@ public class SubsetServiceImpl implements SubsetService {
final Subset subset = new Subset();
copyValues(subset, source);
copyAccessions(subset, source.getAccessionIds());
subset.setState(PublishState.DRAFT);
return deepLoad(subsetRepository.save(subset));
}
......@@ -105,7 +122,7 @@ public class SubsetServiceImpl implements SubsetService {
private void copyValues(final Subset target, final Subset source) {
target.setInstitute(instituteRepository.findByCode(source.getWiewsCode()));
target.setTitle(source.getTitle());
target.setPublished(source.isPublished());
target.setState(source.getState());
target.setDescription(source.getDescription());
target.setPublisher(source.getPublisher());
target.setDateCreated(source.getDateCreated());
......@@ -129,6 +146,9 @@ public class SubsetServiceImpl implements SubsetService {
return subset;
}
/**
* {@inheritDoc}
*/
@Override
public Subset loadSubset(final Subset input) {
LOG.debug("Load Subset.");
......@@ -145,12 +165,19 @@ public class SubsetServiceImpl implements SubsetService {
return deepLoad(subset);
}
/**
* {@inheritDoc}
*/
@Override
public Subset get(final UUID uuid) {
return deepLoad(subsetRepository.getByUuid(uuid));
}
/**
* {@inheritDoc}
*/
@Override
@PostAuthorize("hasRole('ADMINISTRATOR') || returnObject==null || returnObject.isPublished() || hasPermission(returnObject, 'read')")
public Subset get(final UUID uuid, final int version) {
final Subset subset = subsetRepository.getByUuidAndVersion(uuid, version);
if (subset == null)
......@@ -158,6 +185,9 @@ public class SubsetServiceImpl implements SubsetService {
return deepLoad(subsetRepository.getByUuidAndVersion(uuid, version));
}
/**
* {@inheritDoc}
*/
@Override
@Transactional
public Subset update(final Subset source) {
......@@ -171,6 +201,9 @@ public class SubsetServiceImpl implements SubsetService {
return deepLoad(subsetRepository.save(subset));
}
/**
* {@inheritDoc}
*/
@Override
@Transactional
public Subset delete(final Subset subset) {
......@@ -179,6 +212,9 @@ public class SubsetServiceImpl implements SubsetService {
return subset;
}
/**
* {@inheritDoc}
*/
@Override
@Transactional
public Subset removeAccessions(final Subset input, final Set<UUID> accessionsUuids) {
......@@ -193,9 +229,14 @@ public class SubsetServiceImpl implements SubsetService {
// Keep accessions that are not in the list
subset.setAccessionIds(subset.getAccessionIds().stream().filter(accessionId -> !uuidsToRemove.contains(accessionId.getUuid())).collect(Collectors.toList()));
subset.setState(PublishState.DRAFT);
return deepLoad(subsetRepository.save(subset));
}
/**
* {@inheritDoc}
*/
@Override
@Transactional
public Subset addAccessions(final Subset input, final Set<UUID> accessionsUuids) {
......@@ -214,7 +255,75 @@ public class SubsetServiceImpl implements SubsetService {
currentAccessions.add(accession.getUuid());
}
}
subset.setState(PublishState.DRAFT);
return deepLoad(subsetRepository.save(subset));
}
/**
* {@inheritDoc}
*/
@Override
@Transactional
@PreAuthorize("hasRole('ADMINISTRATOR')")
public Subset approveSubset(final Subset subset) {
final Subset loaded = subsetRepository.getByUuidAndVersion(subset.getUuid(), subset.getVersion());
if (loaded == null) {
throw new NotFoundElement("No subset with specified uuid and version");
}
if (loaded.isPublished()) {
throw new InvalidApiUsageException("Subset is already published");
}
if (loaded.getState() == PublishState.DRAFT) {
throw new InvalidApiUsageException("Subset should be sent for review before publication");
}
loaded.setState(PublishState.PUBLISHED);
return deepLoad(subsetRepository.save(loaded));
}
/**
* {@inheritDoc}
*/
@Override
@Transactional
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#subset, 'write')")
public Subset reviewSubset(final Subset subset) {
final Subset loaded = subsetRepository.getByUuidAndVersion(subset.getUuid(), subset.getVersion());
if (loaded == null) {
throw new NotFoundElement("No subset with specified uuid and version");
}
if (loaded.isPublished()) {
throw new InvalidApiUsageException("Subset is already published");
}
if (loaded.getState() == PublishState.REVIEWING) {
throw new InvalidApiUsageException("The subset is already under approval");
}
loaded.setState(PublishState.REVIEWING);
return deepLoad(subsetRepository.save(loaded));
}
/**
* {@inheritDoc}
*/
@Override
@Transactional
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#subset, 'administration')")
public Subset rejectSubset(final Subset subset) {
final Subset loaded = subsetRepository.getByUuidAndVersion(subset.getUuid(), subset.getVersion());
if (loaded == null) {
throw new NotFoundElement("No subset with specified uuid and version");
}
if (!securityUtils.hasRole(UserRole.ADMINISTRATOR) && loaded.getState().equals(PublishState.PUBLISHED)) {
long oneDay = 24 * 60 * 60 * 1000;
if (loaded.getLastModifiedDate() != null && loaded.getLastModifiedDate().getTime() <= (System.currentTimeMillis() - oneDay)) {
throw new InvalidApiUsageException("Cannot be un-published. More than 24 hours have passed since the publication.");
}
}
loaded.setState(PublishState.DRAFT);
return deepLoad(subsetRepository.save(loaded));
}
}
......@@ -3739,3 +3739,31 @@ databaseChangeLog:
- sql:
sql: >-
update accession_historic ah right join acce ac on ac.id = ah.id right join accession_geo geo on geo.id = ac.geoId set ah.tileIndex = geo.tileIndex;
- changeSet:
id: 1535727409888-1
author: mborodenko
comment: Add column `state` to subset table
changes:
- addColumn:
columns:
- column:
defaultValueNumeric: 0
constraints:
nullable: false
name: state
type: INT
tableName: subset
- changeSet:
id: 1535727409888-2
author: mborodenko
comment: Migrate data to new column
changes:
- sql:
sql: >-
UPDATE subset SET state = published;
- dropColumn:
tableName: subset
columnName: published
......@@ -30,9 +30,12 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;