Add a new Lock Table that will prevent two or more users to edit simultaneously a single DMP or Dataset (ref #240)
This commit is contained in:
parent
ccea83b4d4
commit
b62c0f7ff5
|
@ -0,0 +1,38 @@
|
||||||
|
package eu.eudat.data.dao.criteria;
|
||||||
|
|
||||||
|
import eu.eudat.data.entities.Lock;
|
||||||
|
import eu.eudat.data.entities.UserInfo;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class LockCriteria extends Criteria<Lock> {
|
||||||
|
|
||||||
|
private UUID target;
|
||||||
|
private UserInfo lockedBy;
|
||||||
|
private Date touchedAt;
|
||||||
|
|
||||||
|
public UUID getTarget() {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTarget(UUID target) {
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo getLockedBy() {
|
||||||
|
return lockedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLockedBy(UserInfo lockedBy) {
|
||||||
|
this.lockedBy = lockedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getTouchedAt() {
|
||||||
|
return touchedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTouchedAt(Date touchedAt) {
|
||||||
|
this.touchedAt = touchedAt;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package eu.eudat.data.dao.entities;
|
||||||
|
|
||||||
|
import eu.eudat.data.dao.DatabaseAccessLayer;
|
||||||
|
import eu.eudat.data.dao.criteria.LockCriteria;
|
||||||
|
import eu.eudat.data.entities.Lock;
|
||||||
|
import eu.eudat.queryable.QueryableList;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public interface LockDao extends DatabaseAccessLayer<Lock, UUID> {
|
||||||
|
|
||||||
|
QueryableList<Lock> getWithCriteria(LockCriteria criteria);
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package eu.eudat.data.dao.entities;
|
||||||
|
|
||||||
|
import eu.eudat.data.dao.DatabaseAccess;
|
||||||
|
import eu.eudat.data.dao.criteria.LockCriteria;
|
||||||
|
import eu.eudat.data.dao.databaselayer.service.DatabaseService;
|
||||||
|
import eu.eudat.data.entities.Lock;
|
||||||
|
import eu.eudat.queryable.QueryableList;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
@Service("LockDao")
|
||||||
|
public class LockDaoImpl extends DatabaseAccess<Lock> implements LockDao {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public LockDaoImpl(DatabaseService<Lock> databaseService) {
|
||||||
|
super(databaseService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryableList<Lock> getWithCriteria(LockCriteria criteria) {
|
||||||
|
QueryableList<Lock> query = this.getDatabaseService().getQueryable(Lock.class);
|
||||||
|
if (criteria.getTouchedAt() != null)
|
||||||
|
query.where((builder, root) -> builder.equal(root.get("touchedAt"), criteria.getTouchedAt()));
|
||||||
|
if (criteria.getLockedBy() != null)
|
||||||
|
query.where(((builder, root) -> builder.equal(root.get("lockedBy"), criteria.getLockedBy())));
|
||||||
|
if (criteria.getTarget() != null)
|
||||||
|
query.where(((builder, root) -> builder.equal(root.get("target"), criteria.getTarget())));
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Lock createOrUpdate(Lock item) {
|
||||||
|
return this.getDatabaseService().createOrUpdate(item, Lock.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Async
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Lock> createOrUpdateAsync(Lock item) {
|
||||||
|
return CompletableFuture.supplyAsync(() -> this.createOrUpdate(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Lock find(UUID id) {
|
||||||
|
return this.getDatabaseService().getQueryable(Lock.class).where(((builder, root) -> builder.equal(root.get("id"), id))).getSingle();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Lock find(UUID id, String hint) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(Lock item) {
|
||||||
|
this.getDatabaseService().delete(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryableList<Lock> asQueryable() {
|
||||||
|
return this.getDatabaseService().getQueryable(Lock.class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
package eu.eudat.data.entities;
|
||||||
|
|
||||||
|
import eu.eudat.data.converters.DateToUTCConverter;
|
||||||
|
import eu.eudat.data.entities.helpers.EntityBinder;
|
||||||
|
import eu.eudat.queryable.queryableentity.DataEntity;
|
||||||
|
import org.hibernate.annotations.GenericGenerator;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "\"Lock\"")
|
||||||
|
public class Lock implements DataEntity<Lock, UUID> {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
@GenericGenerator(name = "uuid2", strategy = "uuid2")
|
||||||
|
@Column(name = "id", updatable = false, nullable = false, columnDefinition = "BINARY(16)")
|
||||||
|
private UUID id;
|
||||||
|
|
||||||
|
@Column(name = "\"Target\"", nullable = false)
|
||||||
|
private UUID target;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.EAGER)
|
||||||
|
@JoinColumn(name = "\"LockedBy\"", nullable = false)
|
||||||
|
private UserInfo lockedBy;
|
||||||
|
|
||||||
|
@Column(name = "\"LockedAt\"")
|
||||||
|
@Convert(converter = DateToUTCConverter.class)
|
||||||
|
private Date lockedAt = new Date();
|
||||||
|
|
||||||
|
@Column(name = "\"TouchedAt\"")
|
||||||
|
@Convert(converter = DateToUTCConverter.class)
|
||||||
|
private Date touchedAt = null;
|
||||||
|
|
||||||
|
|
||||||
|
public UUID getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(UUID id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getTarget() {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTarget(UUID target) {
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo getLockedBy() {
|
||||||
|
return lockedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLockedBy(UserInfo lockedBy) {
|
||||||
|
this.lockedBy = lockedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getLockedAt() {
|
||||||
|
return lockedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLockedAt(Date lockedAt) {
|
||||||
|
this.lockedAt = lockedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getTouchedAt() {
|
||||||
|
return touchedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTouchedAt(Date touchedAt) {
|
||||||
|
this.touchedAt = touchedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Lock entity) {
|
||||||
|
this.touchedAt = entity.touchedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getKeys() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Lock buildFromTuple(List<Tuple> tuple, List<String> fields, String base) {
|
||||||
|
String currentBase = base.isEmpty() ? "" : base + ".";
|
||||||
|
if (fields.contains(currentBase + "id")) this.id = EntityBinder.fromTuple(tuple, currentBase + "id");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -69,6 +69,9 @@ public class UserInfo implements DataEntity<UserInfo, UUID> {
|
||||||
@OneToMany(mappedBy = "userInfo", fetch = FetchType.LAZY)
|
@OneToMany(mappedBy = "userInfo", fetch = FetchType.LAZY)
|
||||||
private Set<UserRole> userRoles = new HashSet<>();
|
private Set<UserRole> userRoles = new HashSet<>();
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "lockedBy", fetch = FetchType.LAZY)
|
||||||
|
private Set<Lock> locks = new HashSet<>();
|
||||||
|
|
||||||
public Set<DMP> getDmps() {
|
public Set<DMP> getDmps() {
|
||||||
return dmps;
|
return dmps;
|
||||||
}
|
}
|
||||||
|
@ -165,6 +168,14 @@ public class UserInfo implements DataEntity<UserInfo, UUID> {
|
||||||
this.userRoles = userRoles;
|
this.userRoles = userRoles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<Lock> getLocks() {
|
||||||
|
return locks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLocks(Set<Lock> locks) {
|
||||||
|
this.locks = locks;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(UserInfo entity) {
|
public void update(UserInfo entity) {
|
||||||
this.name = entity.getName();
|
this.name = entity.getName();
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package eu.eudat.data.query.items.item.lock;
|
||||||
|
|
||||||
|
import eu.eudat.data.dao.criteria.LockCriteria;
|
||||||
|
import eu.eudat.data.entities.Lock;
|
||||||
|
import eu.eudat.data.query.definition.Query;
|
||||||
|
import eu.eudat.queryable.QueryableList;
|
||||||
|
|
||||||
|
public class LockCriteriaRequest extends Query<LockCriteria, Lock> {
|
||||||
|
@Override
|
||||||
|
public QueryableList<Lock> applyCriteria() {
|
||||||
|
QueryableList<Lock> query = this.getQuery();
|
||||||
|
if (this.getCriteria().getTouchedAt() != null)
|
||||||
|
query.where((builder, root) -> builder.equal(root.get("touchedAt"), this.getCriteria().getTouchedAt()));
|
||||||
|
if (this.getCriteria().getLockedBy() != null)
|
||||||
|
query.where(((builder, root) -> builder.equal(root.get("lockedBy"), this.getCriteria().getLockedBy())));
|
||||||
|
if (this.getCriteria().getTarget() != null)
|
||||||
|
query.where(((builder, root) -> builder.equal(root.get("target"), this.getCriteria().getTarget())));
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package eu.eudat.data.query.items.table.lock;
|
||||||
|
|
||||||
|
import eu.eudat.data.dao.criteria.LockCriteria;
|
||||||
|
import eu.eudat.data.entities.Lock;
|
||||||
|
import eu.eudat.data.query.PaginationService;
|
||||||
|
import eu.eudat.data.query.definition.Query;
|
||||||
|
import eu.eudat.data.query.definition.TableQuery;
|
||||||
|
import eu.eudat.queryable.QueryableList;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class LockTableRequest extends TableQuery<LockCriteria, Lock, UUID> {
|
||||||
|
@Override
|
||||||
|
public QueryableList<Lock> applyCriteria() {
|
||||||
|
QueryableList<Lock> query = this.getQuery();
|
||||||
|
if (this.getCriteria().getTouchedAt() != null)
|
||||||
|
query.where((builder, root) -> builder.equal(root.get("touchedAt"), this.getCriteria().getTouchedAt()));
|
||||||
|
if (this.getCriteria().getLockedBy() != null)
|
||||||
|
query.where(((builder, root) -> builder.equal(root.get("lockedBy"), this.getCriteria().getLockedBy())));
|
||||||
|
if (this.getCriteria().getTarget() != null)
|
||||||
|
query.where(((builder, root) -> builder.equal(root.get("target"), this.getCriteria().getTarget())));
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryableList<Lock> applyPaging(QueryableList<Lock> items) {
|
||||||
|
return PaginationService.applyPaging(items, this);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
package eu.eudat.query;
|
||||||
|
|
||||||
|
import eu.eudat.data.dao.DatabaseAccessLayer;
|
||||||
|
import eu.eudat.data.entities.Lock;
|
||||||
|
import eu.eudat.data.entities.UserInfo;
|
||||||
|
import eu.eudat.queryable.QueryableList;
|
||||||
|
import eu.eudat.queryable.types.FieldSelectionType;
|
||||||
|
import eu.eudat.queryable.types.SelectionField;
|
||||||
|
|
||||||
|
import javax.persistence.criteria.Subquery;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class LockQuery extends Query<Lock, UUID> {
|
||||||
|
|
||||||
|
private UUID id;
|
||||||
|
private UUID target;
|
||||||
|
private UserQuery userQuery;
|
||||||
|
private Date touchedAt;
|
||||||
|
|
||||||
|
public UUID getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(UUID id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getTarget() {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTarget(UUID target) {
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserQuery getUserQuery() {
|
||||||
|
return userQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserQuery(UserQuery userQuery) {
|
||||||
|
this.userQuery = userQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getTouchedAt() {
|
||||||
|
return touchedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTouchedAt(Date touchedAt) {
|
||||||
|
this.touchedAt = touchedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LockQuery(DatabaseAccessLayer<Lock, UUID> databaseAccessLayer, List<String> selectionFields) {
|
||||||
|
super(databaseAccessLayer, selectionFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LockQuery(DatabaseAccessLayer<Lock, UUID> databaseAccessLayer) {
|
||||||
|
super(databaseAccessLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryableList<Lock> getQuery() {
|
||||||
|
QueryableList<Lock> query = this.databaseAccessLayer.asQueryable();
|
||||||
|
if (this.id != null) {
|
||||||
|
query.where((builder, root) -> builder.equal(root.get("id"), this.id));
|
||||||
|
}
|
||||||
|
if (this.target != null) {
|
||||||
|
query.where(((builder, root) -> builder.equal(root.get("target"), this.target)));
|
||||||
|
}
|
||||||
|
if (this.userQuery != null) {
|
||||||
|
Subquery<UserInfo> userSubQuery = this.userQuery.getQuery().query(Arrays.asList(new SelectionField(FieldSelectionType.FIELD, "id")));
|
||||||
|
query.where((builder, root) -> root.get("lockedBy").get("id").in(userSubQuery));
|
||||||
|
}
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package eu.eudat.controllers;
|
||||||
|
|
||||||
|
import com.sun.org.apache.xpath.internal.operations.Bool;
|
||||||
|
import eu.eudat.logic.managers.LockManager;
|
||||||
|
import eu.eudat.models.data.dmp.DataManagementPlan;
|
||||||
|
import eu.eudat.models.data.helpers.responses.ResponseItem;
|
||||||
|
import eu.eudat.models.data.lock.Lock;
|
||||||
|
import eu.eudat.models.data.security.Principal;
|
||||||
|
import eu.eudat.types.ApiMessageCode;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@CrossOrigin
|
||||||
|
@RequestMapping(value = {"/api/lock/"})
|
||||||
|
public class LockController {
|
||||||
|
|
||||||
|
private LockManager lockManager;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public LockController(LockManager lockManager) {
|
||||||
|
this.lockManager = lockManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@RequestMapping(method = RequestMethod.GET, path = "target/status/{id}")
|
||||||
|
public @ResponseBody ResponseEntity<ResponseItem<Boolean>> getLocked(@PathVariable String id, Principal principal) throws Exception {
|
||||||
|
boolean locked = this.lockManager.isLocked(id, principal);
|
||||||
|
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<Boolean>().status(ApiMessageCode.SUCCESS_MESSAGE).message("locked").payload(locked));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@RequestMapping(method = RequestMethod.DELETE, path = "target/unlock/{id}")
|
||||||
|
public @ResponseBody ResponseEntity<ResponseItem<String>> unlock(@PathVariable String id, Principal principal) throws Exception {
|
||||||
|
this.lockManager.unlock(id, principal);
|
||||||
|
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<String>().status(ApiMessageCode.SUCCESS_MESSAGE).message("Created").payload("Lock Removed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
|
||||||
|
public @ResponseBody ResponseEntity<ResponseItem<UUID>> createOrUpdate(@RequestBody Lock lock, Principal principal) throws Exception {
|
||||||
|
eu.eudat.data.entities.Lock result = this.lockManager.createOrUpdate(lock, principal);
|
||||||
|
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<UUID>().status(ApiMessageCode.SUCCESS_MESSAGE).message("Created").payload(result.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(method = RequestMethod.GET, path = "target/{id}")
|
||||||
|
public @ResponseBody ResponseEntity<ResponseItem<Lock>> getSingle(@PathVariable String id, Principal principal) throws Exception {
|
||||||
|
Lock lock = this.lockManager.getFromTarget(id, principal);
|
||||||
|
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<Lock>().status(ApiMessageCode.NO_MESSAGE).payload(lock));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
package eu.eudat.logic.managers;
|
||||||
|
|
||||||
|
import eu.eudat.data.dao.criteria.LockCriteria;
|
||||||
|
import eu.eudat.logic.services.ApiContext;
|
||||||
|
import eu.eudat.models.data.lock.Lock;
|
||||||
|
import eu.eudat.models.data.security.Principal;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.persistence.NoResultException;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class LockManager {
|
||||||
|
|
||||||
|
private ApiContext apiContext;
|
||||||
|
private Environment environment;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public LockManager(ApiContext apiContext, Environment environment) {
|
||||||
|
this.apiContext = apiContext;
|
||||||
|
this.environment = environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public eu.eudat.data.entities.Lock createOrUpdate(Lock lock, Principal principal) throws Exception {
|
||||||
|
if (lock.getId() != null) {
|
||||||
|
try {
|
||||||
|
eu.eudat.data.entities.Lock entity = this.apiContext.getOperationsContext().getDatabaseRepository().getLockDao().find(lock.getId());
|
||||||
|
if (entity != null) {
|
||||||
|
if (!entity.getLockedBy().getId().equals(principal.getId())) {
|
||||||
|
throw new Exception("Is not locked by that user");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch(NoResultException e) {
|
||||||
|
return new eu.eudat.data.entities.Lock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eu.eudat.data.entities.Lock newLock = lock.toDataModel();
|
||||||
|
newLock = this.apiContext.getOperationsContext().getDatabaseRepository().getLockDao().createOrUpdate(newLock);
|
||||||
|
|
||||||
|
return newLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLocked(String targetId, Principal principal) throws Exception {
|
||||||
|
LockCriteria criteria = new LockCriteria();
|
||||||
|
criteria.setTarget(UUID.fromString(targetId));
|
||||||
|
Long availableLocks = this.apiContext.getOperationsContext().getDatabaseRepository().getLockDao().getWithCriteria(criteria).count();
|
||||||
|
if (availableLocks > 0) {
|
||||||
|
eu.eudat.data.entities.Lock lock = this.apiContext.getOperationsContext().getDatabaseRepository().getLockDao().getWithCriteria(criteria).getSingle();
|
||||||
|
if (lock.getLockedBy().getId().equals(principal.getId())) {
|
||||||
|
lock.setTouchedAt(new Date());
|
||||||
|
this.createOrUpdate(new Lock().fromDataModel(lock), principal);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (new Date().getTime() - lock.getTouchedAt().getTime() > environment.getProperty("database.lock-fail-interval", Integer.class)) {
|
||||||
|
this.forceUnlock(targetId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void forceUnlock(String targetId) throws Exception {
|
||||||
|
LockCriteria criteria = new LockCriteria();
|
||||||
|
criteria.setTarget(UUID.fromString(targetId));
|
||||||
|
Long availableLocks = this.apiContext.getOperationsContext().getDatabaseRepository().getLockDao().getWithCriteria(criteria).count();
|
||||||
|
if (availableLocks > 0) {
|
||||||
|
eu.eudat.data.entities.Lock lock = this.apiContext.getOperationsContext().getDatabaseRepository().getLockDao().getWithCriteria(criteria).getSingle();
|
||||||
|
this.apiContext.getOperationsContext().getDatabaseRepository().getLockDao().delete(lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unlock(String targetId, Principal principal) throws Exception {
|
||||||
|
LockCriteria criteria = new LockCriteria();
|
||||||
|
criteria.setTarget(UUID.fromString(targetId));
|
||||||
|
Long availableLocks = this.apiContext.getOperationsContext().getDatabaseRepository().getLockDao().getWithCriteria(criteria).count();
|
||||||
|
if (availableLocks > 0) {
|
||||||
|
eu.eudat.data.entities.Lock lock = this.apiContext.getOperationsContext().getDatabaseRepository().getLockDao().getWithCriteria(criteria).getSingle();
|
||||||
|
if (!lock.getLockedBy().getId().equals(principal.getId())) {
|
||||||
|
throw new Exception("Only the user who created that lock can delete it");
|
||||||
|
}
|
||||||
|
this.apiContext.getOperationsContext().getDatabaseRepository().getLockDao().delete(lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Lock getFromTarget(String targetId, Principal principal) throws Exception {
|
||||||
|
LockCriteria criteria = new LockCriteria();
|
||||||
|
criteria.setTarget(UUID.fromString(targetId));
|
||||||
|
Long availableLocks = this.apiContext.getOperationsContext().getDatabaseRepository().getLockDao().getWithCriteria(criteria).count();
|
||||||
|
if (availableLocks > 0) {
|
||||||
|
eu.eudat.data.entities.Lock lock = this.apiContext.getOperationsContext().getDatabaseRepository().getLockDao().getWithCriteria(criteria).getSingle();
|
||||||
|
if (!lock.getLockedBy().getId().equals(principal.getId())) {
|
||||||
|
throw new Exception("Only the user who created that lock can access it");
|
||||||
|
}
|
||||||
|
return new Lock().fromDataModel(lock);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,5 +52,7 @@ public interface DatabaseRepository {
|
||||||
|
|
||||||
FunderDao getFunderDao();
|
FunderDao getFunderDao();
|
||||||
|
|
||||||
|
LockDao getLockDao();
|
||||||
|
|
||||||
<T> void detachEntity(T entity);
|
<T> void detachEntity(T entity);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ public class DatabaseRepositoryImpl implements DatabaseRepository {
|
||||||
private LoginConfirmationEmailDao loginConfirmationEmailDao;
|
private LoginConfirmationEmailDao loginConfirmationEmailDao;
|
||||||
private ProjectDao projectDao;
|
private ProjectDao projectDao;
|
||||||
private FunderDao funderDao;
|
private FunderDao funderDao;
|
||||||
|
private LockDao lockDao;
|
||||||
|
|
||||||
private EntityManager entityManager;
|
private EntityManager entityManager;
|
||||||
|
|
||||||
|
@ -273,6 +274,16 @@ public class DatabaseRepositoryImpl implements DatabaseRepository {
|
||||||
this.funderDao = funderDao;
|
this.funderDao = funderDao;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void setLockDao(LockDao lockDao) {
|
||||||
|
this.lockDao = lockDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LockDao getLockDao() {
|
||||||
|
return lockDao;
|
||||||
|
}
|
||||||
|
|
||||||
public <T> void detachEntity(T entity) {
|
public <T> void detachEntity(T entity) {
|
||||||
this.entityManager.detach(entity);
|
this.entityManager.detach(entity);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
package eu.eudat.models.data.lock;
|
||||||
|
|
||||||
|
import eu.eudat.models.DataModel;
|
||||||
|
import eu.eudat.models.data.userinfo.UserInfo;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class Lock implements DataModel<eu.eudat.data.entities.Lock, Lock> {
|
||||||
|
private UUID id;
|
||||||
|
private UUID target;
|
||||||
|
private UserInfo lockedBy;
|
||||||
|
private Date lockedAt;
|
||||||
|
private Date touchedAt;
|
||||||
|
|
||||||
|
public UUID getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(UUID id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getTarget() {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTarget(UUID target) {
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo getLockedBy() {
|
||||||
|
return lockedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLockedBy(UserInfo lockedBy) {
|
||||||
|
this.lockedBy = lockedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getLockedAt() {
|
||||||
|
return lockedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLockedAt(Date lockedAt) {
|
||||||
|
this.lockedAt = lockedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getTouchedAt() {
|
||||||
|
return touchedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTouchedAt(Date touchedAt) {
|
||||||
|
this.touchedAt = touchedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Lock fromDataModel(eu.eudat.data.entities.Lock entity) {
|
||||||
|
this.id = entity.getId();
|
||||||
|
this.target = entity.getTarget();
|
||||||
|
this.lockedBy = new UserInfo().fromDataModel(entity.getLockedBy());
|
||||||
|
this.lockedAt = entity.getLockedAt();
|
||||||
|
this.touchedAt = entity.getTouchedAt();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public eu.eudat.data.entities.Lock toDataModel() throws Exception {
|
||||||
|
eu.eudat.data.entities.Lock entity = new eu.eudat.data.entities.Lock();
|
||||||
|
entity.setId(this.getId());
|
||||||
|
entity.setTarget(this.getTarget());
|
||||||
|
entity.setLockedAt(this.getLockedAt());
|
||||||
|
entity.setTouchedAt(this.getTouchedAt());
|
||||||
|
entity.setLockedBy(this.getLockedBy().toDataModel());
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHint() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -107,8 +107,17 @@ public class UserInfo implements DataModel<eu.eudat.data.entities.UserInfo, User
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public eu.eudat.data.entities.UserInfo toDataModel() {
|
public eu.eudat.data.entities.UserInfo toDataModel() {
|
||||||
// TODO Auto-generated method stub
|
eu.eudat.data.entities.UserInfo entity = new eu.eudat.data.entities.UserInfo();
|
||||||
return null;
|
entity.setId(this.getId());
|
||||||
|
entity.setEmail(this.getEmail());
|
||||||
|
entity.setName(this.getName());
|
||||||
|
entity.setAdditionalinfo(this.getAdditionalinfo());
|
||||||
|
entity.setAuthorization_level(this.getAuthorization_level());
|
||||||
|
entity.setCreated(this.getCreated());
|
||||||
|
entity.setLastloggedin(this.getLastloggedin());
|
||||||
|
entity.setUsertype(this.getUsertype());
|
||||||
|
entity.setVerified_email(this.getVerified_email());
|
||||||
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -75,3 +75,4 @@ http-logger.delay = 10
|
||||||
##########################PERISTENCE##########################################
|
##########################PERISTENCE##########################################
|
||||||
#############GENERIC DATASOURCE CONFIGURATIONS#########
|
#############GENERIC DATASOURCE CONFIGURATIONS#########
|
||||||
database.driver-class-name=org.postgresql.Driver
|
database.driver-class-name=org.postgresql.Driver
|
||||||
|
database.lock-fail-interval=120000
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
CREATE TABLE public."Lock" (
|
||||||
|
id uuid NOT NULL,
|
||||||
|
"Target" uuid NOT NULL,
|
||||||
|
"LockedBy" uuid NOT NULL,
|
||||||
|
"LockedAt" timestamp NOT NULL,
|
||||||
|
"TouchedAt" timestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public."Lock"
|
||||||
|
ADD CONSTRAINT "Lock_pkey" PRIMARY KEY (id);
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public."Lock"
|
||||||
|
ADD CONSTRAINT "LockUserReference" FOREIGN KEY ("LockedBy") REFERENCES public."UserInfo"(id);
|
||||||
|
|
|
@ -37,6 +37,7 @@ import { FunderService } from './services/funder/funder.service';
|
||||||
import { ContactSupportService } from './services/contact-support/contact-support.service';
|
import { ContactSupportService } from './services/contact-support/contact-support.service';
|
||||||
import { LanguageService } from './services/language/language.service';
|
import { LanguageService } from './services/language/language.service';
|
||||||
import { AdminAuthGuard } from './admin-auth-guard.service';
|
import { AdminAuthGuard } from './admin-auth-guard.service';
|
||||||
|
import { LockService } from './services/lock/lock.service';
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// This is shared module that provides all the services. Its imported only once on the AppModule.
|
// This is shared module that provides all the services. Its imported only once on the AppModule.
|
||||||
|
@ -93,7 +94,8 @@ export class CoreServiceModule {
|
||||||
OrganisationService,
|
OrganisationService,
|
||||||
EmailConfirmationService,
|
EmailConfirmationService,
|
||||||
ContactSupportService,
|
ContactSupportService,
|
||||||
LanguageService
|
LanguageService,
|
||||||
|
LockService
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { Guid } from '@common/types/guid';
|
||||||
|
import { UserInfoListingModel } from '../user/user-info-listing';
|
||||||
|
|
||||||
|
export class LockModel {
|
||||||
|
id: Guid;
|
||||||
|
target: Guid;
|
||||||
|
lockedBy: UserInfoListingModel;
|
||||||
|
lockedAt: Date;
|
||||||
|
touchedAt: Date;
|
||||||
|
|
||||||
|
constructor(targetId: string, lockedBy: any) {
|
||||||
|
this.lockedAt = new Date();
|
||||||
|
this.touchedAt = new Date();
|
||||||
|
this.target = Guid.parse(targetId);
|
||||||
|
this.lockedBy = lockedBy;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { HttpHeaders, HttpClient } from '@angular/common/http';
|
||||||
|
import { BaseHttpService } from '../http/base-http.service';
|
||||||
|
import { environment } from 'environments/environment';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { LockModel } from '@app/core/model/lock/lock.model';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class LockService {
|
||||||
|
|
||||||
|
private actionUrl: string;
|
||||||
|
private headers = new HttpHeaders();
|
||||||
|
|
||||||
|
constructor(private http: BaseHttpService, private httpClient: HttpClient) {
|
||||||
|
this.actionUrl = environment.Server + 'lock/';
|
||||||
|
}
|
||||||
|
|
||||||
|
checkLockStatus(id: string): Observable<boolean> {
|
||||||
|
return this.http.get(`${this.actionUrl}target/status/${id}`, {headers: this.headers});
|
||||||
|
}
|
||||||
|
|
||||||
|
unlockTarget(id: string): Observable<any> {
|
||||||
|
return this.http.delete(`${this.actionUrl}target/unlock/${id}`, {headers: this.headers});
|
||||||
|
}
|
||||||
|
|
||||||
|
getSingle(id: string): Observable<LockModel> {
|
||||||
|
return this.http.get(`${this.actionUrl}target/${id}`, {headers: this.headers});
|
||||||
|
}
|
||||||
|
|
||||||
|
createOrUpdate(lock: LockModel): Observable<string> {
|
||||||
|
return this.http.post(`${this.actionUrl}`, lock, {headers: this.headers});
|
||||||
|
}
|
||||||
|
}
|
|
@ -107,15 +107,16 @@
|
||||||
</mat-tab-group>
|
</mat-tab-group>
|
||||||
|
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<mat-icon *ngIf="hasNotReversableStatus()" color="accent" class="align-self-center mr-1">info_outlined</mat-icon>
|
<mat-icon *ngIf="hasNotReversableStatus() || lockStatus" color="accent" class="align-self-center mr-1">info_outlined</mat-icon>
|
||||||
<div *ngIf="hasNotReversableStatus()" class="align-self-center mr-3">{{'DATASET-WIZARD.ACTIONS.INFO' | translate}}</div>
|
<div *ngIf="hasNotReversableStatus()" class="align-self-center mr-3">{{'DATASET-WIZARD.ACTIONS.INFO' | translate}}</div>
|
||||||
|
<div *ngIf="lockStatus" class="align-self-center mr-3">{{'DATASET-WIZARD.ACTIONS.LOCK' | translate}}</div>
|
||||||
<button mat-raised-button (click)="cancel()" type="button" class="cancelButton" color="primary">
|
<button mat-raised-button (click)="cancel()" type="button" class="cancelButton" color="primary">
|
||||||
{{'DMP-EDITOR.ACTIONS.CANCEL' | translate}}
|
{{'DMP-EDITOR.ACTIONS.CANCEL' | translate}}
|
||||||
</button>
|
</button>
|
||||||
<button *ngIf="datasetWizardModel.status == 0 || isNew" mat-raised-button class="saveButton" color="primary" (click)="save();" type="button">{{ 'DATASET-WIZARD.ACTIONS.SAVE' | translate }}</button>
|
<button *ngIf="(datasetWizardModel.status == 0 || isNew) && !lockStatus" mat-raised-button class="saveButton" color="primary" (click)="save();" type="button">{{ 'DATASET-WIZARD.ACTIONS.SAVE' | translate }}</button>
|
||||||
<button *ngIf="datasetWizardModel.status == 0 || isNew" mat-raised-button class="finalizeButton" color="primary" (click)="saveFinalize();" type="button">{{ 'DATASET-WIZARD.ACTIONS.FINALIZE' | translate }}</button>
|
<button *ngIf="(datasetWizardModel.status == 0 || isNew) && !lockStatus" mat-raised-button class="finalizeButton" color="primary" (click)="saveFinalize();" type="button">{{ 'DATASET-WIZARD.ACTIONS.FINALIZE' | translate }}</button>
|
||||||
<div class="fill-space"></div>
|
<div class="fill-space"></div>
|
||||||
<button *ngIf="hasReversableStatus()" mat-raised-button class="reverseButton" color="primary" (click)="reverse()" type="button">{{ 'DATASET-WIZARD.ACTIONS.REVERSE' | translate }}</button>
|
<button *ngIf="hasReversableStatus() && !lockStatus" mat-raised-button class="reverseButton" color="primary" (click)="reverse()" type="button">{{ 'DATASET-WIZARD.ACTIONS.REVERSE' | translate }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -31,8 +31,15 @@ import { ValidationErrorModel } from '@common/forms/validation/error-model/valid
|
||||||
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
|
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import * as FileSaver from 'file-saver';
|
import * as FileSaver from 'file-saver';
|
||||||
import { Observable, of as observableOf } from 'rxjs';
|
import { Observable, of as observableOf, interval } from 'rxjs';
|
||||||
import { catchError, map, takeUntil } from 'rxjs/operators';
|
import { catchError, map, takeUntil } from 'rxjs/operators';
|
||||||
|
import { LockService } from '@app/core/services/lock/lock.service';
|
||||||
|
import { Location } from '@angular/common';
|
||||||
|
import { LockModel } from '@app/core/model/lock/lock.model';
|
||||||
|
import { Guid } from '@common/types/guid';
|
||||||
|
import { isNullOrUndefined } from 'util';
|
||||||
|
import { AuthService } from '@app/core/services/auth/auth.service';
|
||||||
|
import { environment } from 'environments/environment';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-dataset-wizard-component',
|
selector: 'app-dataset-wizard-component',
|
||||||
|
@ -61,6 +68,8 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr
|
||||||
profileUpdateId: string;
|
profileUpdateId: string;
|
||||||
downloadDocumentId: string;
|
downloadDocumentId: string;
|
||||||
isLinear = false;
|
isLinear = false;
|
||||||
|
lock: LockModel;
|
||||||
|
lockStatus: Boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private datasetWizardService: DatasetWizardService,
|
private datasetWizardService: DatasetWizardService,
|
||||||
|
@ -73,7 +82,10 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr
|
||||||
public dialog: MatDialog,
|
public dialog: MatDialog,
|
||||||
public externalSourcesConfigurationService: ExternalSourcesConfigurationService,
|
public externalSourcesConfigurationService: ExternalSourcesConfigurationService,
|
||||||
private uiNotificationService: UiNotificationService,
|
private uiNotificationService: UiNotificationService,
|
||||||
private formService: FormService
|
private formService: FormService,
|
||||||
|
private lockService: LockService,
|
||||||
|
private location: Location,
|
||||||
|
private authService: AuthService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
@ -112,6 +124,8 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr
|
||||||
this.datasetWizardService.getSingle(this.itemId)
|
this.datasetWizardService.getSingle(this.itemId)
|
||||||
.pipe(takeUntil(this._destroyed))
|
.pipe(takeUntil(this._destroyed))
|
||||||
.subscribe(data => {
|
.subscribe(data => {
|
||||||
|
this.lockService.checkLockStatus(data.id).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => {
|
||||||
|
this.lockStatus = lockStatus;
|
||||||
this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(data);
|
this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(data);
|
||||||
this.needsUpdate();
|
this.needsUpdate();
|
||||||
this.breadCrumbs = observableOf([
|
this.breadCrumbs = observableOf([
|
||||||
|
@ -129,14 +143,23 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr
|
||||||
}]);
|
}]);
|
||||||
this.formGroup = this.datasetWizardModel.buildForm();
|
this.formGroup = this.datasetWizardModel.buildForm();
|
||||||
this.editMode = this.datasetWizardModel.status === DatasetStatus.Draft;
|
this.editMode = this.datasetWizardModel.status === DatasetStatus.Draft;
|
||||||
if (this.datasetWizardModel.status === DatasetStatus.Finalized) {
|
if (this.datasetWizardModel.status === DatasetStatus.Finalized || lockStatus) {
|
||||||
this.formGroup.disable();
|
this.formGroup.disable();
|
||||||
this.viewOnly = true;
|
this.viewOnly = true;
|
||||||
}
|
}
|
||||||
|
if (!lockStatus) {
|
||||||
|
this.lock = new LockModel(data.id, this.authService.current());
|
||||||
|
|
||||||
|
this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => {
|
||||||
|
this.lock.id = Guid.parse(result);
|
||||||
|
interval(environment.lockInterval).pipe(takeUntil(this._destroyed)).subscribe(() => this.pumpLock());
|
||||||
|
});
|
||||||
|
}
|
||||||
// if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Dataset edit like DMP.
|
// if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Dataset edit like DMP.
|
||||||
this.loadDatasetProfiles();
|
this.loadDatasetProfiles();
|
||||||
this.registerFormListeners();
|
this.registerFormListeners();
|
||||||
// this.availableProfiles = this.datasetWizardModel.dmp.profiles;
|
// this.availableProfiles = this.datasetWizardModel.dmp.profiles;
|
||||||
|
})
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-WIZARD.MESSAGES.DATASET-NOT-FOUND'), SnackBarNotificationLevel.Error);
|
this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-WIZARD.MESSAGES.DATASET-NOT-FOUND'), SnackBarNotificationLevel.Error);
|
||||||
|
@ -184,6 +207,8 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr
|
||||||
this.datasetWizardService.getSingle(this.itemId)
|
this.datasetWizardService.getSingle(this.itemId)
|
||||||
.pipe(takeUntil(this._destroyed))
|
.pipe(takeUntil(this._destroyed))
|
||||||
.subscribe(data => {
|
.subscribe(data => {
|
||||||
|
this.lockService.checkLockStatus(data.id).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => {
|
||||||
|
this.lockStatus = lockStatus;
|
||||||
this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(data);
|
this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(data);
|
||||||
this.formGroup = this.datasetWizardModel.buildForm();
|
this.formGroup = this.datasetWizardModel.buildForm();
|
||||||
this.formGroup.get('id').setValue(null);
|
this.formGroup.get('id').setValue(null);
|
||||||
|
@ -216,13 +241,22 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
this.editMode = this.datasetWizardModel.status === DatasetStatus.Draft;
|
this.editMode = this.datasetWizardModel.status === DatasetStatus.Draft;
|
||||||
if (this.datasetWizardModel.status === DatasetStatus.Finalized) {
|
if (this.datasetWizardModel.status === DatasetStatus.Finalized || lockStatus) {
|
||||||
this.formGroup.disable();
|
this.formGroup.disable();
|
||||||
this.viewOnly = true;
|
this.viewOnly = true;
|
||||||
}
|
}
|
||||||
|
if (!lockStatus) {
|
||||||
|
this.lock = new LockModel(data.id, this.authService.current());
|
||||||
|
|
||||||
|
this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => {
|
||||||
|
this.lock.id = Guid.parse(result);
|
||||||
|
interval(environment.lockInterval).pipe(takeUntil(this._destroyed)).subscribe(() => this.pumpLock());
|
||||||
|
});
|
||||||
|
}
|
||||||
// if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Dataset edit like DMP.
|
// if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Dataset edit like DMP.
|
||||||
this.loadDatasetProfiles();
|
this.loadDatasetProfiles();
|
||||||
// this.availableProfiles = data.dmp.profiles;
|
// this.availableProfiles = data.dmp.profiles;
|
||||||
|
})
|
||||||
});
|
});
|
||||||
} else if (this.publicId != null) { // For Finalized -> Public Datasets
|
} else if (this.publicId != null) { // For Finalized -> Public Datasets
|
||||||
this.isNew = false;
|
this.isNew = false;
|
||||||
|
@ -235,19 +269,30 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr
|
||||||
}))
|
}))
|
||||||
.subscribe(data => {
|
.subscribe(data => {
|
||||||
if (data) {
|
if (data) {
|
||||||
|
this.lockService.checkLockStatus(data.id).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => {
|
||||||
|
this.lockStatus = lockStatus;
|
||||||
this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(data);
|
this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(data);
|
||||||
this.formGroup = this.datasetWizardModel.buildForm();
|
this.formGroup = this.datasetWizardModel.buildForm();
|
||||||
this.editMode = this.datasetWizardModel.status === DatasetStatus.Draft;
|
this.editMode = this.datasetWizardModel.status === DatasetStatus.Draft;
|
||||||
if (this.datasetWizardModel.status === DatasetStatus.Finalized) {
|
if (this.datasetWizardModel.status === DatasetStatus.Finalized || lockStatus) {
|
||||||
this.formGroup.disable();
|
this.formGroup.disable();
|
||||||
this.viewOnly = true;
|
this.viewOnly = true;
|
||||||
}
|
}
|
||||||
|
if (!lockStatus) {
|
||||||
|
this.lock = new LockModel(data.id, this.authService.current());
|
||||||
|
|
||||||
|
this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => {
|
||||||
|
this.lock.id = Guid.parse(result);
|
||||||
|
interval(environment.lockInterval).pipe(takeUntil(this._destroyed)).subscribe(() => this.pumpLock());
|
||||||
|
});
|
||||||
|
}
|
||||||
this.formGroup.get('dmp').setValue(this.datasetWizardModel.dmp);
|
this.formGroup.get('dmp').setValue(this.datasetWizardModel.dmp);
|
||||||
this.loadDatasetProfiles();
|
this.loadDatasetProfiles();
|
||||||
const breadcrumbs = [];
|
const breadcrumbs = [];
|
||||||
breadcrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC DATASETS'), url: '/explore' });
|
breadcrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC DATASETS'), url: '/explore' });
|
||||||
breadcrumbs.push({ parentComponentName: null, label: this.datasetWizardModel.label, url: '/datasets/publicEdit/' + this.datasetWizardModel.id });
|
breadcrumbs.push({ parentComponentName: null, label: this.datasetWizardModel.label, url: '/datasets/publicEdit/' + this.datasetWizardModel.id });
|
||||||
this.breadCrumbs = observableOf(breadcrumbs);
|
this.breadCrumbs = observableOf(breadcrumbs);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.publicMode = true;
|
this.publicMode = true;
|
||||||
|
@ -284,6 +329,7 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr
|
||||||
// if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Dataset edit like DMP.
|
// if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Dataset edit like DMP.
|
||||||
this.loadDatasetProfiles();
|
this.loadDatasetProfiles();
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.datasetWizardModel = new DatasetWizardEditorModel();
|
this.datasetWizardModel = new DatasetWizardEditorModel();
|
||||||
this.formGroup = this.datasetWizardModel.buildForm();
|
this.formGroup = this.datasetWizardModel.buildForm();
|
||||||
|
@ -368,7 +414,21 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr
|
||||||
}
|
}
|
||||||
|
|
||||||
public cancel(): void {
|
public cancel(): void {
|
||||||
this.router.navigate(['/datasets']);
|
if (!isNullOrUndefined(this.lock)) {
|
||||||
|
this.lockService.unlockTarget(this.datasetWizardModel.id).pipe(takeUntil(this._destroyed)).subscribe(
|
||||||
|
complete => {
|
||||||
|
this.router.navigate(['/datasets']);
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
this.formGroup.get('status').setValue(DmpStatus.Draft);
|
||||||
|
this.onCallbackError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
this.router.navigate(['/datasets']);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getDatasetDisplay(item: any): string {
|
getDatasetDisplay(item: any): string {
|
||||||
|
@ -679,7 +739,7 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -706,4 +766,15 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr
|
||||||
onStepFound(linkToScroll: LinkToScroll) {
|
onStepFound(linkToScroll: LinkToScroll) {
|
||||||
this.linkToScroll = linkToScroll;
|
this.linkToScroll = linkToScroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private pumpLock() {
|
||||||
|
this.lock.touchedAt = new Date();
|
||||||
|
this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe( async result => {
|
||||||
|
if (!isNullOrUndefined(result)) {
|
||||||
|
this.lock.id = Guid.parse(result);
|
||||||
|
} else {
|
||||||
|
this.location.back();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
<h4 class="card-title">{{ 'DMP-EDITOR.TITLE.NEW' | translate }}</h4>
|
<h4 class="card-title">{{ 'DMP-EDITOR.TITLE.NEW' | translate }}</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex ml-auto p-2" *ngIf="!isNew">
|
<div class="d-flex ml-auto p-2" *ngIf="!isNew">
|
||||||
<button *ngIf="!isFinalized" mat-icon-button [matMenuTriggerFor]="actionsMenu" class="ml-auto more-icon" (click)="$event.stopImmediatePropagation();">
|
<button *ngIf="!isFinalized && !lockStatus" mat-icon-button [matMenuTriggerFor]="actionsMenu" class="ml-auto more-icon" (click)="$event.stopImmediatePropagation();">
|
||||||
<mat-icon class="more-horiz">more_horiz</mat-icon>
|
<mat-icon class="more-horiz">more_horiz</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<mat-menu #actionsMenu="matMenu">
|
<mat-menu #actionsMenu="matMenu">
|
||||||
|
@ -65,21 +65,21 @@
|
||||||
<mat-icon class="mr-2">work_outline</mat-icon>
|
<mat-icon class="mr-2">work_outline</mat-icon>
|
||||||
{{ 'DMP-LISTING.COLUMNS.GRANT' | translate }}
|
{{ 'DMP-LISTING.COLUMNS.GRANT' | translate }}
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<app-grant-tab [grantformGroup]="formGroup.get('grant')" [projectFormGroup]="formGroup.get('project')" [funderFormGroup]="formGroup.get('funder')" [isFinalized]="isFinalized" [isNew]="isNew" [isUserOwner]="isUserOwner"></app-grant-tab>
|
<app-grant-tab [grantformGroup]="formGroup.get('grant')" [projectFormGroup]="formGroup.get('project')" [funderFormGroup]="formGroup.get('funder')" [isFinalized]="isFinalized || lockStatus" [isNew]="isNew" [isUserOwner]="isUserOwner"></app-grant-tab>
|
||||||
</mat-tab>
|
</mat-tab>
|
||||||
<mat-tab *ngIf="!isNew">
|
<mat-tab *ngIf="!isNew">
|
||||||
<ng-template mat-tab-label>
|
<ng-template mat-tab-label>
|
||||||
<mat-icon class="mr-2">library_books</mat-icon>
|
<mat-icon class="mr-2">library_books</mat-icon>
|
||||||
{{ 'DMP-LISTING.COLUMNS.DATASETS' | translate }}
|
{{ 'DMP-LISTING.COLUMNS.DATASETS' | translate }}
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<app-datasets-tab [dmp]="dmp" [isPublic]="isPublic" [isFinalized]="isFinalized"></app-datasets-tab>
|
<app-datasets-tab [dmp]="dmp" [isPublic]="isPublic" [isFinalized]="isFinalized || lockStatus"></app-datasets-tab>
|
||||||
</mat-tab>
|
</mat-tab>
|
||||||
<mat-tab *ngIf="!isNew">
|
<mat-tab *ngIf="!isNew">
|
||||||
<ng-template mat-tab-label>
|
<ng-template mat-tab-label>
|
||||||
<mat-icon class="mr-2">person</mat-icon>
|
<mat-icon class="mr-2">person</mat-icon>
|
||||||
{{ 'DMP-LISTING.COLUMNS.PEOPLE' | translate }}
|
{{ 'DMP-LISTING.COLUMNS.PEOPLE' | translate }}
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<app-people-tab [formGroup]="formGroup" [dmp]="dmp" [isPublic]="isPublic" [isFinalized]="isFinalized"></app-people-tab>
|
<app-people-tab [formGroup]="formGroup" [dmp]="dmp" [isPublic]="isPublic" [isFinalized]="isFinalized || lockStatus"></app-people-tab>
|
||||||
</mat-tab>
|
</mat-tab>
|
||||||
<mat-tab *ngIf="isNew" disabled>
|
<mat-tab *ngIf="isNew" disabled>
|
||||||
<ng-template mat-tab-label></ng-template>
|
<ng-template mat-tab-label></ng-template>
|
||||||
|
@ -101,12 +101,12 @@
|
||||||
{{'DMP-EDITOR.ACTIONS.CANCEL' | translate}}
|
{{'DMP-EDITOR.ACTIONS.CANCEL' | translate}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="isNew">
|
<div *ngIf="isNew && !lockStatus">
|
||||||
<button mat-raised-button color="primary" (click)="cancel()" type="button" class="text-uppercase mr-2">
|
<button mat-raised-button color="primary" (click)="cancel()" type="button" class="text-uppercase mr-2">
|
||||||
{{'DMP-EDITOR.ACTIONS.CANCEL' | translate}}
|
{{'DMP-EDITOR.ACTIONS.CANCEL' | translate}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="formGroup.enabled">
|
<div *ngIf="formGroup.enabled && !lockStatus">
|
||||||
<button *ngIf="!isNew" mat-raised-button type="submit" class="text-uppercase dark-theme mr-2" color="primary">
|
<button *ngIf="!isNew" mat-raised-button type="submit" class="text-uppercase dark-theme mr-2" color="primary">
|
||||||
{{'DMP-EDITOR.ACTIONS.SAVE-CHANGES' | translate}}
|
{{'DMP-EDITOR.ACTIONS.SAVE-CHANGES' | translate}}
|
||||||
</button>
|
</button>
|
||||||
|
@ -114,7 +114,7 @@
|
||||||
{{'DMP-EDITOR.ACTIONS.SAVE' | translate}}
|
{{'DMP-EDITOR.ACTIONS.SAVE' | translate}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="formGroup.enabled && !isNew">
|
<div *ngIf="formGroup.enabled && !isNew && !lockStatus">
|
||||||
<button type="button" mat-raised-button color="primary" class="text-uppercase mr-2" (click)="saveAndFinalize()">{{'DMP-EDITOR.ACTIONS.FINALISE' | translate}}
|
<button type="button" mat-raised-button color="primary" class="text-uppercase mr-2" (click)="saveAndFinalize()">{{'DMP-EDITOR.ACTIONS.FINALISE' | translate}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -32,10 +32,16 @@ import { FormValidationErrorsDialogComponent } from '@common/forms/form-validati
|
||||||
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model';
|
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import * as FileSaver from 'file-saver';
|
import * as FileSaver from 'file-saver';
|
||||||
import { Observable, of as observableOf } from 'rxjs';
|
import { Observable, of as observableOf, interval } from 'rxjs';
|
||||||
import { map, takeUntil } from 'rxjs/operators';
|
import { map, takeUntil } from 'rxjs/operators';
|
||||||
import { Principal } from "@app/core/model/auth/Principal";
|
import { Principal } from "@app/core/model/auth/Principal";
|
||||||
import { Role } from "@app/core/common/enum/role";
|
import { Role } from "@app/core/common/enum/role";
|
||||||
|
import { LockService } from '@app/core/services/lock/lock.service';
|
||||||
|
import { Location } from '@angular/common';
|
||||||
|
import { LockModel } from '@app/core/model/lock/lock.model';
|
||||||
|
import { Guid } from '@common/types/guid';
|
||||||
|
import { isNullOrUndefined } from 'util';
|
||||||
|
import { environment } from 'environments/environment';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-dmp-editor-component',
|
selector: 'app-dmp-editor-component',
|
||||||
|
@ -62,6 +68,8 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
|
||||||
selectedDmpProfileDefinition: DmpProfileDefinition;
|
selectedDmpProfileDefinition: DmpProfileDefinition;
|
||||||
DynamicDmpFieldResolverComponent: any;
|
DynamicDmpFieldResolverComponent: any;
|
||||||
isUserOwner: boolean = true;
|
isUserOwner: boolean = true;
|
||||||
|
lock: LockModel;
|
||||||
|
lockStatus: Boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private dmpProfileService: DmpProfileService,
|
private dmpProfileService: DmpProfileService,
|
||||||
|
@ -73,7 +81,8 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
|
||||||
private uiNotificationService: UiNotificationService,
|
private uiNotificationService: UiNotificationService,
|
||||||
private authentication: AuthService,
|
private authentication: AuthService,
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
private formService: FormService
|
private formService: FormService,
|
||||||
|
private lockService: LockService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
@ -104,6 +113,8 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
|
||||||
this.dmpService.getSingle(itemId).pipe(map(data => data as DmpModel))
|
this.dmpService.getSingle(itemId).pipe(map(data => data as DmpModel))
|
||||||
.pipe(takeUntil(this._destroyed))
|
.pipe(takeUntil(this._destroyed))
|
||||||
.subscribe(async data => {
|
.subscribe(async data => {
|
||||||
|
this.lockService.checkLockStatus(data.id).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => {
|
||||||
|
this.lockStatus = lockStatus;
|
||||||
this.dmp = new DmpEditorModel();
|
this.dmp = new DmpEditorModel();
|
||||||
this.dmp.grant = new GrantTabModel();
|
this.dmp.grant = new GrantTabModel();
|
||||||
this.dmp.project = new ProjectFormModel();
|
this.dmp.project = new ProjectFormModel();
|
||||||
|
@ -115,12 +126,22 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
|
||||||
this.isFinalized = true;
|
this.isFinalized = true;
|
||||||
this.formGroup.disable();
|
this.formGroup.disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
//this.registerFormEventsForDmpProfile(this.dmp.definition);
|
//this.registerFormEventsForDmpProfile(this.dmp.definition);
|
||||||
if (!this.editMode || this.dmp.status === DmpStatus.Finalized) {
|
if (!this.editMode || this.dmp.status === DmpStatus.Finalized || lockStatus) {
|
||||||
this.isFinalized = true;
|
this.isFinalized = true;
|
||||||
this.formGroup.disable();
|
this.formGroup.disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isAuthenticated) {
|
if (this.isAuthenticated) {
|
||||||
|
if (!lockStatus) {
|
||||||
|
this.lock = new LockModel(data.id, this.getUserFromDMP());
|
||||||
|
|
||||||
|
this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => {
|
||||||
|
this.lock.id = Guid.parse(result);
|
||||||
|
interval(environment.lockInterval).pipe(takeUntil(this._destroyed)).subscribe(() => this.pumpLock());
|
||||||
|
});
|
||||||
|
}
|
||||||
// if (!this.isAuthenticated) {
|
// if (!this.isAuthenticated) {
|
||||||
const breadCrumbs = [];
|
const breadCrumbs = [];
|
||||||
breadCrumbs.push({
|
breadCrumbs.push({
|
||||||
|
@ -139,6 +160,7 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
|
||||||
}
|
}
|
||||||
this.associatedUsers = data.associatedUsers;
|
this.associatedUsers = data.associatedUsers;
|
||||||
this.people = data.users;
|
this.people = data.users;
|
||||||
|
})
|
||||||
});
|
});
|
||||||
} else if (publicId != null) {
|
} else if (publicId != null) {
|
||||||
this.isNew = false;
|
this.isNew = false;
|
||||||
|
@ -146,6 +168,8 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
|
||||||
this.dmpService.getSinglePublic(publicId).pipe(map(data => data as DmpModel))
|
this.dmpService.getSinglePublic(publicId).pipe(map(data => data as DmpModel))
|
||||||
.pipe(takeUntil(this._destroyed))
|
.pipe(takeUntil(this._destroyed))
|
||||||
.subscribe(async data => {
|
.subscribe(async data => {
|
||||||
|
this.lockService.checkLockStatus(data.id).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => {
|
||||||
|
this.lockStatus = lockStatus;
|
||||||
this.dmp = new DmpEditorModel();
|
this.dmp = new DmpEditorModel();
|
||||||
this.dmp.grant = new GrantTabModel();
|
this.dmp.grant = new GrantTabModel();
|
||||||
this.dmp.project = new ProjectFormModel();
|
this.dmp.project = new ProjectFormModel();
|
||||||
|
@ -153,7 +177,7 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
|
||||||
this.dmp.fromModel(data);
|
this.dmp.fromModel(data);
|
||||||
this.formGroup = this.dmp.buildForm();
|
this.formGroup = this.dmp.buildForm();
|
||||||
//this.registerFormEventsForDmpProfile(this.dmp.definition);
|
//this.registerFormEventsForDmpProfile(this.dmp.definition);
|
||||||
if (!this.editMode || this.dmp.status === DmpStatus.Finalized) { this.formGroup.disable(); }
|
if (!this.editMode || this.dmp.status === DmpStatus.Finalized || lockStatus) { this.formGroup.disable(); }
|
||||||
// if (!this.isAuthenticated) {
|
// if (!this.isAuthenticated) {
|
||||||
const breadcrumbs = [];
|
const breadcrumbs = [];
|
||||||
breadcrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC-DMPS').toUpperCase(), url: '/plans' });
|
breadcrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC-DMPS').toUpperCase(), url: '/plans' });
|
||||||
|
@ -169,6 +193,15 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
|
||||||
// );
|
// );
|
||||||
this.associatedUsers = data.associatedUsers;
|
this.associatedUsers = data.associatedUsers;
|
||||||
// }
|
// }
|
||||||
|
if (!lockStatus) {
|
||||||
|
this.lock = new LockModel(data.id, this.getUserFromDMP());
|
||||||
|
|
||||||
|
this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => {
|
||||||
|
this.lock.id = Guid.parse(result);
|
||||||
|
interval(environment.lockInterval).pipe(takeUntil(this._destroyed)).subscribe(() => this.pumpLock());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.dmp = new DmpEditorModel();
|
this.dmp = new DmpEditorModel();
|
||||||
|
@ -301,7 +334,17 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
|
||||||
|
|
||||||
public cancel(id: String): void {
|
public cancel(id: String): void {
|
||||||
if (id != null) {
|
if (id != null) {
|
||||||
this.router.navigate(['/plans/overview/' + id]);
|
this.lockService.unlockTarget(this.dmp.id).pipe(takeUntil(this._destroyed)).subscribe(
|
||||||
|
complete => {
|
||||||
|
this.router.navigate(['/plans/overview/' + id]);
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
this.formGroup.get('status').setValue(DmpStatus.Draft);
|
||||||
|
this.onCallbackError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.router.navigate(['/plans']);
|
this.router.navigate(['/plans']);
|
||||||
}
|
}
|
||||||
|
@ -498,6 +541,17 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private pumpLock() {
|
||||||
|
this.lock.touchedAt = new Date();
|
||||||
|
this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe( async result => {
|
||||||
|
if (!isNullOrUndefined(result)) {
|
||||||
|
this.lock.id = Guid.parse(result);
|
||||||
|
} else {
|
||||||
|
this.location.back();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// advancedClicked() {
|
// advancedClicked() {
|
||||||
// const dialogRef = this.dialog.open(ExportMethodDialogComponent, {
|
// const dialogRef = this.dialog.open(ExportMethodDialogComponent, {
|
||||||
// maxWidth: '500px',
|
// maxWidth: '500px',
|
||||||
|
|
|
@ -477,6 +477,7 @@
|
||||||
"FINALIZE": "Finalize",
|
"FINALIZE": "Finalize",
|
||||||
"REVERSE": "Undo Finalization",
|
"REVERSE": "Undo Finalization",
|
||||||
"INFO": "Datasets of finalized DMPs can't revert to unfinalized",
|
"INFO": "Datasets of finalized DMPs can't revert to unfinalized",
|
||||||
|
"LOCK": "Dataset is Locked by another user",
|
||||||
"DOWNLOAD-PDF": "Download PDF",
|
"DOWNLOAD-PDF": "Download PDF",
|
||||||
"DOWNLOAD-XML": "Download XML",
|
"DOWNLOAD-XML": "Download XML",
|
||||||
"DOWNLOAD-DOCX": "Download DOCX",
|
"DOWNLOAD-DOCX": "Download DOCX",
|
||||||
|
|
|
@ -477,6 +477,7 @@
|
||||||
"FINALIZE": "Finalize",
|
"FINALIZE": "Finalize",
|
||||||
"REVERSE": "Undo Finalization",
|
"REVERSE": "Undo Finalization",
|
||||||
"INFO": "Datasets of finalized DMPs can't revert to unfinalized",
|
"INFO": "Datasets of finalized DMPs can't revert to unfinalized",
|
||||||
|
"LOCK": "Dataset is Locked by another user",
|
||||||
"DOWNLOAD-PDF": "Download PDF",
|
"DOWNLOAD-PDF": "Download PDF",
|
||||||
"DOWNLOAD-XML": "Download XML",
|
"DOWNLOAD-XML": "Download XML",
|
||||||
"DOWNLOAD-DOCX": "Download DOCX",
|
"DOWNLOAD-DOCX": "Download DOCX",
|
||||||
|
|
|
@ -43,4 +43,5 @@ export const environment = {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
logLevels: ["debug", "info", "warning", "error"]
|
logLevels: ["debug", "info", "warning", "error"]
|
||||||
},
|
},
|
||||||
|
lockInterval: 60000,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue