From 70f9bd8f7dd49dcd81606288e46cfe329b0311c6 Mon Sep 17 00:00:00 2001
From: uhensler <urs.hensler@frentix.com>
Date: Fri, 21 Feb 2020 08:54:14 +0100
Subject: [PATCH] OO-4285: Users of "open for all" courses act as participants

---
 .../IsCourseParticipantFunction.java          |  4 +-
 .../EditorUserCourseEnvironmentImpl.java      |  5 +
 .../course/nodes/cal/CourseCalendars.java     |  2 +-
 .../calendar/CourseCalendarController.java    |  2 +-
 .../run/userview/UserCourseEnvironment.java   |  9 ++
 .../userview/UserCourseEnvironmentImpl.java   | 45 ++++++---
 .../CurriculumElementCalendarController.java  |  2 +-
 .../UserCourseEnvironmentImplTest.java        | 92 +++++++++++++++++++
 .../java/org/olat/test/AllTestsJunit4.java    |  1 +
 9 files changed, 145 insertions(+), 17 deletions(-)
 create mode 100644 src/test/java/org/olat/course/run/userview/UserCourseEnvironmentImplTest.java

diff --git a/src/main/java/org/olat/course/condition/interpreter/IsCourseParticipantFunction.java b/src/main/java/org/olat/course/condition/interpreter/IsCourseParticipantFunction.java
index 208d32ba2c4..29ad7900405 100644
--- a/src/main/java/org/olat/course/condition/interpreter/IsCourseParticipantFunction.java
+++ b/src/main/java/org/olat/course/condition/interpreter/IsCourseParticipantFunction.java
@@ -21,8 +21,8 @@
 
 package org.olat.course.condition.interpreter;
 
-import org.olat.core.id.Identity;
 import org.apache.logging.log4j.Logger;
+import org.olat.core.id.Identity;
 import org.olat.core.logging.Tracing;
 import org.olat.course.editor.CourseEditorEnv;
 import org.olat.course.run.userview.UserCourseEnvironment;
