diff --git a/src/main/java/org/olat/admin/site/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/site/ui/_i18n/LocalStrings_de.properties index 3566b007c0d858a5e6afd0f72648805ca0106998..3e3306ef6340f9ed87fb987f890a738e1987bfdb 100644 --- a/src/main/java/org/olat/admin/site/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/admin/site/ui/_i18n/LocalStrings_de.properties @@ -46,3 +46,5 @@ restrictToInstResourceManagersAndAuthorsSiteSecurityCallback=Autoren und Lernres restrictToUserManagerSiteSecurityCallback=Benutzerverwalter restrictToGroupManagerSiteSecurityCallback=Gruppenverwalter restrictToPoolAdminSiteSecurityCallback=Poolverwalter +poolPrivateMembersSiteSecurityCallback=Poolmitglieder und Poolverwalter +authorAndPoolPrivateMembersSiteSecurityCallback=Autoren, Poolmitglieder und Poolverwalter diff --git a/src/main/java/org/olat/core/gui/control/_spring/sitedefContext.xml b/src/main/java/org/olat/core/gui/control/_spring/sitedefContext.xml index bff5af93690dbbd9cb092dc612bd424411802c66..36537288afa5be660fa9f341eaabeb6c49f321ff 100644 --- a/src/main/java/org/olat/core/gui/control/_spring/sitedefContext.xml +++ b/src/main/java/org/olat/core/gui/control/_spring/sitedefContext.xml @@ -143,6 +143,16 @@ <property name="catalogManager" ref="catalogManager" /> </bean> + <bean id="poolPrivateMembersSiteSecurityCallback" class="org.olat.modules.qpool.site.PoolPrivateMembersSecurityCallback"> + <property name="qPoolService" ref="qpoolService" /> + <property name="questionPoolModule" ref="qpoolModule" /> + </bean> + + <bean id="authorAndPoolPrivateMembersSiteSecurityCallback" class="org.olat.modules.qpool.site.AuthorAndPoolPrivateMembersSecurityCallback"> + <property name="qPoolService" ref="qpoolService" /> + <property name="questionPoolModule" ref="qpoolModule" /> + </bean> + <!-- Alternative controllers --> <bean id="courseSiteForbiddenAlt" class="org.olat.core.gui.control.navigation.SiteAlternativeControllerCreator"> diff --git a/src/main/java/org/olat/modules/qpool/QPoolService.java b/src/main/java/org/olat/modules/qpool/QPoolService.java index c20094e7ad4bcf8d54e722792790c92840e96364..c4a97b8e8f3689f2dcbffa996081a8433c25bdc9 100644 --- a/src/main/java/org/olat/modules/qpool/QPoolService.java +++ b/src/main/java/org/olat/modules/qpool/QPoolService.java @@ -25,6 +25,7 @@ import java.util.Locale; import java.util.Set; import java.util.zip.ZipOutputStream; +import org.olat.basesecurity.IdentityRef; import org.olat.core.commons.persistence.ResultInfos; import org.olat.core.commons.persistence.SortKey; import org.olat.core.gui.media.MediaResource; @@ -108,6 +109,8 @@ public interface QPoolService { //pools public List<Pool> getPools(Identity identity, Roles roles); + public boolean isMemberOfPrivatePools(IdentityRef identity); + public boolean isOwner(Identity owner, Pool pool); public void addOwners(List<Identity> owners, List<Pool> pools); diff --git a/src/main/java/org/olat/modules/qpool/manager/PoolDAO.java b/src/main/java/org/olat/modules/qpool/manager/PoolDAO.java index 922d786d4f5dbe3c60b766fad7a2b47512927fd4..25168da2e0865f0e9ad2aec3783d1684ba496446 100644 --- a/src/main/java/org/olat/modules/qpool/manager/PoolDAO.java +++ b/src/main/java/org/olat/modules/qpool/manager/PoolDAO.java @@ -26,6 +26,8 @@ import java.util.List; import javax.persistence.TypedQuery; import org.olat.basesecurity.BaseSecurity; +import org.olat.basesecurity.GroupRoles; +import org.olat.basesecurity.IdentityRef; import org.olat.basesecurity.SecurityGroup; import org.olat.basesecurity.SecurityGroupMembershipImpl; import org.olat.core.commons.persistence.DB; @@ -144,6 +146,34 @@ public class PoolDAO { return query.getResultList(); } + public boolean isMemberOfPrivatePools(IdentityRef identity) { + StringBuilder sb = new StringBuilder(); + sb.append("select count(pool.key) from qpool pool") + .append(" where exists (from ").append(SecurityGroupMembershipImpl.class.getName()).append(" as vmember ") + .append(" where vmember.identity.key=:identityKey and vmember.securityGroup=pool.ownerGroup)"); + + Number countPool = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), Number.class) + .setParameter("identityKey", identity.getKey()) + .getSingleResult(); + Number countShared = null; + if(countPool == null || countPool.intValue() <= 0) { + StringBuilder sc = new StringBuilder(); + sc.append("select count(bgi.key) from ").append(org.olat.group.BusinessGroupImpl.class.getName()).append(" as bgi ") + .append(" inner join bgi.baseGroup as baseGroup") + .append(" inner join baseGroup.members as membership") + .append(" where membership.identity.key=:identityKey") + .append(" and membership.role in ('").append(GroupRoles.coach.name()).append("','").append(GroupRoles.participant.name()).append("')") + .append(" and exists (select share from qshareitem share where share.resource=bgi.resource)"); + + countShared = dbInstance.getCurrentEntityManager() + .createQuery(sc.toString(), Number.class) + .setParameter("identityKey", identity.getKey()) + .getSingleResult(); + } + return (countPool != null && countPool.intValue() > 0) || (countShared != null && countShared.intValue() > 0); + } + public List<Pool> getPools(Identity identity, int firstResult, int maxResults) { StringBuilder sb = new StringBuilder(); sb.append("select pool from qpool pool") diff --git a/src/main/java/org/olat/modules/qpool/manager/QuestionPoolServiceImpl.java b/src/main/java/org/olat/modules/qpool/manager/QuestionPoolServiceImpl.java index 8b960b1f7b74de6b7874a3d23c40d2a1d7aaa092..dc708a6c1d9f6a7cf104e61721fc167c077fbc78 100644 --- a/src/main/java/org/olat/modules/qpool/manager/QuestionPoolServiceImpl.java +++ b/src/main/java/org/olat/modules/qpool/manager/QuestionPoolServiceImpl.java @@ -28,6 +28,7 @@ import java.util.Set; import java.util.zip.ZipOutputStream; import org.olat.basesecurity.BaseSecurity; +import org.olat.basesecurity.IdentityRef; import org.olat.basesecurity.SecurityGroup; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.DefaultResultInfos; @@ -320,6 +321,11 @@ public class QuestionPoolServiceImpl implements QPoolService { } return poolDao.getPools(identity, 0, -1); } + + @Override + public boolean isMemberOfPrivatePools(IdentityRef identity) { + return poolDao.isMemberOfPrivatePools(identity); + } @Override public List<QuestionItem2Pool> getPoolInfosByItem(QuestionItemShort item) { diff --git a/src/main/java/org/olat/modules/qpool/model/PoolImpl.java b/src/main/java/org/olat/modules/qpool/model/PoolImpl.java index 3a2d4f1a15aa8ad7a2280899ace79dfca7ae210d..6cd850553d2375640e9a8b565cc130cbb46130cd 100644 --- a/src/main/java/org/olat/modules/qpool/model/PoolImpl.java +++ b/src/main/java/org/olat/modules/qpool/model/PoolImpl.java @@ -58,8 +58,8 @@ public class PoolImpl implements Pool, CreateInfo, ModifiedInfo, Persistable { private static final long serialVersionUID = 581458115174074849L; @Id - @GeneratedValue(generator = "system-uuid") - @GenericGenerator(name = "system-uuid", strategy = "hilo") + @GeneratedValue(generator = "system-uuid") + @GenericGenerator(name = "system-uuid", strategy = "hilo") @Column(name="id", nullable=false, unique=true, insertable=true, updatable=false) private Long key; diff --git a/src/main/java/org/olat/modules/qpool/site/AuthorAndPoolPrivateMembersSecurityCallback.java b/src/main/java/org/olat/modules/qpool/site/AuthorAndPoolPrivateMembersSecurityCallback.java new file mode 100644 index 0000000000000000000000000000000000000000..d7e696b4547ea0f6282fb1f369d549aa371b50ff --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/site/AuthorAndPoolPrivateMembersSecurityCallback.java @@ -0,0 +1,74 @@ +/** + * OLAT - Online Learning and Training<br> + * http://www.olat.org + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Copyright (c) frentix GmbH<br> + * http://www.frentix.com<br> + * <p> + */ +package org.olat.modules.qpool.site; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.control.navigation.SiteSecurityCallback; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.QuestionPoolModule; + +/** + * + * Initial date: 14.10.2014<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AuthorAndPoolPrivateMembersSecurityCallback implements SiteSecurityCallback { + + private QPoolService qPoolService; + private QuestionPoolModule questionPoolModule; + + /** + * [used by Spring] + * @param qPoolService + */ + public void setQPoolService(QPoolService qPoolService) { + this.qPoolService = qPoolService; + } + + /** + * [used by Spring] + * @param questionPoolModule + */ + public void setQuestionPoolModule(QuestionPoolModule questionPoolModule) { + this.questionPoolModule = questionPoolModule; + } + + /** + * @see com.frentix.olat.coursesite.SiteSecurityCallback#isAllowedToLaunchSite(org.olat.core.gui.UserRequest) + */ + @Override + public boolean isAllowedToLaunchSite(UserRequest ureq) { + if (!questionPoolModule.isEnabled() || ureq == null || ureq.getUserSession() == null || ureq.getUserSession().getRoles() == null + || ureq.getIdentity() == null + || ureq.getUserSession().getRoles().isInvitee() || ureq.getUserSession().getRoles().isGuestOnly()) { + return false; + } + Roles roles = ureq.getUserSession().getRoles(); + if (roles.isOLATAdmin() || roles.isPoolAdmin() || roles.isAuthor()) { + return true; + } + Identity identity = ureq.getIdentity(); + return qPoolService.isMemberOfPrivatePools(identity); + } +} diff --git a/src/main/java/org/olat/modules/qpool/site/PoolPrivateMembersSecurityCallback.java b/src/main/java/org/olat/modules/qpool/site/PoolPrivateMembersSecurityCallback.java new file mode 100644 index 0000000000000000000000000000000000000000..27f798a5f61851f3fa8dcd11368ad08d38c9b966 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/site/PoolPrivateMembersSecurityCallback.java @@ -0,0 +1,77 @@ +/** + * OLAT - Online Learning and Training<br> + * http://www.olat.org + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Copyright (c) frentix GmbH<br> + * http://www.frentix.com<br> + * <p> + */ +package org.olat.modules.qpool.site; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.control.navigation.SiteSecurityCallback; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.QuestionPoolModule; + +/** + * + * Initial date: 14.10.2014<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class PoolPrivateMembersSecurityCallback implements SiteSecurityCallback { + + private QPoolService qPoolService; + private QuestionPoolModule questionPoolModule; + + + /** + * [used by Spring] + * @param qPoolService + */ + public void setQPoolService(QPoolService qPoolService) { + this.qPoolService = qPoolService; + } + + /** + * [used by Spring] + * @param questionPoolModule + */ + public void setQuestionPoolModule(QuestionPoolModule questionPoolModule) { + this.questionPoolModule = questionPoolModule; + } + + /** + * @see com.frentix.olat.coursesite.SiteSecurityCallback#isAllowedToLaunchSite(org.olat.core.gui.UserRequest) + */ + @Override + public boolean isAllowedToLaunchSite(UserRequest ureq) { + if (!questionPoolModule.isEnabled() || ureq == null || ureq.getUserSession() == null || ureq.getUserSession().getRoles() == null + || ureq.getIdentity() == null + || ureq.getUserSession().getRoles().isInvitee() || ureq.getUserSession().getRoles().isGuestOnly()) { + return false; + } + + Roles roles = ureq.getUserSession().getRoles(); + if (roles.isOLATAdmin() || roles.isPoolAdmin()) { + return true; + } + + Identity identity = ureq.getIdentity(); + return qPoolService.isMemberOfPrivatePools(identity); + } +} diff --git a/src/test/java/org/olat/modules/qpool/manager/PoolDAOTest.java b/src/test/java/org/olat/modules/qpool/manager/PoolDAOTest.java index b7cc38a1ec9a4b4c5ed3bfae747cb18dbf6b7f68..8c1dcfb6e66487f2f4af5991a345c03c598a4b3a 100644 --- a/src/test/java/org/olat/modules/qpool/manager/PoolDAOTest.java +++ b/src/test/java/org/olat/modules/qpool/manager/PoolDAOTest.java @@ -28,8 +28,12 @@ import java.util.UUID; import junit.framework.Assert; import org.junit.Test; +import org.olat.basesecurity.GroupRoles; import org.olat.core.commons.persistence.DB; import org.olat.core.id.Identity; +import org.olat.group.BusinessGroup; +import org.olat.group.manager.BusinessGroupDAO; +import org.olat.group.manager.BusinessGroupRelationDAO; import org.olat.ims.qti.QTIConstants; import org.olat.modules.qpool.Pool; import org.olat.modules.qpool.QuestionItem; @@ -58,9 +62,15 @@ public class PoolDAOTest extends OlatTestCase { @Autowired private QItemTypeDAO qItemTypeDao; @Autowired + private QuestionItemDAO questionDao; + @Autowired private QItemQueriesDAO qItemQueriesDao; @Autowired private QuestionItemDAO questionItemDao; + @Autowired + private BusinessGroupDAO businessGroupDao; + @Autowired + private BusinessGroupRelationDAO businessGroupRelationDao; @Test public void createPool() { @@ -126,6 +136,55 @@ public class PoolDAOTest extends OlatTestCase { Assert.assertFalse(quidamPoolList.contains(pool)); } + @Test + public void isMemberOfPrivatePools_poolOnly() { + Identity id = JunitTestHelper.createAndPersistIdentityAsUser("Pool-owner-" + UUID.randomUUID().toString()); + Pool pool = poolDao.createPool(id, "NGC owned", false); + Assert.assertNotNull(pool); + dbInstance.commitAndCloseSession(); + + boolean isMember = poolDao.isMemberOfPrivatePools(id); + Assert.assertTrue(isMember); + } + + @Test + public void isMemberOfPrivatePools_groupOnly() { + Identity owner = JunitTestHelper.createAndPersistIdentityAsUser("Group-owner-" + UUID.randomUUID().toString()); + Identity participant = JunitTestHelper.createAndPersistIdentityAsUser("Group-participant-" + UUID.randomUUID().toString()); + //create a group to share 2 items + QItemType mcType = qItemTypeDao.loadByType(QuestionType.MC.name()); + BusinessGroup group = businessGroupDao.createAndPersist(owner, "gdao", "gdao-desc", -1, -1, false, false, false, false, false); + QuestionItem item = questionDao.createAndPersist(owner, "Shared-Item-1", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); + questionDao.share(item, group.getResource()); + + businessGroupRelationDao.addRole(participant, group, GroupRoles.participant.name()); + dbInstance.commitAndCloseSession(); + Assert.assertNotNull(item); + Assert.assertNotNull(group); + + //retrieve them + boolean isOwnerMember = poolDao.isMemberOfPrivatePools(owner); + Assert.assertTrue(isOwnerMember); + boolean isParticipantMember = poolDao.isMemberOfPrivatePools(participant); + Assert.assertTrue(isParticipantMember); + } + + @Test + public void isMemberOfPrivatePools_negativeTest() { + Identity owner = JunitTestHelper.createAndPersistIdentityAsUser("Pool-owner-" + UUID.randomUUID().toString()); + Identity somebody = JunitTestHelper.createAndPersistIdentityAsUser("Somebody-" + UUID.randomUUID().toString()); + //pool + Pool pool = poolDao.createPool(owner, "NGC owned", false); + Assert.assertNotNull(pool); + //group without item + BusinessGroup group = businessGroupDao.createAndPersist(owner, "gdao", "gdao-desc", -1, -1, false, false, false, false, false); + businessGroupRelationDao.addRole(somebody, group, GroupRoles.participant.name()); + dbInstance.commitAndCloseSession(); + + boolean isMember = poolDao.isMemberOfPrivatePools(somebody); + Assert.assertFalse(isMember); + } + @Test public void addItemToPool() { //create a pool