/** * Finds the right index at which to insert a new data approval level. Returns -1 if the new data * approval level is a duplicate. * * @param dataApprovalLevels list of all levels. * @param newLevel new level to find the insertion point for. * @return index where the new approval level should be inserted, or -1 if the new level is a * duplicate. */ private int getInsertIndex( List<DataApprovalLevel> dataApprovalLevels, DataApprovalLevel newLevel) { int i = dataApprovalLevels.size() - 1; while (i >= 0) { DataApprovalLevel test = dataApprovalLevels.get(i); int orgLevelDifference = newLevel.getOrgUnitLevel() - test.getOrgUnitLevel(); if (orgLevelDifference > 0) { break; } if (orgLevelDifference == 0) { if (newLevel.levelEquals(test)) { return -1; } if (test.getCategoryOptionGroupSet() == null) { break; } } i--; } return i + 1; }
@Override public DataApprovalLevel getLowestDataApprovalLevel( OrganisationUnit orgUnit, DataElementCategoryOptionCombo attributeOptionCombo) { Set<CategoryOptionGroupSet> cogSets = null; if (attributeOptionCombo != null && attributeOptionCombo != categoryService.getDefaultDataElementCategoryOptionCombo()) { cogSets = new HashSet<>(); for (DataElementCategoryOption option : attributeOptionCombo.getCategoryOptions()) { if (option.getGroupSets() != null) { cogSets.addAll(option.getGroupSets()); } } } int orgUnitLevel = orgUnit.getLevel(); List<DataApprovalLevel> approvalLevels = getDataApprovalLevelsByOrgUnitLevel(orgUnitLevel); for (DataApprovalLevel level : Lists.reverse(approvalLevels)) { if (level.getCategoryOptionGroupSet() == null) { if (cogSets == null) { return level; } } else if (cogSets != null && cogSets.contains(level.getCategoryOptionGroupSet())) { return level; } } return null; }
/** * Get the approval level for an organisation unit that is required in order for the user to see * the data, assuming user is limited to seeing approved data only from lower approval levels. * * @param orgUnit organisation unit to test. * @param user the user. * @param approvalLevels all data approval levels. * @return required approval level for user to see the data. */ private int requiredApprovalLevel( OrganisationUnit orgUnit, User user, List<DataApprovalLevel> approvalLevels) { DataApprovalLevel userLevel = getUserApprovalLevel(orgUnit, user, approvalLevels); int totalLevels = approvalLevels.size(); return userLevel == null ? 0 : userLevel.getLevel() == totalLevels ? APPROVAL_LEVEL_UNAPPROVED : userLevel.getLevel() + 1; }
@Override public boolean canDataApprovalLevelMoveUp(int level) { List<DataApprovalLevel> dataApprovalLevels = getAllDataApprovalLevels(); int index = level - 1; if (index <= 0 || index >= dataApprovalLevels.size()) { return false; } DataApprovalLevel test = dataApprovalLevels.get(index); DataApprovalLevel previous = dataApprovalLevels.get(index - 1); return test.getOrgUnitLevel() == previous.getOrgUnitLevel() && previous.getCategoryOptionGroupSet() != null; }
@Override public boolean canDataApprovalLevelMoveDown(int level) { List<DataApprovalLevel> dataApprovalLevels = getAllDataApprovalLevels(); int index = level - 1; if (index < 0 || index + 1 >= dataApprovalLevels.size()) { return false; } DataApprovalLevel test = dataApprovalLevels.get(index); DataApprovalLevel next = dataApprovalLevels.get(index + 1); return test.getOrgUnitLevel() == next.getOrgUnitLevel() && test.getCategoryOptionGroupSet() != null; }
/** * Get the approval level for a user for a given organisation unit. It is assumed that the user * has access to the organisation unit (must be checked elsewhere, it is not checked here.) If the * organisation unit is above all approval levels, returns null (no approval levels apply.) * * <p>If users are restricted to viewing approved data only, users may see data from lower levels * *only* if it is approved *below* this approval level (higher number approval level). Or, if * this method returns the lowest (highest number) approval level, users may see unapproved data. * * <p>If users have approve/unapprove authority (checked elsewhere, not here), the returned level * is the level at which users may approve/unapprove. If users have authority to approve at lower * levels, they may approve at levels below the returned level. * * <p>If users have accept/unaccept authority (checked elsewhere, not here), users may * accept/unaccept at the level just *below* this level. * * @param orgUnit organisation unit to test. * @param user the user. * @param approvalLevels app data approval levels. * @return approval level for user. */ private DataApprovalLevel getUserApprovalLevel( OrganisationUnit orgUnit, User user, List<DataApprovalLevel> approvalLevels) { int userOrgUnitLevel = orgUnit.getLevel(); DataApprovalLevel userLevel = null; for (DataApprovalLevel level : approvalLevels) { if (level.getOrgUnitLevel() >= userOrgUnitLevel && securityService.canRead(level) && canReadCOGS(user, level.getCategoryOptionGroupSet())) { userLevel = level; break; } } return userLevel; }
@Override public Set<OrganisationUnitLevel> getOrganisationUnitApprovalLevels() { Set<OrganisationUnitLevel> orgUnitLevels = new HashSet<>(); List<DataApprovalLevel> dataApprovalLevels = dataApprovalLevelStore.getAllDataApprovalLevels(); for (DataApprovalLevel level : dataApprovalLevels) { OrganisationUnitLevel orgUnitLevel = organisationUnitService.getOrganisationUnitLevelByLevel(level.getOrgUnitLevel()); if (orgUnitLevel != null) { orgUnitLevels.add(orgUnitLevel); } } return orgUnitLevels; }
@Override public List<DataApprovalLevel> getAllDataApprovalLevels() { List<DataApprovalLevel> dataApprovalLevels = dataApprovalLevelStore.getAllDataApprovalLevels(); for (DataApprovalLevel dataApprovalLevel : dataApprovalLevels) { int ouLevelNumber = dataApprovalLevel.getOrgUnitLevel(); OrganisationUnitLevel ouLevel = organisationUnitService.getOrganisationUnitLevelByLevel(ouLevelNumber); String ouLevelName = ouLevel != null ? ouLevel.getName() : "Organisation unit level " + ouLevelNumber; dataApprovalLevel.setOrgUnitLevelName(ouLevelName); } return dataApprovalLevels; }
@Override public List<DataApprovalLevel> getUserDataApprovalLevels() { UserCredentials userCredentials = currentUserService.getCurrentUser().getUserCredentials(); boolean mayApprove = userCredentials.isAuthorized(DataApproval.AUTH_APPROVE); boolean mayApproveAtLowerLevels = userCredentials.isAuthorized(DataApproval.AUTH_APPROVE_LOWER_LEVELS); boolean mayAcceptAtLowerLevels = userCredentials.isAuthorized(DataApproval.AUTH_ACCEPT_LOWER_LEVELS); if (!mayApprove && !mayApproveAtLowerLevels && !mayAcceptAtLowerLevels) { return new ArrayList<>(); } int lowestNumberOrgUnitLevel = getCurrentUsersLowestNumberOrgUnitLevel(); boolean canSeeAllDimensions = CollectionUtils.isEmpty(userService.getCoDimensionConstraints(userCredentials)) && CollectionUtils.isEmpty(userService.getCogDimensionConstraints(userCredentials)); List<DataApprovalLevel> approvalLevels = getAllDataApprovalLevels(); List<DataApprovalLevel> userDataApprovalLevels = new ArrayList<>(); boolean addLevel = false; for (DataApprovalLevel approvalLevel : approvalLevels) { if (!addLevel && approvalLevel.getOrgUnitLevel() >= lowestNumberOrgUnitLevel) { CategoryOptionGroupSet cogs = approvalLevel.getCategoryOptionGroupSet(); addLevel = securityService.canRead(approvalLevel) && cogs == null ? canSeeAllDimensions : (securityService.canRead(cogs) && !CollectionUtils.isEmpty(categoryService.getCategoryOptionGroups(cogs))); } if (addLevel) { userDataApprovalLevels.add(approvalLevel); } } return userDataApprovalLevels; }
@Override public boolean dataApprovalLevelExists(DataApprovalLevel level) { List<DataApprovalLevel> dataApprovalLevels = getAllDataApprovalLevels(); for (DataApprovalLevel dataApprovalLevel : dataApprovalLevels) { if (level.levelEquals(dataApprovalLevel)) { return true; } } return false; }
@Override public DataApprovalLevel getHighestDataApprovalLevel(OrganisationUnit orgUnit) { int orgUnitLevel = orgUnit.getLevel(); DataApprovalLevel levelAbove = null; int levelAboveOrgUnitLevel = 0; List<DataApprovalLevel> userApprovalLevels = getUserDataApprovalLevels(); for (DataApprovalLevel level : userApprovalLevels) { log.debug("Get highest data approval level: " + level.getName()); if (level.getOrgUnitLevel() == orgUnitLevel) { return level; // Exact match on org unit level. } else if (level.getOrgUnitLevel() > levelAboveOrgUnitLevel) { levelAbove = level; // Must be first matching approval level for this org unit level. levelAboveOrgUnitLevel = level.getOrgUnitLevel(); } } return levelAbove; // Closest ancestor above, or null if none. }
@Override public Map<OrganisationUnit, Integer> getUserReadApprovalLevels(DataApprovalLevel approvalLevel) { Map<OrganisationUnit, Integer> map = new HashMap<>(); User user = currentUserService.getCurrentUser(); Collection<OrganisationUnit> orgUnits = user.getDataViewOrganisationUnits(); if (orgUnits == null || orgUnits.isEmpty()) { orgUnits = organisationUnitService.getRootOrganisationUnits(); } for (OrganisationUnit orgUnit : orgUnits) { map.put(orgUnit, approvalLevel.getLevel()); } return map; }
@Override public void deleteDataApprovalLevel(DataApprovalLevel dataApprovalLevel) { List<DataApprovalLevel> dataApprovalLevels = getAllDataApprovalLevels(); int index = dataApprovalLevel.getLevel() - 1; if (index >= 0 && index < dataApprovalLevels.size()) { dataApprovalLevelStore.delete(dataApprovalLevel); dataApprovalLevels.remove(index); // Move up from here to end, to avoid duplicate level in database. for (int i = index; i < dataApprovalLevels.size(); i++) { update(dataApprovalLevels.get(i), i); } } }
@Override public boolean prepareAddDataApproval(DataApprovalLevel level) { List<DataApprovalLevel> dataApprovalLevels = getAllDataApprovalLevels(); int index = getInsertIndex(dataApprovalLevels, level); if (index < 0) { return false; } dataApprovalLevels.add(index, level); // Move down from end to here, to avoid duplicate level in database. for (int i = dataApprovalLevels.size() - 1; i > index; i--) { update(dataApprovalLevels.get(i), i); } level.setLevel(index + 1); return true; }
/** * Updates a data approval level object by setting the level to correspond with the list index, * setting the updated date to now, and updating the object on disk. * * @param dataApprovalLevel data approval level to update * @param index index of the object (used to set the level.) */ private void update(DataApprovalLevel dataApprovalLevel, int index) { dataApprovalLevel.setLevel(index + 1); dataApprovalLevelStore.update(dataApprovalLevel); }
@Override public int addDataApprovalLevel(DataApprovalLevel approvalLevel, int level) { approvalLevel.setLevel(level); return dataApprovalLevelStore.save(approvalLevel); }