@@ -70,7 +70,7 @@ public class IsCourseParticipantFunction extends AbstractFunction {
 			//administrator of any course
 			isParticipant = getUserCourseEnv().isParticipantOfAnyCourse();
 		} else {
-			isParticipant = getUserCourseEnv().isParticipant();
+			isParticipant = getUserCourseEnv().isMemberParticipant();
 		}
 		if (log.isDebugEnabled()) {
 			Identity ident = getUserCourseEnv().getIdentityEnvironment().getIdentity();
diff --git a/src/main/java/org/olat/course/editor/EditorUserCourseEnvironmentImpl.java b/src/main/java/org/olat/course/editor/EditorUserCourseEnvironmentImpl.java
index 783342d80f8..062246115af 100644
--- a/src/main/java/org/olat/course/editor/EditorUserCourseEnvironmentImpl.java
+++ b/src/main/java/org/olat/course/editor/EditorUserCourseEnvironmentImpl.java
@@ -144,6 +144,11 @@ public class EditorUserCourseEnvironmentImpl implements UserCourseEnvironment {
 		return false;
 	}
 
+	@Override
+	public boolean isMemberParticipant() {
+		return false;
+	}
+
 	@Override
 	public boolean isAdministratorOfAnyCourse() {
 		return false;
diff --git a/src/main/java/org/olat/course/nodes/cal/CourseCalendars.java b/src/main/java/org/olat/course/nodes/cal/CourseCalendars.java
index 1b8f04ee771..c7f2b397ba6 100644
--- a/src/main/java/org/olat/course/nodes/cal/CourseCalendars.java
+++ b/src/main/java/org/olat/course/nodes/cal/CourseCalendars.java
@@ -109,7 +109,7 @@ public class CourseCalendars {
 			courseKalendarWrapper.setPrivateEventsVisible(true);
 		} else {
 			courseKalendarWrapper.setAccess(KalendarRenderWrapper.ACCESS_READ_ONLY);
-			courseKalendarWrapper.setPrivateEventsVisible(userCourseEnv.isAdmin() || userCourseEnv.isCoach() || userCourseEnv.isParticipant());
+			courseKalendarWrapper.setPrivateEventsVisible(userCourseEnv.isAdmin() || userCourseEnv.isCoach() || userCourseEnv.isMemberParticipant());
 		}
 		CalendarUserConfiguration config = calendarManager.findCalendarConfigForIdentity(courseKalendarWrapper.getKalendar(), ureq.getIdentity());
 		if (config != null) {
diff --git a/src/main/java/org/olat/course/run/calendar/CourseCalendarController.java b/src/main/java/org/olat/course/run/calendar/CourseCalendarController.java
index 7ca107e40b9..7575f1cb558 100644
--- a/src/main/java/org/olat/course/run/calendar/CourseCalendarController.java
+++ b/src/main/java/org/olat/course/run/calendar/CourseCalendarController.java
@@ -82,7 +82,7 @@ public class CourseCalendarController extends BasicController {
 			courseKalendarWrapper.setPrivateEventsVisible(true);
 		} else {
 			courseKalendarWrapper.setAccess(KalendarRenderWrapper.ACCESS_READ_ONLY);
-			courseKalendarWrapper.setPrivateEventsVisible(userCourseEnv.isAdmin() || userCourseEnv.isCoach() || userCourseEnv.isParticipant());
+			courseKalendarWrapper.setPrivateEventsVisible(userCourseEnv.isAdmin() || userCourseEnv.isCoach() || userCourseEnv.isMemberParticipant());
 		}
 		CalendarUserConfiguration config = calendarManager.findCalendarConfigForIdentity(courseKalendarWrapper.getKalendar(), getIdentity());
 		if (config != null) {
diff --git a/src/main/java/org/olat/course/run/userview/UserCourseEnvironment.java b/src/main/java/org/olat/course/run/userview/UserCourseEnvironment.java
index 3b7bfdadd88..1c796c5df42 100644
--- a/src/main/java/org/olat/course/run/userview/UserCourseEnvironment.java
+++ b/src/main/java/org/olat/course/run/userview/UserCourseEnvironment.java
@@ -81,10 +81,19 @@ public interface UserCourseEnvironment {
 
 	/**
 	 * Is a participant of the course, within the course as in relation of a group.
+	 * Users in a open course are participants as well.
+	 * 
 	 * @return
 	 */
 	public boolean isParticipant();
 	
+	/**
+	 * Is the identity a member with the role participant of the course?
+	 * 
+	 * @return
+	 */
+	public boolean isMemberParticipant();
+	
 	public boolean isIdentityInCourseGroup(Long groupKey);
 	
 	
diff --git a/src/main/java/org/olat/course/run/userview/UserCourseEnvironmentImpl.java b/src/main/java/org/olat/course/run/userview/UserCourseEnvironmentImpl.java
index 1eff5d2676f..96cb87905ca 100644
--- a/src/main/java/org/olat/course/run/userview/UserCourseEnvironmentImpl.java
+++ b/src/main/java/org/olat/course/run/userview/UserCourseEnvironmentImpl.java
@@ -70,7 +70,7 @@ public class UserCourseEnvironmentImpl implements UserCourseEnvironment {
 	
 	private final WindowControl windowControl;
 	
-	private Boolean admin, coach, participant;
+	private Boolean admin, coach, participant, allUsersParticipant;
 	private Boolean adminAnyCourse, coachAnyCourse, participantAnyCourse;
 	
 	private Boolean certification;
@@ -101,7 +101,6 @@ public class UserCourseEnvironmentImpl implements UserCourseEnvironment {
 		this.participant = participant;
 		this.windowControl = windowControl;
 		this.courseReadOnly = courseReadOnly;
-		initScoreAccounting();
 	}
 
 	public static UserCourseEnvironmentImpl load(UserRequest ureq, ICourse course, RepositoryEntrySecurity reSecurity, WindowControl wControl) {
@@ -130,14 +129,6 @@ public class UserCourseEnvironmentImpl implements UserCourseEnvironment {
 				reSecurity.isCoach(), reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isMasterCoach() , reSecurity.isParticipant(),
 				reSecurity.isReadOnly() || reSecurity.isOnlyPrincipal() || reSecurity.isOnlyMasterCoach());
 	}
-
-	private void initScoreAccounting() {
-		if (isParticipant()) {
-			scoreAccounting =  new AssessmentAccounting(this);
-		} else {
-			scoreAccounting = new NoEvaluationAccounting();
-		}
-	}
 	
 	@Override
 	public CourseEnvironment getCourseEnvironment() {
@@ -161,8 +152,15 @@ public class UserCourseEnvironmentImpl implements UserCourseEnvironment {
 
 	@Override
 	public ScoreAccounting getScoreAccounting() {
+		if (scoreAccounting == null) {
+			initScoreAccounting();
+		}
 		return scoreAccounting;
 	}
+	
+	private void initScoreAccounting() {
+		scoreAccounting = isParticipant()? new AssessmentAccounting(this): new NoEvaluationAccounting();
+	}
 
 	@Override
 	public CourseEditorEnv getCourseEditorEnv() {
@@ -212,15 +210,37 @@ public class UserCourseEnvironmentImpl implements UserCourseEnvironment {
 
 	@Override
 	public boolean isParticipant() {
-		if(participant != null) {
-			return participant.booleanValue();
+		// User is membership participant
+		if(participant != null && participant.booleanValue()) {
+			return true;
+		}
+		
+		// If a course is open to all users, a user may is not a member but has access as well.
+		// Such a user has to act as a participant as well.
+		if (allUsersParticipant == null) {
+			boolean allUsersOnly = !isAdmin() && !isCoach() && !getIdentityEnvironment().getRoles().isGuestOnly();
+			allUsersParticipant = Boolean.valueOf(allUsersOnly);
+		}
+		if (allUsersParticipant.booleanValue()) {
+			return true;
 		}
+		
+		// User is not membership participant
+		if(participant != null && !participant.booleanValue()) {
+			return false;
+		}
+		
 		//lazy loading
 		CourseGroupManager cgm = courseEnvironment.getCourseGroupManager();
 		boolean partLazy = cgm.isIdentityCourseParticipant(identityEnvironment.getIdentity());
 		participant = Boolean.valueOf(partLazy);
 		return partLazy;
 	}
+	
+	@Override
+	public boolean isMemberParticipant() {
+		return courseEnvironment.getCourseGroupManager().isIdentityCourseParticipant(identityEnvironment.getIdentity());
+	}
 
 	@Override
 	public boolean isAdministratorOfAnyCourse() {
@@ -354,5 +374,6 @@ public class UserCourseEnvironmentImpl implements UserCourseEnvironment {
 		if (participantChanged) {
 			initScoreAccounting();
 		}
+		this.allUsersParticipant = null;
 	}
 }
diff --git a/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementCalendarController.java b/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementCalendarController.java
index 91b4a19412a..98ace2ba45a 100644
--- a/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementCalendarController.java
+++ b/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementCalendarController.java
@@ -120,7 +120,7 @@ public class CurriculumElementCalendarController extends BasicController impleme
 			courseKalendarWrapper.setPrivateEventsVisible(true);
 		} else {
 			courseKalendarWrapper.setAccess(KalendarRenderWrapper.ACCESS_READ_ONLY);
-			courseKalendarWrapper.setPrivateEventsVisible(userCourseEnv.isAdmin() || userCourseEnv.isCoach() || userCourseEnv.isParticipant());
+			courseKalendarWrapper.setPrivateEventsVisible(userCourseEnv.isAdmin() || userCourseEnv.isCoach() || userCourseEnv.isMemberParticipant());
 		}
 		CalendarUserConfiguration config = calendarManager.findCalendarConfigForIdentity(courseKalendarWrapper.getKalendar(), getIdentity());
 		if (config != null) {
diff --git a/src/test/java/org/olat/course/run/userview/UserCourseEnvironmentImplTest.java b/src/test/java/org/olat/course/run/userview/UserCourseEnvironmentImplTest.java
new file mode 100644
index 00000000000..e208f3aac3c
--- /dev/null
+++ b/src/test/java/org/olat/course/run/userview/UserCourseEnvironmentImplTest.java
@@ -0,0 +1,92 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <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 the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <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>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.run.userview;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.junit.Test;
+import org.olat.core.id.IdentityEnvironment;
+import org.olat.core.id.Roles;
+import org.olat.course.run.environment.CourseEnvironment;
+
+/**
+ * 
+ * Initial date: 21.02.2020<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public class UserCourseEnvironmentImplTest {
+
+	@Test
+	public void shouldBeParticipantIfIsMemebershipParticipant() {
+		IdentityEnvironment identEnv = mock(IdentityEnvironment.class, RETURNS_DEEP_STUBS);
+		CourseEnvironment courseEnv = mock(CourseEnvironment.class, RETURNS_DEEP_STUBS);
+		UserCourseEnvironmentImpl sut =  new UserCourseEnvironmentImpl(identEnv, courseEnv);
+		
+		sut.setUserRoles(Boolean.FALSE, Boolean.FALSE, Boolean.TRUE);
+		
+		assertThat(sut.isParticipant()).isTrue();
+	}
+	
+	@Test
+	public void shouldNotBeParticipantIfIsMemberAdminOnly() {
+		IdentityEnvironment identEnv = mock(IdentityEnvironment.class, RETURNS_DEEP_STUBS);
+		CourseEnvironment courseEnv = mock(CourseEnvironment.class, RETURNS_DEEP_STUBS);
+		UserCourseEnvironmentImpl sut =  new UserCourseEnvironmentImpl(identEnv, courseEnv);
+		
+		sut.setUserRoles(Boolean.TRUE, Boolean.FALSE, Boolean.FALSE);
+		
+		assertThat(sut.isParticipant()).isFalse();
+	}
+	
+	@Test
+	public void shouldNotBeParticipantIfIsMemberCoachOnly() {
+		IdentityEnvironment identEnv = mock(IdentityEnvironment.class, RETURNS_DEEP_STUBS);
+		CourseEnvironment courseEnv = mock(CourseEnvironment.class, RETURNS_DEEP_STUBS);
+		UserCourseEnvironmentImpl sut =  new UserCourseEnvironmentImpl(identEnv, courseEnv);
+		
+		sut.setUserRoles(Boolean.FALSE, Boolean.TRUE, Boolean.FALSE);
+		
+		assertThat(sut.isParticipant()).isFalse();
+	}
+
+	@Test
+	public void shouldNotBeParticipantIfIsGuestOnly() {
+		IdentityEnvironment identEnv = mock(IdentityEnvironment.class);
+		when(identEnv.getRoles()).thenReturn(Roles.guestRoles());
+		CourseEnvironment courseEnv = mock(CourseEnvironment.class, RETURNS_DEEP_STUBS);
+		UserCourseEnvironmentImpl sut =  new UserCourseEnvironmentImpl(identEnv, courseEnv);
+		
+		assertThat(sut.isParticipant()).isFalse();
+	}
+	
+	@Test
+	public void shouldBeParticipantIfIsWhetherMemberNorGuestOnly() {
+		IdentityEnvironment identEnv = mock(IdentityEnvironment.class, RETURNS_DEEP_STUBS);
+		CourseEnvironment courseEnv = mock(CourseEnvironment.class, RETURNS_DEEP_STUBS);
+		UserCourseEnvironmentImpl sut =  new UserCourseEnvironmentImpl(identEnv, courseEnv);
+		
+		assertThat(sut.isParticipant()).isTrue();
+	}
+
+}
diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java
index 2a60aaafa87..5f2d79787a1 100644
--- a/src/test/java/org/olat/test/AllTestsJunit4.java
+++ b/src/test/java/org/olat/test/AllTestsJunit4.java
@@ -487,6 +487,7 @@ import org.junit.runners.Suite;
 	org.olat.course.nodes.st.assessment.STLastModificationsEvaluatorTest.class,
 	org.olat.course.nodes.st.assessment.STStatusEvaluatorTest.class,
 	org.olat.course.run.scoring.AverageCompletionEvaluatorTest.class,
+	org.olat.course.run.userview.UserCourseEnvironmentImplTest.class,
 	org.olat.login.validation.PasswordSyntaxValidatorTest.class,
 	org.olat.login.validation.PasswordValidationRuleFactoryTest.class,
 	org.olat.modules.assessment.model.OverridableImplTest.class,
-- 
GitLab