///////////////////////////////////////////////////////////////////////////// // // Project ProjectForge Community Edition // www.projectforge.org // // Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de) // // ProjectForge is dual-licensed. // // This community edition is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as published // by the Free Software Foundation; version 3 of the License. // // This community edition is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General // Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, see http://www.gnu.org/licenses/. // ///////////////////////////////////////////////////////////////////////////// package org.projectforge.access; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.Validate; import org.hibernate.Hibernate; import org.hibernate.criterion.Restrictions; import org.projectforge.core.BaseDao; import org.projectforge.core.BaseSearchFilter; import org.projectforge.core.QueryFilter; import org.projectforge.task.TaskDO; import org.projectforge.task.TaskDao; import org.projectforge.task.TaskNode; import org.projectforge.task.TaskTree; import org.projectforge.user.GroupDO; import org.projectforge.user.GroupDao; import org.projectforge.user.PFUserDO; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; /** * * @author Kai Reinhard (k.reinhard@micromata.de) * */ public class AccessDao extends BaseDao<GroupTaskAccessDO> { // private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(AccessDao.class); private static final String[] ADDITIONAL_SEARCH_FIELDS = new String[] { "task.title", "group.name"}; private TaskTree taskTree; private TaskDao taskDao; private GroupDao groupDao; public void setTaskTree(final TaskTree taskTree) { this.taskTree = taskTree; } public void setTaskDao(final TaskDao taskDao) { this.taskDao = taskDao; } public AccessDao() { super(GroupTaskAccessDO.class); this.supportAfterUpdate = true; } public void setGroupDao(final GroupDao groupDao) { this.groupDao = groupDao; } /** * @param access * @param taskId If null, then task will be set to null; * @see BaseDao#getOrLoad(Integer) */ public void setTask(final GroupTaskAccessDO access, final Integer taskId) { final TaskDO task = taskDao.getOrLoad(taskId); access.setTask(task); } /** * @param access * @param groupId If null, then group will be set to null; * @see BaseDao#getOrLoad(Integer) */ public void setGroup(final GroupTaskAccessDO access, final Integer groupId) { final GroupDO group = groupDao.getOrLoad(groupId); access.setGroup(group); } /** * Loads all GroupTaskAccessDO (not deleted ones) without any access checking. * @return */ @Override @SuppressWarnings("unchecked") @Transactional(readOnly = true, propagation = Propagation.SUPPORTS) public List<GroupTaskAccessDO> internalLoadAll() { List<GroupTaskAccessDO> list = getHibernateTemplate().find( "from GroupTaskAccessDO g join fetch g.accessEntries where deleted=false order by g.task.id, g.group.id"); list = selectUnique(list); return list; } @Override protected String[] getAdditionalSearchFields() { return ADDITIONAL_SEARCH_FIELDS; } @SuppressWarnings("unchecked") @Transactional(readOnly = true, propagation = Propagation.SUPPORTS) public GroupTaskAccessDO getEntry(final TaskDO task, final GroupDO group) { Validate.notNull(task); Validate.notNull(task.getId()); Validate.notNull(group); Validate.notNull(group.getId()); final List<GroupTaskAccessDO> list = getHibernateTemplate().find("from GroupTaskAccessDO a where a.task.id = ? and a.group.id = ?", new Object[] { task.getId(), group.getId()}); if (list != null && list.size() == 1) { final GroupTaskAccessDO access = list.get(0); checkLoggedInUserSelectAccess(access); return access; } return null; } @Override public List<GroupTaskAccessDO> getList(final BaseSearchFilter filter) { final AccessFilter myFilter; if (filter instanceof AccessFilter) { myFilter = (AccessFilter) filter; } else { myFilter = new AccessFilter(filter); } final QueryFilter queryFilter = new QueryFilter(myFilter); if (myFilter.getTaskId() != null) { List<Integer> descendants = null; List<Integer> ancestors = null; final TaskNode node = taskTree.getTaskNodeById(myFilter.getTaskId()); if (myFilter.isIncludeDescendentTasks() == true) { descendants = node.getDescendantIds(); } if (myFilter.isInherit() == true || myFilter.isIncludeAncestorTasks() == true) { ancestors = node.getAncestorIds(); } if (descendants != null || ancestors != null) { final List<Integer> taskIds = new ArrayList<Integer>(); if (descendants != null) { taskIds.addAll(descendants); } if (ancestors != null) { taskIds.addAll(ancestors); } taskIds.add(node.getId()); queryFilter.add(Restrictions.in("task.id", taskIds)); } else { queryFilter.add(Restrictions.eq("task.id", myFilter.getTaskId())); } } if (myFilter.getGroupId() != null) { final GroupDO group = new GroupDO(); group.setId(myFilter.getGroupId()); queryFilter.add(Restrictions.eq("group", group)); } final List<GroupTaskAccessDO> qlist = getList(queryFilter); List<GroupTaskAccessDO> list; if (myFilter.getTaskId() != null && myFilter.isInherit() == true && myFilter.isIncludeAncestorTasks() == false) { // Now we have to remove all inherited entries of ancestor nodes which are not declared as recursive. list = new ArrayList<GroupTaskAccessDO>(); final TaskNode taskNode = taskTree.getTaskNodeById(myFilter.getTaskId()); if (taskNode == null) { // Paranoia list = qlist; } else { for (final GroupTaskAccessDO access : qlist) { if (access.isRecursive() == false) { final TaskNode accessNode = taskTree.getTaskNodeById(access.getTaskId()); // && myFilter.getTaskId().equals(access.getTaskId()) == false) { if (accessNode.isParentOf(taskNode) == true) { // This entry is not recursive and inherited, therefore this entry will be ignored. continue; } } list.add(access); } } } else { list = qlist; } if (myFilter.getUserId() != null) { final List<GroupTaskAccessDO> result = new ArrayList<GroupTaskAccessDO>(); for (final GroupTaskAccessDO access : list) { if (userGroupCache.isUserMemberOfGroup(myFilter.getUserId(), access.getGroupId())) { result.add(access); } } return result; } return list; } /** * @return Always true, no generic select access needed for group task access objects. * @see org.projectforge.core.BaseDao#hasSelectAccess() */ @Override public boolean hasSelectAccess(final PFUserDO user, final boolean throwException) { return true; } /** * @return false, if no admin user and the context user is not member of the group. Also deleted entries are only visible for admin users. * @see org.projectforge.core.BaseDao#hasSelectAccess(org.projectforge.core.BaseDO, boolean) */ @Override public boolean hasSelectAccess(final PFUserDO user, final GroupTaskAccessDO obj, final boolean throwException) { Validate.notNull(obj); boolean result = accessChecker.isUserMemberOfAdminGroup(user); if (result == false && obj.isDeleted() == false) { Validate.notNull(user); result = userGroupCache.isUserMemberOfGroup(user.getId(), obj.getGroupId()); } if (throwException == true && result == false) { throw new AccessException(AccessType.GROUP, OperationType.SELECT); } return result; } /** * @see org.projectforge.core.BaseDao#hasAccess(Object, OperationType) */ @Override public boolean hasAccess(final PFUserDO user, final GroupTaskAccessDO obj, final GroupTaskAccessDO oldObj, final OperationType operationType, final boolean throwException) { return accessChecker.hasPermission(user, obj.getTaskId(), AccessType.TASK_ACCESS_MANAGEMENT, operationType, throwException); } /** * @see org.projectforge.core.BaseDao#hasUpdateAccess(Object, Object) */ @Override public boolean hasUpdateAccess(final PFUserDO user, final GroupTaskAccessDO obj, final GroupTaskAccessDO dbObj, final boolean throwException) { Validate.notNull(dbObj); Validate.notNull(obj); Validate.notNull(dbObj.getTaskId()); Validate.notNull(obj.getTaskId()); if (accessChecker.hasPermission(user, obj.getTaskId(), AccessType.TASK_ACCESS_MANAGEMENT, OperationType.UPDATE, throwException) == false) { return false; } if (dbObj.getTaskId().equals(obj.getTaskId()) == false) { // User moves the object to another task: if (accessChecker.hasPermission(user, obj.getTaskId(), AccessType.TASK_ACCESS_MANAGEMENT, OperationType.INSERT, throwException) == false) { // Inserting of object under new task not allowed. return false; } if (accessChecker.hasPermission(user, dbObj.getTaskId(), AccessType.TASK_ACCESS_MANAGEMENT, OperationType.DELETE, throwException) == false) { // Deleting of object under old task not allowed. return false; } } return true; } /** * @see org.projectforge.core.BaseDao#prepareHibernateSearch(org.projectforge.core.ExtendedBaseDO, org.projectforge.access.OperationType) */ @Override protected void prepareHibernateSearch(final GroupTaskAccessDO obj, final OperationType operationType) { final TaskDO task = obj.getTask(); if (task != null && Hibernate.isInitialized(task) == false) { Hibernate.initialize(obj.getTask()); obj.setTask(taskTree.getTaskById(task.getId())); } final GroupDO group = obj.getGroup(); if (group != null && Hibernate.isInitialized(group) == false) { obj.setGroup(userGroupCache.getGroup(obj.getGroupId())); } } @Override protected void afterSaveOrModify(final GroupTaskAccessDO obj) { super.afterSaveOrModify(obj); taskTree.setGroupTaskAccess(obj); } @Override protected void afterUpdate(final GroupTaskAccessDO obj, final GroupTaskAccessDO dbObj) { Validate.notNull(dbObj); final List<AccessEntryDO> entries = obj.getOrderedEntries(); final StringBuffer bufNew = new StringBuffer(); final StringBuffer bufOld = new StringBuffer(); boolean firstNew = true, firstOld = true; for (final AccessEntryDO entry : entries) { final AccessEntryDO dbEntry = dbObj.getAccessEntry(entry.getAccessType()); if (dbEntry != null && dbEntry.getAccessSelect() == entry.getAccessSelect() && dbEntry.getAccessInsert() == entry.getAccessInsert() && dbEntry.getAccessUpdate() == entry.getAccessUpdate() && dbEntry.getAccessDelete() == entry.getAccessDelete()) { // Nothing changed. continue; } if (firstNew == true) { firstNew = false; } else { bufNew.append(";"); } bufNew.append(entry.getAccessType()).append("={").append(entry.getAccessSelect()).append(",").append(entry.getAccessInsert()) .append(",").append(entry.getAccessUpdate()).append(",").append(entry.getAccessDelete()).append("}"); if (dbEntry != null) { if (firstOld == true) { firstOld = false; } else { bufOld.append(";"); } bufOld.append(dbEntry.getAccessType()).append("={").append(dbEntry.getAccessSelect()).append(",").append(dbEntry.getAccessInsert()) .append(",").append(dbEntry.getAccessUpdate()).append(",").append(dbEntry.getAccessDelete()).append("}"); } } if (firstNew == false || firstOld == false) { createHistoryEntry(obj, obj.getId(), "entries", String.class, bufOld.toString(), bufNew.toString()); } } @Override protected GroupTaskAccessDO getBackupObject(final GroupTaskAccessDO dbObj) { final GroupTaskAccessDO access = new GroupTaskAccessDO(); for (final AccessEntryDO dbEntry : dbObj.getAccessEntries()) { final AccessEntryDO entry = new AccessEntryDO(dbEntry.getAccessType()); entry.setAccessSelect(dbEntry.getAccessSelect()); entry.setAccessInsert(dbEntry.getAccessInsert()); entry.setAccessUpdate(dbEntry.getAccessUpdate()); entry.setAccessDelete(dbEntry.getAccessDelete()); access.addAccessEntry(entry); } return access; } @Override protected void afterDelete(final GroupTaskAccessDO obj) { taskTree.removeGroupTaskAccess(obj); } @Override protected void afterUndelete(final GroupTaskAccessDO obj) { taskTree.setGroupTaskAccess(obj); } @Override public boolean hasHistoryAccess(final PFUserDO user, final boolean throwException) { return accessChecker.isUserMemberOfAdminGroup(user, throwException); } @Override public GroupTaskAccessDO newInstance() { return new GroupTaskAccessDO(); } }