package edu.ualberta.med.biobank.model; import java.io.Serializable; import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; import edu.ualberta.med.biobank.common.util.NotAProxy; /** * The id of these enumerations are saved in the database. Therefore, DO NOT * CHANGE THESE ENUM IDS (unless you are prepared to write an upgrade script). * However, order and enum name can be modified freely. * <p> * Also, these enums should probably never be deleted, unless they are not used * in <em>any</em> database. Instead, they should be deprecated and probably * always return false when checking allow-ability. * * @author Jonathan Ferland * */ public enum PermissionEnum implements NotAProxy, Serializable { SPECIMEN_CREATE(2), SPECIMEN_READ(3), SPECIMEN_UPDATE(4), SPECIMEN_DELETE(5), SPECIMEN_LINK(6), SPECIMEN_ASSIGN(7), SITE_CREATE(8, Require.ALL_CENTERS), SITE_READ(9), SITE_UPDATE(10), SITE_DELETE(11), PATIENT_CREATE(12), PATIENT_READ(13), PATIENT_UPDATE(14), PATIENT_DELETE(15), PATIENT_MERGE(16), COLLECTION_EVENT_CREATE(17), COLLECTION_EVENT_READ(18), COLLECTION_EVENT_UPDATE(19), COLLECTION_EVENT_DELETE(20), PROCESSING_EVENT_CREATE(21), PROCESSING_EVENT_READ(22), PROCESSING_EVENT_UPDATE(23), PROCESSING_EVENT_DELETE(24), ORIGIN_INFO_CREATE(25), ORIGIN_INFO_READ(26), ORIGIN_INFO_UPDATE(27), ORIGIN_INFO_DELETE(28), DISPATCH_CREATE(29), DISPATCH_READ(30), DISPATCH_CHANGE_STATE(31), DISPATCH_UPDATE(32), DISPATCH_DELETE(33), RESEARCH_GROUP_CREATE(34, Require.ALL_CENTERS), RESEARCH_GROUP_READ(35), RESEARCH_GROUP_UPDATE(36), RESEARCH_GROUP_DELETE(37), STUDY_CREATE(38, Require.ALL_STUDIES), STUDY_READ(39), STUDY_UPDATE(40), STUDY_DELETE(41), REQUEST_CREATE(42), REQUEST_READ(43), REQUEST_UPDATE(44), REQUEST_DELETE(45), REQUEST_PROCESS(46), CLINIC_CREATE(47, Require.ALL_CENTERS), CLINIC_READ(48), CLINIC_UPDATE(49), CLINIC_DELETE(50), CONTAINER_TYPE_CREATE(52), CONTAINER_TYPE_READ(53), CONTAINER_TYPE_UPDATE(54), CONTAINER_TYPE_DELETE(55), CONTAINER_CREATE(56), CONTAINER_READ(57), CONTAINER_UPDATE(58), CONTAINER_DELETE(59), SPECIMEN_TYPE_CREATE(60, Require.ALL_CENTERS, Require.ALL_STUDIES), SPECIMEN_TYPE_READ(61), SPECIMEN_TYPE_UPDATE(62, Require.ALL_CENTERS, Require.ALL_STUDIES), SPECIMEN_TYPE_DELETE(63, Require.ALL_CENTERS, Require.ALL_STUDIES), LOGGING(64), REPORTS(65), SPECIMEN_LIST(66), LABEL_PRINTING(67); private static final List<PermissionEnum> VALUES_LIST = Collections .unmodifiableList(Arrays.asList(values())); private static final Map<Integer, PermissionEnum> VALUES_MAP; static { Map<Integer, PermissionEnum> map = new HashMap<Integer, PermissionEnum>(); for (PermissionEnum permissionEnum : values()) { PermissionEnum check = map.get(permissionEnum.getId()); if (check != null) { throw new RuntimeException("permission enum value " + permissionEnum.getId() + " used multiple times"); } map.put(permissionEnum.getId(), permissionEnum); } VALUES_MAP = Collections.unmodifiableMap(map); } private final Integer id; private final EnumSet<Require> requires; private PermissionEnum(Integer id, Require... requires) { this.id = id; this.requires = EnumSet.of(Require.DEFAULT, requires); } public static List<PermissionEnum> valuesList() { return VALUES_LIST; } public static Map<Integer, PermissionEnum> valuesMap() { return VALUES_MAP; } public Integer getId() { return id; } public EnumSet<Require> getRequires() { return EnumSet.copyOf(requires); } public String getName() { return name(); // TODO: localized name? } public static PermissionEnum fromId(Integer id) { return valuesMap().get(id); } /** * Whether the given {@link User} has this {@link PermissionEnum} on * <em>any</em> {@link Center} or {@link Study}. * * @see {@link #isMembershipAllowed(Membership, Center, Study)} * @param user * @return */ public boolean isAllowed(User user) { return isAllowed(user, null, null); } /** * Whether the given {@link User} has this {@link PermissionEnum} on * <em>any</em> {@link Center}, but a specific {@link Study}. * * @see {@link #isAllowed(User)} * @param user * @return */ public boolean isAllowed(User user, Study study) { return isAllowed(user, null, study); } /** * Whether the given {@link User} has this {@link PermissionEnum} on * <em>any</em> {@link Study}, but a specific {@link Center}. * * @see {@link #isAllowed(User)} * @param user * @return */ public boolean isAllowed(User user, Center center) { return isAllowed(user, center, null); } /** * * @param user * @param center if null, {@link Center} does not matter. * @param study if null, {@link Study} does not matter. * @return */ public boolean isAllowed(User user, Center center, Study study) { for (Membership m : user.getAllMemberships()) { if (isMembershipAllowed(m, center, study)) return true; } return false; } /** * Return true if special requirements (i.e. {@link Require}-s) are met on * the given {@link Membership}, otherwise false. * * @param m * @return */ public boolean isRequirementsMet(Membership m) { boolean reqsMet = true; Domain d = m.getDomain(); reqsMet &= !requires.contains(Require.ALL_CENTERS) || d.isAllCenters(); reqsMet &= !requires.contains(Require.ALL_STUDIES) || d.isAllStudies(); return reqsMet; } /** * This is a confusing check. If {@link Center} is null, it means we do not * care about its value, otherwise, {@link Domain#contains(Center)} must be * true. The same applies to {@link Study}. * * @param m * @param c * @param s * @return */ private boolean isMembershipAllowed(Membership m, Center c, Study s) { boolean requiresMet = isRequirementsMet(m); boolean hasCenter = c == null || m.getDomain().contains(c); boolean hasStudy = s == null || m.getDomain().contains(s); boolean hasPermission = m.getAllPermissions().contains(this); boolean allowed = requiresMet && hasCenter && hasStudy && hasPermission; return allowed; } /** * Defines special requirements for a {@link PermissionEnum}. * * @author jferland * */ public enum Require implements NotAProxy, Serializable { /** * Does nothing but make creating {@link EnumSet}-s easier. */ DEFAULT, /** * If present, the {@link PermissionEnum} must exist in a * {@link Membership} for which its {@link Domain#isAllCenters()} * returns true. */ ALL_CENTERS, /** * If present, the {@link PermissionEnum} must exist in a * {@link Membership} for which its {@link Domain#isAllStudies()} * returns true. */ ALL_STUDIES; } }