package edu.harvard.iq.dataverse.authorization;
import edu.harvard.iq.dataverse.Dataverse;
import edu.harvard.iq.dataverse.DvObject;
import edu.harvard.iq.dataverse.util.BitSet;
import java.io.Serializable;
import java.util.Collection;
import java.util.Comparator;
import java.util.Objects;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
/**
* A role is an annotated set of permissions. A role belongs
* to a {@link Dataverse}. Users may assume roles from the current dataverse,
* or from its parent dataverses, up to the first permission root dataverse.
*
* @author michael
*/
@NamedQueries({
@NamedQuery(name = "DataverseRole.findByOwnerId",
query= "SELECT r FROM DataverseRole r WHERE r.owner.id=:ownerId ORDER BY r.name"),
@NamedQuery(name = "DataverseRole.findBuiltinRoles",
query= "SELECT r FROM DataverseRole r WHERE r.owner is null ORDER BY r.name"),
@NamedQuery(name = "DataverseRole.findBuiltinRoleByAlias",
query= "SELECT r FROM DataverseRole r WHERE r.alias=:alias AND r.owner is null"),
@NamedQuery(name = "DataverseRole.listAll",
query= "SELECT r FROM DataverseRole r"),
@NamedQuery(name = "DataverseRole.deleteById",
query= "DELETE FROM DataverseRole r WHERE r.id=:id")
})
@Entity
@Table(indexes = {@Index(columnList="owner_id")
, @Index(columnList="name")
, @Index(columnList="alias")})
public class DataverseRole implements Serializable {
//constants for the built in roles references in the code
public static final String ADMIN = "admin";
public static final String FILE_DOWNLOADER = "fileDownloader";
public static final String FULL_CONTRIBUTOR = "fullContributor";
public static final String DV_CONTRIBUTOR = "dvContributor";
public static final String DS_CONTRIBUTOR = "dsContributor";
/**
* Heads up that this says "editor" which comes from
* scripts/api/data/role-editor.json but the name is "Contributor". The
* *alias* is "editor". Don't be fooled!
*/
public static final String EDITOR = "editor";
public static final String MANAGER = "manager";
public static final String CURATOR = "curator";
public static final String MEMBER = "member";
public static final Comparator<DataverseRole> CMP_BY_NAME = new Comparator<DataverseRole>(){
@Override
public int compare(DataverseRole o1, DataverseRole o2) {
int cmp = o1.getName().compareTo(o2.getName());
if ( cmp != 0 ) return cmp;
Long o1OwnerId = o1.getOwner() == null ? 0l : o1.getOwner().getId();
Long o2OwnerId = o2.getOwner() == null ? 0l : o2.getOwner().getId();
return o1OwnerId.compareTo( o2OwnerId );
}
};
public static Set<Permission> permissionSet( Iterable<DataverseRole> roles ) {
long miniset = 0l;
for ( DataverseRole role : roles ) {
miniset |= role.permissionBits;
}
return new BitSet(miniset).asSetOf(Permission.class);
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Pattern(regexp=".+", message="A Role must have a name.")
@Column( nullable = false )
private String name;
@Size(max = 255, message = "Description must be at most 255 characters.")
private String description;
@Size(max = 16, message = "Alias must be at most 16 characters.")
@Pattern(regexp = "[a-zA-Z0-9\\_\\-]+", message = "Alias cannot be empty. Valid characters are a-Z, 0-9, '_', and '-'.")
@Column(nullable = false, unique=true)
private String alias;
/** Stores the permissions in a bit set. */
private long permissionBits;
@ManyToOne
@JoinColumn(nullable=true)
private DvObject owner;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias = alias;
}
public DvObject getOwner() {
return owner;
}
public void setOwner(DvObject owner) {
this.owner = owner;
}
public void addPermissions( Collection<Permission> ps ) {
for ( Permission p : ps ) addPermission(p);
}
public void addPermission( Permission p ) {
permissionBits = new BitSet(permissionBits).set(p.ordinal()).getBits();
}
public void clearPermissions() {
permissionBits = 0l;
}
public Set<Permission> permissions() {
return new BitSet(permissionBits).asSetOf(Permission.class);
}
public long getPermissionsBits() {
return permissionBits;
}
@Override
public String toString() {
return "DataverseRole{" + "id=" + id + ", alias=" + alias + '}';
}
@Override
public int hashCode() {
int hash = 7;
hash = 97 * hash + Objects.hashCode(this.id);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final DataverseRole other = (DataverseRole) obj;
if (!Objects.equals(this.id, other.id)) {
return false;
}
return true;
}
/**
* Given a DvObject object, see if this role contains a Permission
* applicable to that object
*
* @param dvObject
* @return
*/
public boolean doesDvObjectHavePermissionForObject(DvObject dvObject){
if (dvObject == null){
return false;
}
return this.doesDvObjectClassHavePermissionForObject(dvObject.getClass());
} // doesDvObjectHavePermissionForObject
/**
* Given a DvObject object class, see if this role contains a Permission
* applicable to that object
*
* Initial user is for MyData page and displaying role tags
*
* @param dvObjectClass
* @return
*/
public boolean doesDvObjectClassHavePermissionForObject(Class<? extends DvObject> dvObjectClass){
if (dvObjectClass == null){
return false;
}
// Iterate through permissions. If one applies to this class, return true
//
for (Permission perm : this.permissions()) {
if (perm.appliesTo(dvObjectClass)){
return true;
}
}
return false;
} // doesDvObjectClassHavePermissionForObject
}