AbstractCardType.java
/*
* The coLAB project
* Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO
*
* Licensed under the MIT License
*/
package ch.colabproject.colab.api.model.card;
import static ch.colabproject.colab.api.model.card.Card.STRUCTURE_SEQUENCE_NAME;
import ch.colabproject.colab.api.exceptions.ColabMergeException;
import ch.colabproject.colab.api.model.ColabEntity;
import ch.colabproject.colab.api.model.WithWebsocketChannels;
import ch.colabproject.colab.api.model.common.DeletionStatus;
import ch.colabproject.colab.api.model.common.Tracking;
import ch.colabproject.colab.api.model.document.AbstractResource;
import ch.colabproject.colab.api.model.document.Resourceable;
import ch.colabproject.colab.api.model.project.Project;
import ch.colabproject.colab.api.model.tools.EntityHelper;
import ch.colabproject.colab.api.security.permissions.Conditions;
import ch.colabproject.colab.api.security.permissions.card.CardTypeOrRefConditions;
import ch.colabproject.colab.api.ws.channel.tool.ChannelsBuilders.AboutCardTypeChannelsBuilder;
import ch.colabproject.colab.api.ws.channel.tool.ChannelsBuilders.ChannelsBuilder;
import ch.colabproject.colab.generator.model.tools.PolymorphicDeserializer;
import java.util.ArrayList;
import java.util.List;
import javax.json.bind.annotation.JsonbTransient;
import javax.json.bind.annotation.JsonbTypeDeserializer;
import javax.persistence.CascadeType;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.PostLoad;
import javax.persistence.Table;
import javax.persistence.Transient;
/**
* Abstract Card type
*
* @author maxence
*/
@Entity
@Table(
indexes = {
@Index(columnList = "project_id"),
}
)
@NamedQuery(name = "AbstractCardType.findPublishedByProjectTeamMemberUser",
query = "SELECT act FROM AbstractCardType act"
+ " JOIN act.project proj"
+ " JOIN proj.teamMembers memb"
+ " WHERE act.published = TRUE AND memb.user.id = :userId")
@NamedQuery(name = "AbstractCardType.findIdsByProjectTeamMemberUser",
query = "SELECT act.id FROM AbstractCardType act"
+ " JOIN act.project proj"
+ " JOIN proj.teamMembers memb"
+ " WHERE memb.user.id = :userId")
@NamedQuery(name = "AbstractCardType.findProjectId",
query = "SELECT act.project.id FROM AbstractCardType act WHERE act.id in :listId")
@Inheritance(strategy = InheritanceType.JOINED)
@JsonbTypeDeserializer(PolymorphicDeserializer.class)
public abstract class AbstractCardType implements ColabEntity, WithWebsocketChannels, Resourceable {
private static final long serialVersionUID = 1L;
// ---------------------------------------------------------------------------------------------
// fields
// ---------------------------------------------------------------------------------------------
/**
* CardType ID
*/
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = STRUCTURE_SEQUENCE_NAME)
private Long id;
/**
* creation + modification + erasure tracking data
*/
@Embedded
private Tracking trackingData;
/**
* Is it in a bin or ready to be definitely deleted. Null means active.
*/
@Enumerated(EnumType.STRING)
private DeletionStatus deletionStatus;
/**
* Is this type available to other projects?
*/
private boolean published;
/**
* published state on load
*/
@Transient
private boolean initialPublished;
/**
* Is this type deprecated? A deprecated type should not be used by new projects.
*/
private boolean deprecated;
/**
* The project it belongs to. If project is null, it means the type is a global type
*/
@ManyToOne(fetch = FetchType.LAZY)
@JsonbTransient
private Project project;
/**
* The id of the project (serialization sugar)
*/
@Transient
protected Long projectId;
/**
* The list of all cards implementing this card definition
*/
@OneToMany(mappedBy = "cardType", cascade = CascadeType.ALL)
@JsonbTransient
private List<Card> implementingCards = new ArrayList<>();
/**
* The list of abstract resources directly linked to this card definition
*/
@OneToMany(mappedBy = "abstractCardType", cascade = CascadeType.ALL)
@JsonbTransient
private List<AbstractResource> directAbstractResources = new ArrayList<>();
// Note : the List<CardTypeRef> of direct references must be retrieved with a DAO
// because the abstract card type must not be seen as changed when a reference is added or
// removed
// ---------------------------------------------------------------------------------------------
// getters and setters
// ---------------------------------------------------------------------------------------------
/**
* @return the cardType ID
*/
@Override
public Long getId() {
return id;
}
/**
* @param id the cardType ID
*/
public void setId(Long id) {
this.id = id;
}
/**
* Get the tracking data
*
* @return tracking data
*/
@Override
public Tracking getTrackingData() {
return trackingData;
}
/**
* Set tracking data
*
* @param trackingData new tracking data
*/
@Override
public void setTrackingData(Tracking trackingData) {
this.trackingData = trackingData;
}
@Override
public DeletionStatus getDeletionStatus() {
return deletionStatus;
}
@Override
public void setDeletionStatus(DeletionStatus status) {
this.deletionStatus = status;
}
/**
* Get the value of published
*
* @return the value of published
*/
public boolean isPublished() {
return published;
}
/**
* Set the value of published
*
* @param published new value of published
*/
public void setPublished(boolean published) {
this.published = published;
}
/**
* Get the value of deprecated
*
* @return the value of deprecated
*/
public boolean isDeprecated() {
return deprecated;
}
/**
* Set the value of deprecated
*
* @param deprecated new value of deprecated
*/
public void setDeprecated(boolean deprecated) {
this.deprecated = deprecated;
}
/**
* @return the project it belongs to
*/
public Project getProject() {
return project;
}
/**
* @param project the project it belongs to
*/
public void setProject(Project project) {
this.project = project;
}
/**
* get the project id. To be sent to client
*
* @return id of the project or null
*/
public Long getProjectId() {
if (this.project != null) {
return this.project.getId();
} else {
return projectId;
}
}
/**
* set the project id. For serialization only
*
* @param id the id of the project
*/
public void setProjectId(Long id) {
this.projectId = id;
}
/**
* @return the list of all cards implementing this card definition
*/
public List<Card> getImplementingCards() {
return implementingCards;
}
/**
* @param implementingCards the list of all cards implementing this card definition
*/
public void setImplementingCards(List<Card> implementingCards) {
this.implementingCards = implementingCards;
}
/**
* @return the list of abstract resources directly linked to this card definition
*/
@Override
public List<AbstractResource> getDirectAbstractResources() {
return directAbstractResources;
}
/**
* @param abstractResources the list of abstract resources directly linked to this card
* definition
*/
public void setDirectAbstractResources(List<AbstractResource> abstractResources) {
this.directAbstractResources = abstractResources;
}
// ---------------------------------------------------------------------------------------------
// helpers
// ---------------------------------------------------------------------------------------------
/**
* @return is now published or was just unpublished
*/
@JsonbTransient
public boolean isOrWasPublished() {
return this.isPublished() || this.initialPublished;
}
// ---------------------------------------------------------------------------------------------
// concerning the whole class
// ---------------------------------------------------------------------------------------------
/**
* Resolve to concrete CardType
*
* @return the effective cardType
*/
public abstract CardType resolve();
/**
* Resolve to concrete type and return all transitive references too.
*
* @return concrete type and transitive references
*/
public abstract List<AbstractCardType> expand();
/**
* JPA post-load callback. Used to keep trace of the initial value of the <code>published</code>
* field.
*/
@PostLoad
public void postLoad() {
// keep trace of modification
this.initialPublished = this.published;
}
@Override
public void mergeToUpdate(ColabEntity other) throws ColabMergeException {
if (other instanceof AbstractCardType) {
AbstractCardType o = (AbstractCardType) other;
this.setDeletionStatus(o.getDeletionStatus());
this.setPublished(o.isPublished());
this.setDeprecated(o.isDeprecated());
} else {
throw new ColabMergeException(this, other);
}
}
@Override
public ChannelsBuilder getChannelsBuilder() {
return new AboutCardTypeChannelsBuilder(this);
}
@Override
@JsonbTransient
public Conditions.Condition getReadCondition() {
return new CardTypeOrRefConditions.IsCardTypeOrRefReadable(this.id);
}
@Override
@JsonbTransient
public Conditions.Condition getUpdateCondition() {
if (this.project != null) {
// type belongs to a project
return this.project.getUpdateCondition();
} else {
// only admin can edit global types
return Conditions.alwaysFalse;
}
}
@Override
public int hashCode() {
return EntityHelper.hashCode(this);
}
@Override
@SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
public boolean equals(Object obj) {
return EntityHelper.equals(this, obj);
}
}