diff --git a/src/main/java/org/olat/admin/user/course/CourseLeaveDialogBoxController.java b/src/main/java/org/olat/admin/user/course/CourseLeaveDialogBoxController.java
index 3652566f02ab0c0df6d1ea18f9bf875ff155177e..99e7e5d1771024622eacbfe970d2ea5375a9f38e 100644
--- a/src/main/java/org/olat/admin/user/course/CourseLeaveDialogBoxController.java
+++ b/src/main/java/org/olat/admin/user/course/CourseLeaveDialogBoxController.java
@@ -34,6 +34,7 @@ import org.olat.core.id.Identity;
 import org.olat.group.BusinessGroup;
 import org.olat.repository.RepositoryEntry;
 import org.olat.user.UserManager;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -53,6 +54,9 @@ public class CourseLeaveDialogBoxController extends FormBasicController {
 	private final List<BusinessGroup> groupsToLeave;
 	private final List<BusinessGroup> groupsToDelete;
 	
+	@Autowired
+	private UserManager userManager;
+	
 	public CourseLeaveDialogBoxController(UserRequest ureq, WindowControl wControl, Identity leavingIdentity,
 			List<RepositoryEntry> repoEntries, List<BusinessGroup> groupsToLeave, List<BusinessGroup> groupsToDelete) {
 		super(ureq, wControl);
@@ -77,7 +81,7 @@ public class CourseLeaveDialogBoxController extends FormBasicController {
 			repoEntryToLeaveNames.append(entry.getDisplayname());
 		}
 		
-		String identityName = UserManager.getInstance().getUserDisplayName(leavingIdentity);
+		String identityName = userManager.getUserDisplayName(leavingIdentity);
 		String leaveText;
 		if(groupsToLeave.isEmpty()) {
 			leaveText = translate("unsubscribe.text", new String[]{identityName, repoEntryToLeaveNames.toString()});
diff --git a/src/main/java/org/olat/admin/user/course/CourseOverviewController.java b/src/main/java/org/olat/admin/user/course/CourseOverviewController.java
index a7ff2e48f3a9f6d4727438dc4ba6eac771a856ff..eae4081ea690f2277d4bbd4d4cd3f797f697213b 100644
--- a/src/main/java/org/olat/admin/user/course/CourseOverviewController.java
+++ b/src/main/java/org/olat/admin/user/course/CourseOverviewController.java
@@ -233,14 +233,14 @@ public class CourseOverviewController extends BasicController  {
 			}
 			
 			//add the roles
-			if(!memberView.getMembership().isRepoOwner()) {
-				memberView.getMembership().setRepoOwner(membership.isOwner());
+			if(!memberView.getMembership().isRepositoryEntryOwner()) {
+				memberView.getMembership().setRepositoryEntryOwner(membership.isOwner());
 			}
-			if(!memberView.getMembership().isRepoTutor()) {
-				memberView.getMembership().setRepoTutor(membership.isCoach());
+			if(!memberView.getMembership().isRepositoryEntryCoach()) {
+				memberView.getMembership().setRepositoryEntryCoach(membership.isCoach());
 			}
-			if(!memberView.getMembership().isRepoParticipant()) {
-				memberView.getMembership().setRepoParticipant(membership.isParticipant());
+			if(!memberView.getMembership().isRepositoryEntryParticipant()) {
+				memberView.getMembership().setRepositoryEntryParticipant(membership.isParticipant());
 			}
 		}
 
@@ -279,9 +279,9 @@ public class CourseOverviewController extends BasicController  {
 					memberView.setLastTime(membership.getLastModified());
 				}
 				switch(membership.getMembership()) {
-					case owner: memberView.getMembership().setGroupTutor(true); break;
-					case participant: memberView.getMembership().setGroupParticipant(true); break;
-					case waiting: memberView.getMembership().setGroupWaiting(true); break;
+					case owner: memberView.getMembership().setBusinessGroupCoach(true); break;
+					case participant: memberView.getMembership().setBusinessGroupParticipant(true); break;
+					case waiting: memberView.getMembership().setBusinessGroupWaiting(true); break;
 				}
 			}
 		}
@@ -514,7 +514,7 @@ public class CourseOverviewController extends BasicController  {
 			RepositoryEntry re = repositoryManager.lookupRepositoryEntry(view.getRepoKey());	
 			if(!RepositoryEntryManagedFlag.isManaged(re, RepositoryEntryManagedFlag.membersmanagement)) {
 				repoEntryToLeave.add(re);
-				if(view.getMembership().isRepoOwner()) {
+				if(view.getMembership().isRepositoryEntryOwner()) {
 					int numOfOwners = repositoryService.countMembers(re, GroupRoles.owner.name());
 					if(numOfOwners == 1) {
 						showError("error.atleastone", view.getDisplayName());
@@ -589,7 +589,7 @@ public class CourseOverviewController extends BasicController  {
 		for(CourseMemberView view:tableDataModel.getObjects()) {
 			if(repoEntry.getKey().equals(view.getRepoKey())) {
 				CourseMembership membership = view.getMembership();
-				return membership.isRepoOwner() || membership.isRepoTutor() || membership.isRepoParticipant();
+				return membership.isRepositoryEntryOwner() || membership.isRepositoryEntryCoach() || membership.isRepositoryEntryParticipant();
 			}
 		}
 		return false;
@@ -758,7 +758,7 @@ public class CourseOverviewController extends BasicController  {
 		
 		public boolean isFullyManaged() {
 			if(membership != null && !membership.isManagedMembersRepo() &&
-					(membership.isRepoOwner() || membership.isRepoTutor() || membership.isRepoParticipant())) {
+					(membership.isRepositoryEntryOwner() || membership.isRepositoryEntryCoach() || membership.isRepositoryEntryParticipant())) {
 				return false;
 			}
 
@@ -769,6 +769,8 @@ public class CourseOverviewController extends BasicController  {
 					}
 				}
 			}
+			
+			
 			return true;
 		}
 	}
@@ -780,27 +782,27 @@ public class CourseOverviewController extends BasicController  {
 				CourseMemberView membership = (CourseMemberView)val;
 				
 				boolean and = false;
-				if(membership.getMembership().isRepoOwner()) {
+				if(membership.getMembership().isRepositoryEntryOwner()) {
 					and = and(sb, and);
 					sb.append(translate("role.repo.owner"));
 				}
-				if(membership.getMembership().isRepoTutor()) {
+				if(membership.getMembership().isRepositoryEntryCoach()) {
 					and = and(sb, and);
 					sb.append(translate("role.repo.tutor"));
 				}
-				if(membership.getMembership().isRepoParticipant()) {
+				if(membership.getMembership().isRepositoryEntryParticipant()) {
 					and = and(sb, and);
 					sb.append(translate("role.repo.participant"));
 				}
-				if(membership.getMembership().isGroupTutor()) {
+				if(membership.getMembership().isBusinessGroupCoach()) {
 					and = and(sb, and);
 					sb.append(translate("role.group.tutor"));
 				}
-				if(membership.getMembership().isGroupParticipant()) {
+				if(membership.getMembership().isBusinessGroupParticipant()) {
 					and = and(sb, and);
 					sb.append(translate("role.group.participant"));
 				}
-				if(membership.getMembership().isGroupWaiting()) {
+				if(membership.getMembership().isBusinessGroupWaiting()) {
 					and = and(sb, and);
 					sb.append(translate("role.group.waiting"));
 				}
diff --git a/src/main/java/org/olat/basesecurity/OrganisationRoles.java b/src/main/java/org/olat/basesecurity/OrganisationRoles.java
index cd893cf75cdf5a8eb15e82b8f11a7e79b97f3db2..893faf08dce7cc05e68389cdd97c17659afa97f0 100644
--- a/src/main/java/org/olat/basesecurity/OrganisationRoles.java
+++ b/src/main/java/org/olat/basesecurity/OrganisationRoles.java
@@ -36,6 +36,7 @@ public enum OrganisationRoles {
 	groupmanager,
 	poolmanager,
 	curriculummanager,
+	principal,
 	author,
 	coach,
 	user,
@@ -71,6 +72,7 @@ public enum OrganisationRoles {
 				groupmanager,
 				poolmanager,
 				curriculummanager,
+				principal,
 				author,
 				user,
 			};
diff --git a/src/main/java/org/olat/basesecurity/OrganisationService.java b/src/main/java/org/olat/basesecurity/OrganisationService.java
index 8057ea50f5d963a8153c1ce66b3398483c0df3b7..b7544495c1eae77e77241b3b558937de1f964d71 100644
--- a/src/main/java/org/olat/basesecurity/OrganisationService.java
+++ b/src/main/java/org/olat/basesecurity/OrganisationService.java
@@ -182,6 +182,8 @@ public interface OrganisationService {
 	public void setAsGuest(Identity identity);
 	
 	public List<OrganisationMember> getMembers(Organisation organisation);
+	
+	public List<Identity> getMembersIdentity(Organisation organisation, OrganisationRoles role);
 
 	
 	/**
diff --git a/src/main/java/org/olat/basesecurity/manager/OrganisationDAO.java b/src/main/java/org/olat/basesecurity/manager/OrganisationDAO.java
index afe789d65c0b25345fd52f054ccc4f0386c62f3a..0df54387447970281eb78612f7b3e1df6c09ad7c 100644
--- a/src/main/java/org/olat/basesecurity/manager/OrganisationDAO.java
+++ b/src/main/java/org/olat/basesecurity/manager/OrganisationDAO.java
@@ -196,6 +196,21 @@ public class OrganisationDAO {
 		return members;
 	}
 	
+	public List<Identity> getMembersIdentity(OrganisationRef organisation, String role) {
+		StringBuilder sb = new StringBuilder(256);
+		sb.append("select ident from organisation org")
+		  .append(" inner join org.group baseGroup")
+		  .append(" inner join baseGroup.members membership")
+		  .append(" inner join membership.identity ident")
+		  .append(" inner join fetch ident.user identUser")
+		  .append(" where org.key=:organisationKey and membership.role=:role");
+		return dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), Identity.class)
+				.setParameter("organisationKey", organisation.getKey())
+				.setParameter("role", role)
+				.getResultList();
+	}
+	
 	public List<Identity> getIdentities(String organisationIdentifier, String role) {
 		StringBuilder sb = new StringBuilder(256);
 		sb.append("select ident from organisation org")
diff --git a/src/main/java/org/olat/basesecurity/manager/OrganisationServiceImpl.java b/src/main/java/org/olat/basesecurity/manager/OrganisationServiceImpl.java
index e733d885178d34e802d1497ffad7c6997a1a590e..0f408ba86bce1fdfbee00974669f7a085fa4d635 100644
--- a/src/main/java/org/olat/basesecurity/manager/OrganisationServiceImpl.java
+++ b/src/main/java/org/olat/basesecurity/manager/OrganisationServiceImpl.java
@@ -334,6 +334,11 @@ public class OrganisationServiceImpl implements OrganisationService, Initializin
 		return organisationDao.getMembers(organisation);
 	}
 
+	@Override
+	public List<Identity> getMembersIdentity(Organisation organisation, OrganisationRoles role) {
+		return organisationDao.getMembersIdentity(organisation, role.name());
+	}
+
 	@Override
 	public void setAsGuest(Identity identity) {
 		OrganisationImpl defOrganisation = (OrganisationImpl)getDefaultOrganisation();
diff --git a/src/main/java/org/olat/commons/memberlist/ui/MembersListDisplayRunController.java b/src/main/java/org/olat/commons/memberlist/ui/MembersListDisplayRunController.java
index 323d00ea71dfabfae3896470b0ebbc73c540bb5f..74489f52fe09238b8b0d18135f5a281da1ced331 100644
--- a/src/main/java/org/olat/commons/memberlist/ui/MembersListDisplayRunController.java
+++ b/src/main/java/org/olat/commons/memberlist/ui/MembersListDisplayRunController.java
@@ -61,7 +61,7 @@ import org.olat.course.run.environment.CourseEnvironment;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupMembership;
 import org.olat.group.ui.main.MemberListTableModel;
-import org.olat.group.ui.main.MemberView;
+import org.olat.group.ui.main.MemberRow;
 import org.olat.modules.co.ContactFormController;
 import org.olat.repository.RepositoryEntry;
 import org.olat.user.DisplayPortraitManager;
@@ -183,7 +183,7 @@ public class MembersListDisplayRunController extends BasicController {
 		Collections.sort(waiting, idComparator);
 		waitingtList = convertIdentitiesToMembers(waiting);
 		
-		Set<MemberView> duplicateCatcher = new HashSet<>();
+		Set<MemberRow> duplicateCatcher = new HashSet<>();
 		boolean userLastTimeVisible = cacheGroupMemberships(ureq);
 		
 		if (showOwners && !owners.isEmpty()) {
diff --git a/src/main/java/org/olat/commons/memberlist/ui/MembersTableController.java b/src/main/java/org/olat/commons/memberlist/ui/MembersTableController.java
index 35cc968b715fde425ed8f31ae489bd0451408585..c4a7bc314e3326cac3f9ebf3668520d37cf58267 100644
--- a/src/main/java/org/olat/commons/memberlist/ui/MembersTableController.java
+++ b/src/main/java/org/olat/commons/memberlist/ui/MembersTableController.java
@@ -61,10 +61,11 @@ import org.olat.core.util.mail.ContactMessage;
 import org.olat.course.run.environment.CourseEnvironment;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupMembership;
+import org.olat.group.model.MemberView;
 import org.olat.group.ui.main.AbstractMemberListController;
 import org.olat.group.ui.main.MemberListTableModel;
 import org.olat.group.ui.main.MemberListTableModel.Cols;
-import org.olat.group.ui.main.MemberView;
+import org.olat.group.ui.main.MemberRow;
 import org.olat.instantMessaging.InstantMessagingModule;
 import org.olat.instantMessaging.InstantMessagingService;
 import org.olat.instantMessaging.OpenInstantMessageEvent;
@@ -93,9 +94,9 @@ public class MembersTableController extends FormBasicController {
 	private final boolean chatEnabled, canEmail, deduplicateList, editable, userLastTimeVisible;
 	
 	private final List<UserPropertyHandler> userPropertyHandlers;
-	private final List<MemberView> membersList;
+	private final List<MemberRow> membersList;
 	private final RepositoryEntry repoEntry; 
-	private Set<MemberView> duplicateCatcher;
+	private Set<MemberRow> duplicateCatcher;
 
 	@Autowired
 	private UserManager userManager;
@@ -111,7 +112,7 @@ public class MembersTableController extends FormBasicController {
 	
 	private int pageSize = 20;
 	
-	public MembersTableController(UserRequest ureq, WindowControl wControl, List<Identity> members, Set<MemberView> duplicateCatcher, Map<Long,Date> recentLaunches, Map<Long,Date> initialLaunches,
+	public MembersTableController(UserRequest ureq, WindowControl wControl, List<Identity> members, Set<MemberRow> duplicateCatcher, Map<Long,Date> recentLaunches, Map<Long,Date> initialLaunches,
 			List<UserPropertyHandler> userPropertyHandlers, Map<Long,BusinessGroupMembership> groupmemberships, RepositoryEntry repoEntry, BusinessGroup businessGroup, 
 			CourseEnvironment courseEnv, boolean deduplicateList, Translator translator, boolean editable, boolean canEmail, boolean userLastTimeVisible) {
 		super(ureq, wControl, "table");
@@ -130,7 +131,7 @@ public class MembersTableController extends FormBasicController {
 		this.businessGroup = businessGroup;
 		this.courseEnv = courseEnv;
 		
-		this.membersList = getMembersFromIdentity(ureq, members, groupmemberships, recentLaunches, initialLaunches);
+		membersList = getMembersFromIdentity(members, groupmemberships, recentLaunches, initialLaunches);
 	
 		initForm(ureq);
 	}
@@ -162,17 +163,17 @@ public class MembersTableController extends FormBasicController {
 				SelectionEvent se = (SelectionEvent)event;
 				String cmd = se.getCommand();
 				if ("vcard".equals(cmd)) {
-					MemberView row = membersModel.getObject(se.getIndex());
+					MemberRow row = membersModel.getObject(se.getIndex());
 					doOpenHomePage(row, ureq);
 				} else if ("email".equals(cmd)) {
-					MemberView row = membersModel.getObject(se.getIndex());
+					MemberRow row = membersModel.getObject(se.getIndex());
 					doSendEmailToMember(row, ureq);
 				}
 			}	
 		} else if (source instanceof FormLink) {
 			FormLink link = (FormLink)source;
 			String cmd = link.getCmd();
-			MemberView row = (MemberView)link.getUserObject();
+			MemberRow row = (MemberRow)link.getUserObject();
 			if ("im".equals(cmd)) {
 				doOpenChat(row, ureq);
 			} 
@@ -208,14 +209,14 @@ public class MembersTableController extends FormBasicController {
 		//
 	}
 	
-	private List<MemberView> getMembersFromIdentity(UserRequest ureq, List<Identity> identities, 
+	private List<MemberRow> getMembersFromIdentity(List<Identity> identities, 
 			Map<Long,BusinessGroupMembership> groupmemberships,	Map<Long,Date> recentLaunches, Map<Long,Date> initialLaunches) {
 		if (!deduplicateList) {
 			duplicateCatcher = new HashSet<>();
 		}
-		List<MemberView> memberList = new ArrayList<>();		
+		List<MemberRow> memberList = new ArrayList<>();		
 		for (Identity identity : identities) {
-			MemberView member = new MemberView(identity, userPropertyHandlers, getLocale());
+			MemberRow member = new MemberRow(new MemberView(identity, userPropertyHandlers, getLocale()));
 			if (userLastTimeVisible) {
 				if (repoEntry == null) {
 					BusinessGroupMembership groupmembership = groupmemberships.get(identity.getKey());
@@ -230,7 +231,7 @@ public class MembersTableController extends FormBasicController {
 			}
 			if (!duplicateCatcher.contains(member)) {
 				memberList.add(member);
-				if (!identity.equals(ureq.getIdentity())){
+				if (!identity.equals(getIdentity())){
 					forgeChatLink(member);
 				}
 			}
@@ -239,7 +240,7 @@ public class MembersTableController extends FormBasicController {
 		return memberList;
 	}
 	
-	protected void forgeChatLink(MemberView row) {
+	protected void forgeChatLink(MemberRow row) {
 		FormLink chatLink = uifactory.addFormLink("tools_" + counter.incrementAndGet(), "im", "", null, null, Link.NONTRANSLATED);
 		chatLink.setIconLeftCSS("o_icon o_icon_status_unavailable");
 		chatLink.setUserObject(row);
@@ -289,7 +290,7 @@ public class MembersTableController extends FormBasicController {
 		return defaultSortKey;
 	}
 	
-	private void doSendEmailToMember(MemberView member, UserRequest ureq) {
+	private void doSendEmailToMember(MemberRow member, UserRequest ureq) {
 		if (!editable) return;
 		ContactList memberList;
 		Identity identity = securityManager.loadIdentityByKey(member.getIdentityKey());
@@ -341,14 +342,14 @@ public class MembersTableController extends FormBasicController {
 		}
 	}
 	
-	private void doOpenHomePage(MemberView member, UserRequest ureq) {
+	private void doOpenHomePage(MemberRow member, UserRequest ureq) {
 		String url = "[HomePage:" + member.getIdentityKey() + "]";
 		BusinessControl bc = BusinessControlFactory.getInstance().createFromString(url);
 		WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(bc, getWindowControl());
 		NewControllerFactory.getInstance().launch(ureq, bwControl);
 	}
 	
-	private void doOpenChat(MemberView member, UserRequest ureq) {
+	private void doOpenChat(MemberRow member, UserRequest ureq) {
 		Buddy buddy = imService.getBuddyById(member.getIdentityKey());
 		OpenInstantMessageEvent e = new OpenInstantMessageEvent(ureq, buddy);
 		ureq.getUserSession().getSingleUserEventCenter().fireEventToListenersOf(e, InstantMessagingService.TOWER_EVENT_ORES);
diff --git a/src/main/java/org/olat/course/member/MemberListController.java b/src/main/java/org/olat/course/member/MemberListController.java
index 710220607adff25d03c1f7763b11b98077f4b469..c9a2f2d2d36e29b35c2c69711eb69c897620ed1d 100644
--- a/src/main/java/org/olat/course/member/MemberListController.java
+++ b/src/main/java/org/olat/course/member/MemberListController.java
@@ -27,7 +27,7 @@ import org.olat.core.util.StringHelper;
 import org.olat.course.assessment.ui.tool.AssessmentIdentityCourseController;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.group.ui.main.AbstractMemberListController;
-import org.olat.group.ui.main.MemberView;
+import org.olat.group.ui.main.MemberRow;
 import org.olat.group.ui.main.SearchMembersParams;
 import org.olat.repository.RepositoryEntry;
 
@@ -54,7 +54,7 @@ public class MemberListController extends AbstractMemberListController {
 	}
 
 	@Override
-	protected void doOpenAssessmentTool(UserRequest ureq, MemberView member) {
+	protected void doOpenAssessmentTool(UserRequest ureq, MemberRow member) {
 		removeAsListenerAndDispose(identityAssessmentController);
 		
 		Identity assessedIdentity = securityManager.loadIdentityByKey(member.getIdentityKey());
diff --git a/src/main/java/org/olat/course/member/MemberListWithOriginFilterController.java b/src/main/java/org/olat/course/member/MemberListWithOriginFilterController.java
index feeede75a1781d0515bb96ea60b549d053613b7e..6c0bb08ae71e32e1d4467b9f5f6ec9e9fcd76126 100644
--- a/src/main/java/org/olat/course/member/MemberListWithOriginFilterController.java
+++ b/src/main/java/org/olat/course/member/MemberListWithOriginFilterController.java
@@ -32,8 +32,9 @@ import org.olat.core.util.StringHelper;
 import org.olat.course.assessment.ui.tool.AssessmentIdentityCourseController;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.group.ui.main.AbstractMemberListController;
-import org.olat.group.ui.main.MemberView;
+import org.olat.group.ui.main.MemberRow;
 import org.olat.group.ui.main.SearchMembersParams;
+import org.olat.group.ui.main.SearchMembersParams.Origin;
 import org.olat.repository.RepositoryEntry;
 
 /**
@@ -42,7 +43,7 @@ import org.olat.repository.RepositoryEntry;
  */
 public class MemberListWithOriginFilterController extends AbstractMemberListController {
 	
-	private static final  String[] originKeys = new String[]{"all", "repo", "group"};
+	private static final  String[] originKeys = new String[]{ Origin.all.name(), Origin.repositoryEntry.name(), Origin.businessGroup.name(), Origin.curriculum.name()};
 	
 	private SingleSelection originEl;
 	
@@ -78,15 +79,10 @@ public class MemberListWithOriginFilterController extends AbstractMemberListCont
 	@Override
 	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
 		if(originEl == source) {
-			if(!originEl.isOneSelected() || originEl.isSelected(0)) {
-				searchParams.setRepoOrigin(true);
-				searchParams.setGroupOrigin(true);
-			} else if(originEl.isSelected(1)) {
-				searchParams.setRepoOrigin(true);
-				searchParams.setGroupOrigin(false);
-			} else if(originEl.isSelected(2)) {
-				searchParams.setRepoOrigin(false);
-				searchParams.setGroupOrigin(true);
+			if(!originEl.isOneSelected()) {
+				searchParams.setOrigin(Origin.all);
+			} else {
+				searchParams.setOrigin(Origin.valueOf(originEl.getSelectedKey()));
 			}
 			membersTable.deselectAll();
 			reloadModel();
@@ -96,7 +92,7 @@ public class MemberListWithOriginFilterController extends AbstractMemberListCont
 	}
 	
 	@Override
-	protected void doOpenAssessmentTool(UserRequest ureq, MemberView member) {
+	protected void doOpenAssessmentTool(UserRequest ureq, MemberRow member) {
 		removeAsListenerAndDispose(identityAssessmentController);
 		
 		Identity assessedIdentity = securityManager.loadIdentityByKey(member.getIdentityKey());
diff --git a/src/main/java/org/olat/course/member/MemberSearchController.java b/src/main/java/org/olat/course/member/MemberSearchController.java
index cf331a0b52aa127eb8de85a57d58f0b1bccac7df..1961cac53964906b470d9743dad4f468e363ae2b 100644
--- a/src/main/java/org/olat/course/member/MemberSearchController.java
+++ b/src/main/java/org/olat/course/member/MemberSearchController.java
@@ -29,7 +29,7 @@ import org.olat.core.id.Identity;
 import org.olat.course.assessment.ui.tool.AssessmentIdentityCourseController;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.group.ui.main.AbstractMemberListController;
-import org.olat.group.ui.main.MemberView;
+import org.olat.group.ui.main.MemberRow;
 import org.olat.group.ui.main.SearchMembersParams;
 import org.olat.repository.RepositoryEntry;
 
@@ -80,7 +80,7 @@ public class MemberSearchController extends AbstractMemberListController {
 	}
 	
 	@Override
-	protected void doOpenAssessmentTool(UserRequest ureq, MemberView member) {
+	protected void doOpenAssessmentTool(UserRequest ureq, MemberRow member) {
 		removeAsListenerAndDispose(identityAssessmentController);
 		
 		Identity assessedIdentity = securityManager.loadIdentityByKey(member.getIdentityKey());
diff --git a/src/main/java/org/olat/course/member/MemberSearchForm.java b/src/main/java/org/olat/course/member/MemberSearchForm.java
index 4742da57dab868c4d755b22b1ab224692f3d1a47..74e4a933956c31ce663295f9014dfd47a908eddf 100644
--- a/src/main/java/org/olat/course/member/MemberSearchForm.java
+++ b/src/main/java/org/olat/course/member/MemberSearchForm.java
@@ -19,12 +19,13 @@
  */
 package org.olat.course.member;
 
-import java.util.Collection;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.olat.basesecurity.GroupRoles;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
@@ -43,6 +44,7 @@ import org.olat.core.gui.control.WindowControl;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.group.ui.main.SearchMembersParams;
+import org.olat.group.ui.main.SearchMembersParams.Origin;
 import org.olat.user.UserManager;
 import org.olat.user.propertyhandlers.EmailProperty;
 import org.olat.user.propertyhandlers.UserPropertyHandler;
@@ -54,8 +56,8 @@ import org.springframework.beans.factory.annotation.Autowired;
  */
 public class MemberSearchForm extends FormBasicController implements ExtendedFlexiTableSearchController {
 	
-	private String[] roleKeys = {"owner", "tutor", "attendee", "waiting"};
-	private String[] originKeys = new String[]{"all", "repo", "group"};
+	private String[] roleKeys = { GroupRoles.owner.name(), GroupRoles.coach.name(), GroupRoles.participant.name(), GroupRoles.waiting.name() };
+	private String[] originKeys = new String[]{ Origin.all.name(), Origin.repositoryEntry.name(), Origin.businessGroup.name(), Origin.curriculum.name() };
 	
 	private TextElement login;
 	private SingleSelection originEl;
@@ -124,7 +126,7 @@ public class MemberSearchForm extends FormBasicController implements ExtendedFle
 		for(int i=originKeys.length; i-->0; ) {
 			openValues[i] = translate("search." + originKeys[i]);
 		}
-		originEl = uifactory.addRadiosHorizontal("openBg", "search.origin", rightContainer, originKeys, openValues);
+		originEl = uifactory.addRadiosVertical("openBg", "search.origin", rightContainer, originKeys, openValues);
 		originEl.select("all", true);
 
 		FormLayoutContainer buttonLayout = FormLayoutContainer.createDefaultFormLayout("button_layout", getTranslator());
@@ -167,24 +169,19 @@ public class MemberSearchForm extends FormBasicController implements ExtendedFle
 	private void fireSearchEvent(UserRequest ureq) {
 		SearchMembersParams params = new SearchMembersParams();
 		//roles
-		Collection<String> selectedKeys = rolesEl.getSelectedKeys();
-		params.setRepoOwners(selectedKeys.contains("owner"));
-		params.setRepoTutors(selectedKeys.contains("tutor"));
-		params.setGroupTutors(selectedKeys.contains("tutor"));
-		params.setRepoParticipants(selectedKeys.contains("attendee"));
-		params.setGroupParticipants(selectedKeys.contains("attendee"));
-		params.setGroupWaitingList(selectedKeys.contains("waiting"));
+		List<String> selectedKeys = new ArrayList<>(rolesEl.getSelectedKeys());
+		GroupRoles[] roles = new GroupRoles[selectedKeys.size()];
+		for(int i=0; i<selectedKeys.size(); i++) {
+			roles[i] = GroupRoles.valueOf(selectedKeys.get(i));
+		}
+		
+		params.setRoles(roles);
 
 		//origin
-		if(!originEl.isOneSelected() || originEl.isSelected(0)) {
-			params.setRepoOrigin(true);
-			params.setGroupOrigin(true);
-		} else if(originEl.isSelected(1)) {
-			params.setRepoOrigin(true);
-			params.setGroupOrigin(false);
-		} else if(originEl.isSelected(2)) {
-			params.setRepoOrigin(false);
-			params.setGroupOrigin(true);
+		if(!originEl.isOneSelected()) {
+			params.setOrigin(Origin.all);
+		} else {
+			params.setOrigin(Origin.valueOf(originEl.getSelectedKey()));
 		}
 		
 		String loginVal = login.getValue();
diff --git a/src/main/java/org/olat/course/member/MembersManagementMainController.java b/src/main/java/org/olat/course/member/MembersManagementMainController.java
index 976e2de8558cecabaa23831b16475dbc5e27e7f5..610d9e1c8f04170df8bc512741944959a44718b2 100644
--- a/src/main/java/org/olat/course/member/MembersManagementMainController.java
+++ b/src/main/java/org/olat/course/member/MembersManagementMainController.java
@@ -63,7 +63,7 @@ import org.springframework.beans.factory.annotation.Autowired;
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class MembersManagementMainController extends MainLayoutBasicController  implements Activateable2 {
+public class MembersManagementMainController extends MainLayoutBasicController implements Activateable2 {
 	
 	private static final String CMD_MEMBERS = "Members";
 	private static final String CMD_GROUPS = "Groups";
diff --git a/src/main/java/org/olat/course/member/MembersOverviewController.java b/src/main/java/org/olat/course/member/MembersOverviewController.java
index cf1893e23974b252aa0129dac934bf3a205598da..849f2896d07f31bf163b25b18894b1032e25e9c0 100644
--- a/src/main/java/org/olat/course/member/MembersOverviewController.java
+++ b/src/main/java/org/olat/course/member/MembersOverviewController.java
@@ -21,6 +21,7 @@ package org.olat.course.member;
 
 import java.util.List;
 
+import org.olat.basesecurity.GroupRoles;
 import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
@@ -432,7 +433,7 @@ public class MembersOverviewController extends BasicController implements Activa
 			OLATResourceable ores = OresHelper.createOLATResourceableInstance(SEG_ALL_MEMBERS, 0l);
 			ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores));
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
-			SearchMembersParams searchParams = new SearchMembersParams(true, true, true, true, true, false, true);
+			SearchMembersParams searchParams = new SearchMembersParams(true, GroupRoles.owner, GroupRoles.coach, GroupRoles.participant);
 			allMemberListCtrl = new MemberListWithOriginFilterController(ureq, bwControl, toolbarPanel, repoEntry, coachCourseEnv, searchParams, null);
 			listenTo(allMemberListCtrl);
 		}
@@ -449,7 +450,7 @@ public class MembersOverviewController extends BasicController implements Activa
 			OLATResourceable ores = OresHelper.createOLATResourceableInstance(SEG_OWNERS_MEMBERS, 0l);
 			ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores));
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
-			SearchMembersParams searchParams = new SearchMembersParams(true, false, false, false, false, false, false);
+			SearchMembersParams searchParams = new SearchMembersParams(false, GroupRoles.owner);
 			String infos = translate("owners.infos");
 			ownersCtrl = new MemberListController(ureq, bwControl, toolbarPanel, repoEntry, coachCourseEnv, searchParams, infos);
 			listenTo(ownersCtrl);
@@ -467,7 +468,7 @@ public class MembersOverviewController extends BasicController implements Activa
 			OLATResourceable ores = OresHelper.createOLATResourceableInstance(SEG_TUTORS_MEMBERS, 0l);
 			ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores));
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
-			SearchMembersParams searchParams = new SearchMembersParams(false, true, false, true, false, false, false);
+			SearchMembersParams searchParams = new SearchMembersParams(false, GroupRoles.coach);
 			String infos = translate("tutors.infos");
 			tutorsCtrl = new MemberListWithOriginFilterController(ureq, bwControl, toolbarPanel, repoEntry, coachCourseEnv, searchParams, infos);
 			listenTo(tutorsCtrl);
@@ -485,7 +486,7 @@ public class MembersOverviewController extends BasicController implements Activa
 			OLATResourceable ores = OresHelper.createOLATResourceableInstance(SEG_PARTICIPANTS_MEMBERS, 0l);
 			ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores));
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
-			SearchMembersParams searchParams = new SearchMembersParams(false, false, true, false, true, false, true);
+			SearchMembersParams searchParams = new SearchMembersParams(false, GroupRoles.participant);
 			String infos = translate("participants.infos");
 			participantsCtrl = new MemberListWithOriginFilterController(ureq, bwControl, toolbarPanel, repoEntry, coachCourseEnv, searchParams, infos);
 			listenTo(participantsCtrl);
@@ -503,7 +504,7 @@ public class MembersOverviewController extends BasicController implements Activa
 			OLATResourceable ores = OresHelper.createOLATResourceableInstance(SEG_WAITING_MEMBERS, 0l);
 			ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores));
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
-			SearchMembersParams searchParams = new SearchMembersParams(false, false, false, false, false, true, false);
+			SearchMembersParams searchParams = new SearchMembersParams(false, GroupRoles.waiting);
 			String infos = translate("waiting.infos");
 			waitingCtrl = new MemberListController(ureq, bwControl, toolbarPanel, repoEntry, coachCourseEnv, searchParams, infos);
 			listenTo(waitingCtrl);
diff --git a/src/main/java/org/olat/course/member/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/member/_i18n/LocalStrings_de.properties
index 51db894e8a0f3abb01b80da298e92f3df0700777..7b13e1fff8cc18e4709ed69d6e8b6f191ee0c0a4 100644
--- a/src/main/java/org/olat/course/member/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/member/_i18n/LocalStrings_de.properties
@@ -19,7 +19,6 @@ error.atleastone=$org.olat.group.ui.main\:error.atleastone
 error.msg.send.no.rcps=$org.olat.modules.co\:error.msg.send.no.rcps
 error.select.one=$org.olat.group.ui.main\:error.select.one
 error.managed.group=$org.olat.group.ui.main\:error.managed.group
-
 group.add=Gruppe hinzuf\u00FCgen
 group.create=Gruppe erstellen
 group.remove=$org.olat.group.ui.edit\:resource.remove
@@ -51,13 +50,14 @@ role.repo.participant=Teilnehmer
 role.repo.tutor=Betreuer
 search=Suche
 search.all=alle Mitglieder
-search.attendee=$\:role.repo.participant
-search.group=nur Gruppenmitglieder
+search.participant=$\:role.repo.participant
+search.curriculum=nur Curriculummitglieder
+search.businessGroup=nur Gruppenmitglieder
 search.login=Benutzername
 search.origin=Herkunft
 search.origin.alt=Anzeige
 search.owner=$\:role.repo.owner
-search.repo=nur Kursmitglieder
+search.repositoryEntry=nur Kursmitglieder
 search.roles=Rolle
 search.tutor=$\:role.repo.tutor
 search.waiting=$\:role.group.waiting
diff --git a/src/main/java/org/olat/course/member/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/member/_i18n/LocalStrings_en.properties
index c9687cb218557a63434ea4d7160fb3a2508de8fc..72415fd1a30d2f2b770624e6bec04686ee1d1f0f 100644
--- a/src/main/java/org/olat/course/member/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/course/member/_i18n/LocalStrings_en.properties
@@ -50,15 +50,16 @@ role.repo.participant=Participant
 role.repo.tutor=Coach
 search=Search
 search.all=all members
-search.attendee=$\:role.repo.participant
-search.group=only group members
+search.participant=$\:role.repo.participant
+search.curriculum=only curriculum members
+search.businessGroup=only group members
 search.login=User name
 search.origin=Origin
 search.origin.alt=Show
 search.owner=$\:role.repo.owner
-search.repo=only course members
+search.repositoryEntry=only course members
 search.roles=Role
-search.tutor=$\:role.repo.tutor
+search.coach=$\:role.repo.tutor
 search.waiting=Waiting list
 select.group=Add group
 table.header.edit=Edit
diff --git a/src/main/java/org/olat/course/member/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/member/_i18n/LocalStrings_fr.properties
index 6f9a40e65e94fe153a40637a7a9139b4172580c4..e71800e49b18caffc5bb8db069f8a1d7b05f8490 100644
--- a/src/main/java/org/olat/course/member/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/course/member/_i18n/LocalStrings_fr.properties
@@ -50,15 +50,15 @@ role.repo.participant=Participant
 role.repo.tutor=Coach
 search=Recherche
 search.all=tous les membres
-search.attendee=$\:role.repo.participant
-search.group=seulement les membres du groupe
+search.participant=$\:role.repo.participant
+search.businessGroup=seulement les membres du groupe
 search.login=Nom d'utilisateur
 search.origin=Origine
 search.origin.alt=Origine
 search.owner=$\:role.repo.owner
-search.repo=seulement les membres du cours
+search.repositoryEntry=seulement les membres du cours
 search.roles=R\u00F4les
-search.tutor=$\:role.repo.tutor
+search.coach=$\:role.repo.tutor
 search.waiting=$\:role.group.waiting
 select.group=S\u00E9lectionner des groupes
 table.header.edit=Editer
diff --git a/src/main/java/org/olat/course/member/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/course/member/_i18n/LocalStrings_it.properties
index 9aae98182299597614ccde13e2f49aed911006fe..e59aa1c75b488df0ccd1c0c75b41b4affe8a40bf 100644
--- a/src/main/java/org/olat/course/member/_i18n/LocalStrings_it.properties
+++ b/src/main/java/org/olat/course/member/_i18n/LocalStrings_it.properties
@@ -50,15 +50,15 @@ role.repo.participant=Partecipante
 role.repo.tutor=Tutore
 search=Ricerca
 search.all=tutti i membri
-search.attendee=$\:role.repo.participant
-search.group=solo i membri del gruppo
+search.participant=$\:role.repo.participant
+search.businessGroup=solo i membri del gruppo
 search.login=Nome utente
 search.origin=Origine
 search.origin.alt=Mostrare
 search.owner=$\:role.repo.owner
-search.repo=solo membri del corso
+search.repositoryEntry=solo membri del corso
 search.roles=Ruolo
-search.tutor=$\:role.repo.tutor
+search.coach=$\:role.repo.tutor
 search.waiting=$\:role.group.waiting
 select.group=Aggiungere gruppo
 table.header.edit=Modificare
diff --git a/src/main/java/org/olat/course/member/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/course/member/_i18n/LocalStrings_pl.properties
index 3c4968f2938f4d0d554504286f92c773d2e7dcc5..9682c60c159ffc45b19df5b50031d29564271551 100644
--- a/src/main/java/org/olat/course/member/_i18n/LocalStrings_pl.properties
+++ b/src/main/java/org/olat/course/member/_i18n/LocalStrings_pl.properties
@@ -39,15 +39,15 @@ role.repo.participant=Uczestnik
 role.repo.tutor=Nauczyciel
 search=Szukaj
 search.all=wszyscy cz\u0142onkowie
-search.attendee=$\:role.repo.participant
-search.group=tylko cz\u0142onkowie grupy
+search.participant=$\:role.repo.participant
+search.businessGroup=tylko cz\u0142onkowie grupy
 search.login=Nazwa u\u017Cytkownika
 search.origin=Pochodzenie
 search.origin.alt=Poka\u017C
 search.owner=$\:role.repo.owner
-search.repo=tylko cz\u0142onkowie kursu
+search.repositoryEntry=tylko cz\u0142onkowie kursu
 search.roles=Rola
-search.tutor=$\:role.repo.tutor
+search.coach=$\:role.repo.tutor
 search.waiting=Lista oczekuj\u0105cych
 select.group=Dodaj grup\u0119
 table.header.edit=Edytuj
diff --git a/src/main/java/org/olat/course/member/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/course/member/_i18n/LocalStrings_pt_BR.properties
index a9830a321788db7c14aae9006876e08e4a843deb..ad40f595da6833e1d71a2740d641be47cb2088be 100644
--- a/src/main/java/org/olat/course/member/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/course/member/_i18n/LocalStrings_pt_BR.properties
@@ -50,15 +50,15 @@ role.repo.participant=Participante
 role.repo.tutor=Treinador
 search=Buscar
 search.all=Todos membros
-search.attendee=$\:role.repo.participant
-search.group=Apenas membros de grupos
+search.participant=$\:role.repo.participant
+search.businessGroup=Apenas membros de grupos
 search.login=Usu\u00E1rio
 search.origin=Origem
 search.origin.alt=Mostrar
 search.owner=$\:role.repo.owner
-search.repo=Apenas membros de curso
+search.repositoryEntry=Apenas membros de curso
 search.roles=Fun\u00E7\u00E3o
-search.tutor=$\:role.repo.tutor
+search.coach=$\:role.repo.tutor
 search.waiting=Lista de espera
 select.group=Adicionar grupo
 table.header.edit=Editar
diff --git a/src/main/java/org/olat/course/member/_i18n/LocalStrings_zh_CN.properties b/src/main/java/org/olat/course/member/_i18n/LocalStrings_zh_CN.properties
index fac086802ad4e3c24d4cda7076af26321dfd6239..0606c423885fd83890bb9c001647759afa17f4f1 100644
--- a/src/main/java/org/olat/course/member/_i18n/LocalStrings_zh_CN.properties
+++ b/src/main/java/org/olat/course/member/_i18n/LocalStrings_zh_CN.properties
@@ -16,15 +16,15 @@ role.repo.participant=\u53C2\u4E0E\u8005
 role.repo.tutor=\u8F85\u5BFC\u5458
 search=\u68C0\u7D22
 search.all=\u6240\u6709\u6210\u5458
-search.attendee=$\:role.repo.participant
-search.group=\u4EC5\u9650\u7FA4\u7EC4\u6210\u5458
+search.participant=$\:role.repo.participant
+search.businessGroup=\u4EC5\u9650\u7FA4\u7EC4\u6210\u5458
 search.login=\u7528\u6237\u540D\u79F0
 search.origin=\u7C4D\u8D2F
 search.origin.alt=\u901A\u544A
 search.owner=$\:role.repo.owner
-search.repo=\u4EC5\u9650\u8BFE\u7A0B\u6210\u5458
+search.repositoryEntry=\u4EC5\u9650\u8BFE\u7A0B\u6210\u5458
 search.roles=\u89D2\u8272
-search.tutor=$\:role.repo.tutor
+search.coach=$\:role.repo.tutor
 search.waiting=$\:role.group.waiting
 select.group=\u6DFB\u52A0\u7FA4\u7EC4
 table.header.edit=\u5904\u7406
diff --git a/src/main/java/org/olat/group/manager/BusinessGroupDAO.java b/src/main/java/org/olat/group/manager/BusinessGroupDAO.java
index 8c2185b95cf99c07cfdeb3d9832be13db28f9ace..90911886dc37b68d415f13db22477a83f7c418d2 100644
--- a/src/main/java/org/olat/group/manager/BusinessGroupDAO.java
+++ b/src/main/java/org/olat/group/manager/BusinessGroupDAO.java
@@ -292,7 +292,7 @@ public class BusinessGroupDAO {
 			groupKeys.add(group.getKey());
 		}
 
-		Map<IdentityGroupKey, BusinessGroupMembershipImpl> memberships = new HashMap<IdentityGroupKey, BusinessGroupMembershipImpl>();
+		Map<IdentityGroupKey, BusinessGroupMembershipImpl> memberships = new HashMap<>();
 		loadBusinessGroupsMembership(groupKeys, memberships);
 		return new ArrayList<BusinessGroupMembership>(memberships.values());
 	}
diff --git a/src/main/java/org/olat/group/manager/MemberViewQueries.java b/src/main/java/org/olat/group/manager/MemberViewQueries.java
new file mode 100644
index 0000000000000000000000000000000000000000..0b24bcc9d7e48249822e8b79154e27633cabccfc
--- /dev/null
+++ b/src/main/java/org/olat/group/manager/MemberViewQueries.java
@@ -0,0 +1,352 @@
+/**
+ * <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.group.manager;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.persistence.TypedQuery;
+
+import org.olat.basesecurity.GroupRoles;
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.commons.persistence.PersistenceHelper;
+import org.olat.core.id.Identity;
+import org.olat.core.util.StringHelper;
+import org.olat.group.BusinessGroup;
+import org.olat.group.model.MemberView;
+import org.olat.group.ui.main.SearchMembersParams;
+import org.olat.group.ui.main.SearchMembersParams.Origin;
+import org.olat.repository.RepositoryEntry;
+import org.olat.user.propertyhandlers.UserPropertyHandler;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * Initial date: 6 juin 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+public class MemberViewQueries {
+	
+	@Autowired
+	private DB dbInstance;
+	
+	public List<MemberView> getBusinessGroupMembers(BusinessGroup businessGroup, SearchMembersParams params,
+			List<UserPropertyHandler> userPropertyHandlers, Locale locale) {
+		if(businessGroup == null) return Collections.emptyList();
+		
+		StringBuilder sb = new StringBuilder();
+		sb.append("select membership.key, membership.role, membership.creationDate, membership.lastModified, ident")
+		  .append(" from businessgroup as grp")
+		  .append(" inner join grp.baseGroup as baseGroup")
+		  .append(" inner join baseGroup.members as membership")
+		  .append(" inner join membership.identity as ident")
+		  .append(" inner join fetch ident.user as identUser")
+		  .append(" where grp.key=:businessGroupKey");
+		searchByIdentity(sb, params);
+		
+		TypedQuery<Object[]> query = dbInstance.getCurrentEntityManager()
+			.createQuery(sb.toString(), Object[].class)
+			.setParameter("businessGroupKey", businessGroup.getKey());
+		searchByIdentity(query, params);
+		
+		List<Object[]> rawObjects = query.getResultList();
+		Map<Identity,MemberView> views = new HashMap<>();
+		for(Object[] objects:rawObjects) {
+			int pos = 1;// 0 is the membershipKey
+			String role = (String)objects[pos++];
+			Date creationDate = (Date)objects[pos++];
+			Date lastModified = (Date)objects[pos++];
+			
+			Identity identity = (Identity)objects[pos++];
+			MemberView view = views.computeIfAbsent(identity, id -> new MemberView(id, userPropertyHandlers, locale, creationDate, lastModified));
+			view.addGroup(businessGroup);
+			view.getMemberShip().setBusinessGroupRole(role);
+		}
+
+		getPending(views, businessGroup, params, userPropertyHandlers, locale);
+		
+		List<MemberView> members = new ArrayList<>(views.values());
+		filterByRoles(members, params);
+		filterByOrigin(members, params);
+		return members;
+	}
+	
+	public List<MemberView> getRepositoryEntryMembers(RepositoryEntry entry, SearchMembersParams params,
+			List<UserPropertyHandler> userPropertyHandlers, Locale locale) {
+		if(entry == null) return Collections.emptyList();
+
+		Map<Identity,MemberView> views = getMembersView(entry, params, userPropertyHandlers, locale);
+		getPending(views, entry, params, userPropertyHandlers, locale);
+		
+		List<MemberView> members = new ArrayList<>(views.values());
+		filterByRoles(members, params);
+		filterByOrigin(members, params);
+		return members;
+	}
+	
+	private Map<Identity,MemberView> getMembersView(RepositoryEntry entry, SearchMembersParams params,
+			List<UserPropertyHandler> userPropertyHandlers, Locale locale) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select membership.key, membership.role, membership.creationDate, membership.lastModified, ident, relGroup.defaultGroup,")
+		  .append("  grp.key, grp.name, grp.managedFlagsString,")
+		  .append("  curriculumEl.key, curriculumEl.displayName, curriculumEl.managedFlagsString")
+		  .append(" from repositoryentry as v ")
+		  .append(" inner join v.groups as relGroup")
+		  .append(" inner join relGroup.group as baseGroup")
+		  .append(" inner join baseGroup.members as membership")
+		  .append(" inner join membership.identity as ident")
+		  .append(" inner join fetch ident.user as identUser")
+		  .append(" left join businessgroup as grp on (grp.baseGroup.key=baseGroup.key)")
+		  .append(" left join curriculumelement as curriculumEl on (curriculumEl.group.key=baseGroup.key)")
+		  .append(" where v.key=:repoEntryKey");
+		searchByIdentity(sb, params);
+		
+		TypedQuery<Object[]> query = dbInstance.getCurrentEntityManager()
+			.createQuery(sb.toString(), Object[].class)
+			.setParameter("repoEntryKey", entry.getKey());
+		searchByIdentity(query, params);
+		
+		List<Object[]> rawObjects = query.getResultList();
+		Map<Identity,MemberView> views = new HashMap<>();
+		for(Object[] objects:rawObjects) {
+			int pos = 1;// 0 is the membershipKey
+			String role = (String)objects[pos++];
+			Date creationDate = (Date)objects[pos++];
+			Date lastModified = (Date)objects[pos++];
+			Identity member = (Identity)objects[pos++];
+			MemberView view = views.computeIfAbsent(member, id -> new MemberView(id, userPropertyHandlers, locale, creationDate, lastModified));
+
+			Boolean defaultGroup = (Boolean)objects[pos++];
+
+			Long groupKey = (Long)objects[pos++];
+			String groupName = (String)objects[pos++];
+			String groupManagedflags = (String)objects[pos++];
+
+			Long curriculumElementKey = (Long)objects[pos++];
+			String curriculumElementName = (String)objects[pos++];
+			String curriculumElementManagedFlags = (String)objects[pos++];
+
+			if(defaultGroup != null && defaultGroup.booleanValue()) {
+				view.setRepositoryEntryDisplayName(entry.getDisplayname());
+				view.setManagedFlags(entry.getManagedFlags());
+				view.getMemberShip().setRepositoryEntryRole(role);
+			} else if(groupKey != null) {
+				view.addGroup(new MemberView.BusinessGroupShortImpl(groupKey, groupName, groupManagedflags));
+				view.getMemberShip().setBusinessGroupRole(role);
+			} else if(curriculumElementKey != null) {
+				view.addCurriculumElement(new MemberView.CurriculumElementShortImpl(curriculumElementKey, curriculumElementName, curriculumElementManagedFlags));
+				view.getMemberShip().setCurriculumElementRole(role);
+			}
+		}
+		return views;
+	}
+	
+	private void getPending(Map<Identity,MemberView> views, RepositoryEntry entry, SearchMembersParams params,
+			List<UserPropertyHandler> userPropertyHandlers, Locale locale) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select ident from resourcereservation as reservation")
+		  .append(" inner join reservation.identity as ident")
+		  .append(" inner join fetch ident.user as identUser")
+		  .append(" where reservation.resource.key in (select v.olatResource.key from repositoryentry as v where v.key=:repoEntryKey)")
+		  .append(" or reservation.resource.key in (select grp.resource.key from businessgroup as grp")
+		  .append("   inner join repoentrytogroup as rel on (grp.baseGroup.key=rel.group.key)")
+		  .append("   where rel.entry.key=:repoEntryKey")
+		  .append(" )");
+		searchByIdentity(sb, params);
+
+		TypedQuery<Identity> query = dbInstance.getCurrentEntityManager()
+			.createQuery(sb.toString(), Identity.class)
+			.setParameter("repoEntryKey", entry.getKey());
+		searchByIdentity(query, params);
+		
+		List<Identity> identities = query.getResultList();
+		for(Identity identity:identities) {
+			views.computeIfAbsent(identity, id -> new MemberView(id, userPropertyHandlers, locale)).setPending(true);
+		}
+	}
+	
+	private void getPending(Map<Identity,MemberView> views, BusinessGroup entry, SearchMembersParams params,
+			List<UserPropertyHandler> userPropertyHandlers, Locale locale) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select ident from resourcereservation as reservation")
+		  .append(" inner join reservation.identity as ident")
+		  .append(" inner join fetch ident.user as identUser")
+		  .append(" inner join businessgroup as grp on (reservation.resource.key = grp.resource.key)")
+		  .append(" where grp.key=:groupKey");
+		searchByIdentity(sb, params);
+		
+		TypedQuery<Identity> query = dbInstance.getCurrentEntityManager()
+			.createQuery(sb.toString(), Identity.class)
+			.setParameter("groupKey", entry.getKey());
+		searchByIdentity(query, params);
+		
+		List<Identity> identities = query.getResultList();
+		for(Identity identity:identities) {
+			views.computeIfAbsent(identity, id -> new MemberView(id, userPropertyHandlers, locale)).setPending(true);
+		}
+	}
+	
+	private void searchByIdentity(StringBuilder sb, SearchMembersParams params) {
+		if (params.getLogin() == null && (params.getUserPropertiesSearch() == null || params.getUserPropertiesSearch().isEmpty())) return;
+
+		sb.append(" and (");			
+
+		// append query for login
+		boolean appendOr = false;
+		
+		if (params.getLogin() != null) {
+			appendOr = true;
+			if (params.getLogin().contains("_") && dbInstance.isOracle()) {
+				//oracle needs special ESCAPE sequence to search for escaped strings
+				sb.append("lower(ident.name) like :login ESCAPE '\\'");
+			} else if (dbInstance.isMySQL()) {
+				sb.append("ident.name like :login");
+			} else {
+				sb.append("lower(ident.name) like :login");
+			}
+		}
+
+		// append queries for user fields
+		if (params.getUserPropertiesSearch() != null && !params.getUserPropertiesSearch().isEmpty()) {
+			// add other fields
+			for (String key : params.getUserPropertiesSearch().keySet()) {
+				if(appendOr) {
+					sb.append(" or ");
+				} else {
+					appendOr = true;
+				}
+				
+				if(dbInstance.isMySQL()) {
+					sb.append("identUser.").append(key).append(" like :").append(key).append("_value");
+				} else {
+					sb.append("lower(identUser.").append(key).append(") like :").append(key).append("_value");
+				}
+				if(dbInstance.isOracle()) {
+					sb.append(" escape '\\'");
+				}
+			}
+		}
+
+		sb.append(" )");
+	}
+	
+	private void searchByIdentity(TypedQuery<?> query, SearchMembersParams params) {
+		if (params.getLogin() != null) {
+			String login = PersistenceHelper.makeFuzzyQueryString(params.getLogin());
+			query.setParameter("login", login.toLowerCase());
+		}
+
+		//	 add user properties attributes
+		if (params.getUserPropertiesSearch() != null && !params.getUserPropertiesSearch().isEmpty()) {
+			for (Map.Entry<String, String> entry : params.getUserPropertiesSearch().entrySet()) {
+				String value = entry.getValue();
+				value = PersistenceHelper.makeFuzzyQueryString(value);
+				query.setParameter(entry.getKey() + "_value", value.toLowerCase());
+			}
+		}
+	}
+	
+	private void filterByOrigin(List<MemberView> memberList, SearchMembersParams params) {
+		if(params.getOrigin() == Origin.businessGroup) {
+			for(Iterator<MemberView> it=memberList.iterator(); it.hasNext(); ) {
+				MemberView m = it.next();
+				if(m.getGroups() == null || m.getGroups().isEmpty()) {
+					it.remove();
+				}
+			}
+		} else if(params.getOrigin() == Origin.curriculum) {
+			for(Iterator<MemberView> it=memberList.iterator(); it.hasNext(); ) {
+				MemberView m = it.next();
+				if(m.getCurriculumElements() == null || m.getCurriculumElements().isEmpty()) {
+					it.remove();
+				}
+			}
+		} else if(params.getOrigin() == Origin.repositoryEntry) {
+			for(Iterator<MemberView> it=memberList.iterator(); it.hasNext(); ) {
+				if(!StringHelper.containsNonWhitespace(it.next().getRepositoryEntryDisplayName())) {
+					it.remove();
+				}
+			}
+		}
+	}
+	
+	/**
+	 * This filter method preserve the multiple roles of a member. If we want only the waiting list but
+	 * a member is in the waiting list and owner of the course, we want it to know.
+	 * @param memberList
+	 * @param params
+	 * @return
+	 */
+	private void filterByRoles(Collection<MemberView> memberList, SearchMembersParams params) {
+		List<MemberView> members = new ArrayList<>(memberList);
+
+		if(params.isRole(GroupRoles.owner)) {
+			for(Iterator<MemberView> it=members.iterator(); it.hasNext(); ) {
+				if(it.next().getMemberShip().isOwner()) {
+					it.remove();
+				}
+			}
+		}
+	
+		if(params.isRole(GroupRoles.participant)) {
+			for(Iterator<MemberView> it=members.iterator(); it.hasNext(); ) {
+				if(it.next().getMemberShip().isParticipant()) {
+					it.remove();
+				}
+			}
+		}
+		
+		if(params.isRole(GroupRoles.coach)) {
+			for(Iterator<MemberView> it=members.iterator(); it.hasNext(); ) {
+				if(it.next().getMemberShip().isCoach()) {
+					it.remove();
+				}
+			}
+		}
+		
+		if(params.isRole(GroupRoles.waiting)) {
+			for(Iterator<MemberView> it=members.iterator(); it.hasNext(); ) {
+				if(it.next().getMemberShip().isBusinessGroupWaiting()) {
+					it.remove();
+				}
+			}
+		}
+
+		if(params.isPending()) {
+			for(Iterator<MemberView> it=members.iterator(); it.hasNext(); ) {
+				if(it.next().isPending()) {
+					it.remove();
+				}
+			}
+		}
+		
+		memberList.removeAll(members);
+	}
+}
diff --git a/src/main/java/org/olat/group/model/MemberView.java b/src/main/java/org/olat/group/model/MemberView.java
new file mode 100644
index 0000000000000000000000000000000000000000..12fd89c36f4d564bf063d57c5f8f9c5f81c060d5
--- /dev/null
+++ b/src/main/java/org/olat/group/model/MemberView.java
@@ -0,0 +1,215 @@
+/**
+ * <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.group.model;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+import org.olat.core.id.Identity;
+import org.olat.group.BusinessGroupManagedFlag;
+import org.olat.group.BusinessGroupShort;
+import org.olat.group.ui.main.CourseMembership;
+import org.olat.modules.curriculum.CurriculumElementManagedFlag;
+import org.olat.modules.curriculum.CurriculumElementShort;
+import org.olat.repository.RepositoryEntryManagedFlag;
+import org.olat.user.UserPropertiesRow;
+import org.olat.user.propertyhandlers.UserPropertyHandler;
+
+/**
+ * 
+ * Initial date: 6 juin 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class MemberView extends UserPropertiesRow {
+	
+	private String repositoryEntryDisplayName;
+	private RepositoryEntryManagedFlag[] managedFlags;
+	
+	private List<BusinessGroupShort> groups;
+	private List<CurriculumElementShort> curriculumElements;
+	
+	private Date creationDate;
+	private Date lastModified;
+	
+	private boolean pending;
+	private boolean managedMembersRepo;
+	private final CourseMembership membership = new CourseMembership();
+	
+	public MemberView(Identity identity, List<UserPropertyHandler> userPropertyHandlers, Locale locale) {
+		this(identity, userPropertyHandlers, locale, null, null);
+	}
+	
+	public MemberView(Identity identity, List<UserPropertyHandler> userPropertyHandlers, Locale locale, Date creationDate, Date lastModified) {
+		super(identity, userPropertyHandlers, locale);
+		this.creationDate = creationDate;
+		this.lastModified = lastModified;
+	}
+
+	public Date getCreationDate() {
+		return creationDate;
+	}
+
+	public void setCreationDate(Date creationDate) {
+		this.creationDate = creationDate;
+	}
+
+	public Date getLastModified() {
+		return lastModified;
+	}
+
+	public void setLastModified(Date lastModified) {
+		this.lastModified = lastModified;
+	}
+
+	public String getRepositoryEntryDisplayName() {
+		return repositoryEntryDisplayName;
+	}
+
+	public void setRepositoryEntryDisplayName(String displayName) {
+		this.repositoryEntryDisplayName = displayName;
+	}
+
+	public RepositoryEntryManagedFlag[] getManagedFlags() {
+		return managedFlags;
+	}
+
+	public void setManagedFlags(RepositoryEntryManagedFlag[] managedFlags) {
+		this.managedFlags = managedFlags;
+	}
+
+	public List<BusinessGroupShort> getGroups() {
+		return groups;
+	}
+
+	public void setGroups(List<BusinessGroupShort> groups) {
+		this.groups = groups;
+	}
+	
+	public void addGroup(BusinessGroupShort group) {
+		if(groups == null) {
+			groups = new ArrayList<>(5);
+		}
+		groups.add(group);
+	}
+
+	public List<CurriculumElementShort> getCurriculumElements() {
+		return curriculumElements;
+	}
+
+	public void setCurriculumElements(List<CurriculumElementShort> curriculumElements) {
+		this.curriculumElements = curriculumElements;
+	}
+	
+	public void addCurriculumElement(CurriculumElementShort curriculumElement) {
+		if(curriculumElements == null) {
+			curriculumElements = new ArrayList<>(3);
+		}
+		curriculumElements.add(curriculumElement);
+	}
+	
+	public CourseMembership getMemberShip() {
+		return membership;
+	}
+
+	public boolean isManagedMembersRepo() {
+		return managedMembersRepo;
+	}
+
+	public void setManagedMembersRepo(boolean managedMembersRepo) {
+		this.managedMembersRepo = managedMembersRepo;
+	}
+	
+	public boolean isPending() {
+		return pending;
+	}
+
+	public void setPending(boolean pending) {
+		this.pending = pending;
+	}
+
+	public static class BusinessGroupShortImpl implements BusinessGroupShort {
+		
+		private final Long key;
+		private final String name;
+		private final BusinessGroupManagedFlag[] managedFlags;
+		
+		public BusinessGroupShortImpl(Long key, String name, String managedFlags) {
+			this.key = key;
+			this.name = name;
+			this.managedFlags = BusinessGroupManagedFlag.toEnum(managedFlags);
+		}
+
+		@Override
+		public String getResourceableTypeName() {
+			return "BusinessGroup";
+		}
+
+		@Override
+		public Long getResourceableId() {
+			return key;
+		}
+
+		@Override
+		public Long getKey() {
+			return key;
+		}
+
+		@Override
+		public String getName() {
+			return name;
+		}
+
+		@Override
+		public BusinessGroupManagedFlag[] getManagedFlags() {
+			return managedFlags;
+		}
+	}
+	
+	public static class CurriculumElementShortImpl implements CurriculumElementShort {
+		
+		private final Long key;
+		private final String displayName;
+		private final CurriculumElementManagedFlag[] managedFlags;
+		
+		public CurriculumElementShortImpl(Long key, String displayName, String managedFlags) {
+			this.key = key;
+			this.displayName = displayName;
+			this.managedFlags = CurriculumElementManagedFlag.toEnum(managedFlags);
+		}
+
+		@Override
+		public Long getKey() {
+			return key;
+		}
+
+		@Override
+		public String getDisplayName() {
+			return displayName;
+		}
+
+		@Override
+		public CurriculumElementManagedFlag[] getManagedFlags() {
+			return managedFlags;
+		}
+	}
+}
diff --git a/src/main/java/org/olat/group/ui/edit/BusinessGroupMembersController.java b/src/main/java/org/olat/group/ui/edit/BusinessGroupMembersController.java
index 1369f2bbd10855a3b76141d70ced179ac3d8160b..c9c7a91acad02095a51cba1bce79ac9d7879a30a 100644
--- a/src/main/java/org/olat/group/ui/edit/BusinessGroupMembersController.java
+++ b/src/main/java/org/olat/group/ui/edit/BusinessGroupMembersController.java
@@ -21,6 +21,7 @@ package org.olat.group.ui.edit;
 
 import java.util.List;
 
+import org.olat.basesecurity.GroupRoles;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.link.Link;
@@ -97,7 +98,7 @@ public class BusinessGroupMembersController extends BasicController {
 		configForm.setMembershipConfiguration(businessGroup);
 		mainVC.put("configMembers", configForm.getInitialComponent());
 		
-		SearchMembersParams searchParams = new SearchMembersParams(false, false, false, true, true, true, true);
+		SearchMembersParams searchParams = new SearchMembersParams(true, GroupRoles.coach, GroupRoles.participant, GroupRoles.waiting);
 		membersController = new MemberListController(ureq, getWindowControl(), toolbarPanel, businessGroup, searchParams);
 		listenTo(membersController);
 		
diff --git a/src/main/java/org/olat/group/ui/edit/MemberListController.java b/src/main/java/org/olat/group/ui/edit/MemberListController.java
index 59f82a63c9de7e43b47380b1c9a65bf1abf76e52..472a6ed9423f6df9ae0fbc81e6e071d03fbfaa9e 100644
--- a/src/main/java/org/olat/group/ui/edit/MemberListController.java
+++ b/src/main/java/org/olat/group/ui/edit/MemberListController.java
@@ -24,7 +24,7 @@ import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.group.BusinessGroup;
 import org.olat.group.ui.main.AbstractMemberListController;
-import org.olat.group.ui.main.MemberView;
+import org.olat.group.ui.main.MemberRow;
 import org.olat.group.ui.main.SearchMembersParams;
 
 /**
@@ -42,7 +42,7 @@ public class MemberListController extends AbstractMemberListController {
 	}
 	
 	@Override
-	protected void doOpenAssessmentTool(UserRequest ureq, MemberView member) {
+	protected void doOpenAssessmentTool(UserRequest ureq, MemberRow member) {
 		//
 	}
 
diff --git a/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java b/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java
index c8a0ced4a5404754cb79fec56ed955a17a7bc89a..f8ad7eb9281fbdf626e8747161750fffc586a094 100644
--- a/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java
+++ b/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java
@@ -20,14 +20,11 @@
 package org.olat.group.ui.main;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -35,9 +32,7 @@ import java.util.concurrent.atomic.AtomicInteger;
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.BaseSecurityModule;
 import org.olat.basesecurity.GroupRoles;
-import org.olat.basesecurity.SearchIdentityParams;
 import org.olat.core.commons.persistence.DBFactory;
-import org.olat.core.commons.persistence.PersistenceHelper;
 import org.olat.core.commons.persistence.SortKey;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
@@ -77,7 +72,6 @@ import org.olat.core.id.Roles;
 import org.olat.core.id.UserConstants;
 import org.olat.core.id.context.ContextEntry;
 import org.olat.core.id.context.StateEntry;
-import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.core.util.mail.ContactList;
 import org.olat.core.util.mail.ContactMessage;
@@ -88,11 +82,12 @@ import org.olat.course.assessment.manager.UserCourseInformationsManager;
 import org.olat.course.member.MemberListController;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupManagedFlag;
-import org.olat.group.BusinessGroupMembership;
 import org.olat.group.BusinessGroupModule;
 import org.olat.group.BusinessGroupService;
 import org.olat.group.BusinessGroupShort;
+import org.olat.group.manager.MemberViewQueries;
 import org.olat.group.model.BusinessGroupMembershipChange;
+import org.olat.group.model.MemberView;
 import org.olat.group.ui.main.MemberListTableModel.Cols;
 import org.olat.instantMessaging.InstantMessagingModule;
 import org.olat.instantMessaging.InstantMessagingService;
@@ -104,11 +99,7 @@ import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryEntryManagedFlag;
 import org.olat.repository.RepositoryManager;
 import org.olat.repository.RepositoryService;
-import org.olat.repository.model.RepositoryEntryMembership;
 import org.olat.repository.model.RepositoryEntryPermissionChangeEvent;
-import org.olat.resource.OLATResource;
-import org.olat.resource.accesscontrol.ACService;
-import org.olat.resource.accesscontrol.ResourceReservation;
 import org.olat.user.UserInfoMainController;
 import org.olat.user.UserManager;
 import org.olat.user.propertyhandlers.UserPropertyHandler;
@@ -160,6 +151,8 @@ public abstract class AbstractMemberListController extends FormBasicController i
 	private boolean overrideManaged = false;
 	private final boolean globallyManaged;
 	
+	@Autowired
+	private MemberViewQueries memberQueries;
 	@Autowired
 	protected UserManager userManager;
 	@Autowired
@@ -177,8 +170,6 @@ public abstract class AbstractMemberListController extends FormBasicController i
 	@Autowired
 	private BusinessGroupModule groupModule;
 	@Autowired
-	private ACService acService;
-	@Autowired
 	private InstantMessagingModule imModule;
 	@Autowired
 	private InstantMessagingService imService;
@@ -349,7 +340,7 @@ public abstract class AbstractMemberListController extends FormBasicController i
 			if(event instanceof SelectionEvent) {
 				SelectionEvent se = (SelectionEvent)event;
 				String cmd = se.getCommand();
-				MemberView row = memberListModel.getObject(se.getIndex());
+				MemberRow row = memberListModel.getObject(se.getIndex());
 				if(TABLE_ACTION_IM.equals(cmd)) {
 					doIm(ureq, row);
 				} else if(TABLE_ACTION_EDIT.equals(cmd)) {
@@ -370,38 +361,38 @@ public abstract class AbstractMemberListController extends FormBasicController i
 				}
 			}
 		} else if(editButton == source) {
-			List<MemberView> selectedItems = getMultiSelectedRows();
+			List<MemberRow> selectedItems = getMultiSelectedRows();
 			openEdit(ureq, selectedItems);
 		} else if(mailButton == source) {
-			List<MemberView> selectedItems = getMultiSelectedRows();
+			List<MemberRow> selectedItems = getMultiSelectedRows();
 			doSendMail(ureq, selectedItems);
 		} else if(removeButton == source) {
-			List<MemberView> selectedItems = getMultiSelectedRows();
+			List<MemberRow> selectedItems = getMultiSelectedRows();
 			confirmDelete(ureq, selectedItems);
 		} else if(source instanceof FormLink) {
 			FormLink link = (FormLink)source;
 			String cmd = link.getCmd();
 			if("tools".equals(cmd)) {
-				MemberView row = (MemberView)link.getUserObject();
+				MemberRow row = (MemberRow)link.getUserObject();
 				doOpenTools(ureq, row, link);
 			} else if("im".equals(cmd)) {
-				MemberView row = (MemberView)link.getUserObject();
+				MemberRow row = (MemberRow)link.getUserObject();
 				doIm(ureq, row);
 			}
 		}
 		super.formInnerEvent(ureq, source, event);
 	}
 	
-	private List<MemberView> getMultiSelectedRows() {
+	private List<MemberRow> getMultiSelectedRows() {
 		Set<Integer> selections = membersTable.getMultiSelectedIndex();
-		List<MemberView> rows = new ArrayList<>(selections.size());
+		List<MemberRow> rows = new ArrayList<>(selections.size());
 		if(selections.isEmpty()) {
 			//do nothing
 		} else {
 			for(Integer i:selections) {
 				int index = i.intValue();
 				if(index >= 0 && index < memberListModel.getRowCount()) {
-					MemberView row = memberListModel.getObject(index);
+					MemberRow row = memberListModel.getObject(index);
 					if(row != null) {
 						rows.add(row);
 					}
@@ -476,7 +467,7 @@ public abstract class AbstractMemberListController extends FormBasicController i
 		editSingleMemberCtrl = null;
 	}
 	
-	protected void confirmDelete(UserRequest ureq, List<MemberView> members) {
+	protected void confirmDelete(UserRequest ureq, List<MemberRow> members) {
 		if(members.isEmpty()) {
 			showWarning("error.select.one.user");
 		} else {
@@ -485,8 +476,8 @@ public abstract class AbstractMemberListController extends FormBasicController i
 					: repositoryService.countMembers(repoEntry, GroupRoles.owner.name());
 			
 			int numOfRemovedOwner = 0;
-			List<Long> identityKeys = new ArrayList<Long>();
-			for(MemberView member:members) {
+			List<Long> identityKeys = new ArrayList<>();
+			for(MemberRow member:members) {
 				identityKeys.add(member.getIdentityKey());
 				if(member.getMembership().isOwner()) {
 					numOfRemovedOwner++;
@@ -507,7 +498,7 @@ public abstract class AbstractMemberListController extends FormBasicController i
 		}
 	}
 	
-	protected void openEdit(UserRequest ureq, MemberView member) {
+	protected void openEdit(UserRequest ureq, MemberRow member) {
 		if(editSingleMemberCtrl != null) return;
 		
 		Identity identity = securityManager.loadIdentityByKey(member.getIdentityKey());
@@ -519,7 +510,7 @@ public abstract class AbstractMemberListController extends FormBasicController i
 		listenTo(cmc);
 	}
 	
-	protected void openEdit(UserRequest ureq, List<MemberView> members) {
+	protected void openEdit(UserRequest ureq, List<MemberRow> members) {
 		if(members.isEmpty()) {
 			showWarning("error.select.one.user");
 		} else {
@@ -542,16 +533,22 @@ public abstract class AbstractMemberListController extends FormBasicController i
 	}
 	
 	protected void doSearch(String search) {
-		getSearchParams().setSearchString(search);
+		Map<String,String> propertiesSearch = new HashMap<>();
+		for(UserPropertyHandler handler:userPropertyHandlers) {
+			propertiesSearch.put(handler.getName(), search);
+		}
+		getSearchParams().setUserPropertiesSearch(propertiesSearch);
+		getSearchParams().setLogin(search);
 		reloadModel();
 	}
 	
 	protected void doResetSearch() {
-		getSearchParams().setSearchString(null);
+		getSearchParams().setLogin(null);
+		getSearchParams().setUserPropertiesSearch(null);
 		reloadModel();
 	}
 	
-	private void doOpenTools(UserRequest ureq, MemberView row, FormLink link) {
+	private void doOpenTools(UserRequest ureq, MemberRow row, FormLink link) {
 		removeAsListenerAndDispose(toolsCtrl);
 		removeAsListenerAndDispose(toolsCalloutCtrl);
 
@@ -569,7 +566,7 @@ public abstract class AbstractMemberListController extends FormBasicController i
 	 * @param ureq
 	 * @param member
 	 */
-	protected void doIm(UserRequest ureq, MemberView member) {
+	protected void doIm(UserRequest ureq, MemberRow member) {
 		Buddy buddy = imService.getBuddyById(member.getIdentityKey());
 		OpenInstantMessageEvent e = new OpenInstantMessageEvent(ureq, buddy);
 		ureq.getUserSession().getSingleUserEventCenter().fireEventToListenersOf(e, InstantMessagingService.TOWER_EVENT_ORES);
@@ -634,7 +631,7 @@ public abstract class AbstractMemberListController extends FormBasicController i
 		reloadModel();
 	}
 	
-	protected void doSendMail(UserRequest ureq, List<MemberView> members) {
+	protected void doSendMail(UserRequest ureq, List<MemberRow> members) {
 		List<Long> identityKeys = getMemberKeys(members);
 		List<Identity> identities = securityManager.loadIdentityByKeys(identityKeys);
 		if(identities.isEmpty()) {
@@ -657,7 +654,7 @@ public abstract class AbstractMemberListController extends FormBasicController i
 		listenTo(cmc);
 	}
 	
-	protected void doGraduate(List<MemberView> members) {
+	protected void doGraduate(List<MemberRow> members) {
 		if(businessGroup != null) {
 			List<Long> identityKeys = getMemberKeys(members);
 			List<Identity> identitiesToGraduate = securityManager.loadIdentityByKeys(identityKeys);
@@ -666,7 +663,7 @@ public abstract class AbstractMemberListController extends FormBasicController i
 		} else {
 			Map<Long, BusinessGroup> groupsMap = new HashMap<>();
 			Map<BusinessGroup, List<Identity>> graduatesMap = new HashMap<>();
-			for(MemberView member:members) {
+			for(MemberRow member:members) {
 				List<BusinessGroupShort> groups = member.getGroups();
 				if(groups != null && groups.size() > 0) {
 					Identity memberIdentity = securityManager.loadIdentityByKey(member.getIdentityKey());
@@ -699,7 +696,7 @@ public abstract class AbstractMemberListController extends FormBasicController i
 		reloadModel();
 	}
 	
-	protected void doOpenVisitingCard(UserRequest ureq, MemberView member) {
+	protected void doOpenVisitingCard(UserRequest ureq, MemberRow member) {
 		removeAsListenerAndDispose(visitingCardCtrl);
 		Identity choosenIdentity = securityManager.loadIdentityByKey(member.getIdentityKey());
 		visitingCardCtrl = new UserInfoMainController(ureq, getWindowControl(), choosenIdentity, false, false);
@@ -709,7 +706,7 @@ public abstract class AbstractMemberListController extends FormBasicController i
 		toolbarPanel.pushController(fullname, visitingCardCtrl);
 	}
 	
-	protected void doOpenContact(UserRequest ureq, MemberView member) {
+	protected void doOpenContact(UserRequest ureq, MemberRow member) {
 		removeAsListenerAndDispose(contactCtrl);
 		
 		Identity choosenIdentity = securityManager.loadIdentityByKey(member.getIdentityKey());
@@ -728,12 +725,12 @@ public abstract class AbstractMemberListController extends FormBasicController i
 		toolbarPanel.pushController(fullname, contactCtrl);
 	}
 	
-	protected abstract void doOpenAssessmentTool(UserRequest ureq, MemberView member);
+	protected abstract void doOpenAssessmentTool(UserRequest ureq, MemberRow member);
 	
-	protected List<Long> getMemberKeys(List<MemberView> members) {
+	protected List<Long> getMemberKeys(List<MemberRow> members) {
 		List<Long> keys = new ArrayList<Long>(members.size());
 		if(members != null && !members.isEmpty()) {
-			for(MemberView member:members) {
+			for(MemberRow member:members) {
 				keys.add(member.getIdentityKey());
 			}
 		}
@@ -746,101 +743,36 @@ public abstract class AbstractMemberListController extends FormBasicController i
 		updateTableModel(getSearchParams());
 	}
 
-	protected List<MemberView> updateTableModel(SearchMembersParams params) {
-		//course membership
-		boolean managedMembersRepo = 
-				RepositoryEntryManagedFlag.isManaged(repoEntry, RepositoryEntryManagedFlag.membersmanagement);
-		
-		List<RepositoryEntryMembership> repoMemberships =
-				repoEntry == null ? Collections.<RepositoryEntryMembership>emptyList()
-				: repositoryManager.getRepositoryEntryMembership(repoEntry);
-
-		//groups membership
-		List<BusinessGroup> groups = 
-				repoEntry == null ? Collections.singletonList(businessGroup)
-				: businessGroupService.findBusinessGroups(null, repoEntry, 0, -1);
-				
-		List<Long> groupKeys = new ArrayList<Long>();
-		Map<Long,BusinessGroupShort> keyToGroupMap = new HashMap<>();
-		for(BusinessGroup group:groups) {
-			groupKeys.add(group.getKey());
-			keyToGroupMap.put(group.getKey(), group);
-		}
-
-		List<BusinessGroupMembership> memberships = groups.isEmpty() ? Collections.<BusinessGroupMembership>emptyList() :
-			businessGroupService.getBusinessGroupsMembership(groups);
-
-		//get identities
-		Set<Long> identityKeys = new HashSet<>();
-		for(RepositoryEntryMembership membership: repoMemberships) {
-			identityKeys.add(membership.getIdentityKey());
-		}
-		for(BusinessGroupMembership membership:memberships) {
-			identityKeys.add(membership.getIdentityKey());
-		}
-		
-		List<Identity> identities;
-		if(identityKeys.isEmpty()) {
-			identities = new ArrayList<>(0);
-		} else  {
-			identities = filterIdentities(params, identityKeys);
+	protected List<MemberRow> updateTableModel(SearchMembersParams params) {
+		List<MemberView> memberViews;
+		if(repoEntry != null) {
+			memberViews = memberQueries.getRepositoryEntryMembers(repoEntry, params, userPropertyHandlers, getLocale());
+		} else if(businessGroup != null) {
+			memberViews = memberQueries.getBusinessGroupMembers(businessGroup, params, userPropertyHandlers, getLocale());
+		} else {
+			memberViews = Collections.emptyList();
 		}
 
-		Map<Long,MemberView> keyToMemberMap = new HashMap<>();
-		List<MemberView> memberList = new ArrayList<>();
-		Locale locale = getLocale();
-
-		//reservations
-		if(params.isPending()) {
-			List<OLATResource> resourcesForReservations = new ArrayList<>();
-			if(repoEntry != null) {
-				resourcesForReservations.add(repoEntry.getOlatResource());
-			}
-			for(BusinessGroup group:groups) {
-				resourcesForReservations.add(group.getResource());
-			}
-			List<ResourceReservation> reservations = acService.getReservations(resourcesForReservations);
-			List<Long> pendingIdentityKeys = new ArrayList<>(reservations.size());
-			for(ResourceReservation reservation:reservations) {
-				pendingIdentityKeys.add(reservation.getIdentity().getKey());
-			}
-			
-			if(StringHelper.containsNonWhitespace(params.getSearchString())
-					|| StringHelper.containsNonWhitespace(params.getLogin())
-					|| (params.getUserPropertiesSearch() != null && !params.getUserPropertiesSearch().isEmpty())) {
-				
-				List<Identity> pendingIdentities = filterIdentities(params, pendingIdentityKeys);
-				pendingIdentityKeys.retainAll(PersistenceHelper.toKeys(pendingIdentities));
-			}
-			
-			for(ResourceReservation reservation:reservations) {
-				Identity identity = reservation.getIdentity();
-				if(pendingIdentityKeys.contains(identity.getKey())) {
-					MemberView member = new MemberView(identity, userPropertyHandlers, locale);
-					member.getMembership().setPending(true);
-					memberList.add(member);
-					forgeLinks(member);
-					keyToMemberMap.put(identity.getKey(), member);
-				}
-			}
-		}
+		Map<Long,MemberRow> keyToMemberMap = new HashMap<>();
+		List<MemberRow> memberList = new ArrayList<>();
 		
 		Long me = getIdentity().getKey();
 		Set<Long> loadStatus = new HashSet<>();
-		for(Identity identity:identities) {
-			MemberView member = new MemberView(identity, userPropertyHandlers, locale);
+		for(MemberView memberView:memberViews) {
+			Long identityKey = memberView.getIdentityKey();
+			MemberRow member = new MemberRow(memberView);
 			if(chatEnabled) {
-				if(identity.getKey().equals(me)) {
+				if(identityKey.equals(me)) {
 					member.setOnlineStatus("me");
-				} else if(sessionManager.isOnline(identity.getKey())) {
-					loadStatus.add(identity.getKey());
+				} else if(sessionManager.isOnline(identityKey)) {
+					loadStatus.add(identityKey);
 				} else {
 					member.setOnlineStatus(Presence.unavailable.name());
 				}
 			}
 			memberList.add(member);
 			forgeLinks(member);
-			keyToMemberMap.put(identity.getKey(), member);
+			keyToMemberMap.put(identityKey, member);
 		}
 		
 		if(loadStatus.size() > 0) {
@@ -848,7 +780,7 @@ public abstract class AbstractMemberListController extends FormBasicController i
 			Map<Long,String> statusMap = imService.getBuddyStatus(statusToLoadList);
 			for(Long toLoad:statusToLoadList) {
 				String status = statusMap.get(toLoad);
-				MemberView member = keyToMemberMap.get(toLoad);
+				MemberRow member = keyToMemberMap.get(toLoad);
 				if(status == null) {
 					member.setOnlineStatus(Presence.available.name());	
 				} else {
@@ -856,105 +788,26 @@ public abstract class AbstractMemberListController extends FormBasicController i
 				}
 			}
 		}
-
-		for(BusinessGroupMembership membership:memberships) {
-			Long identityKey = membership.getIdentityKey();
-			MemberView memberView = keyToMemberMap.get(identityKey);
-			if(memberView != null) {
-				memberView.setFirstTime(membership.getCreationDate());
-				memberView.setLastTime(membership.getLastModified());
-				if(membership.isOwner()) {
-					memberView.getMembership().setGroupTutor(true);
-				}
-				if(membership.isParticipant()) {
-					memberView.getMembership().setGroupParticipant(true);
-				}
-				if(membership.isWaiting()) {
-					memberView.getMembership().setGroupWaiting(true);
-				}
-				
-				Long groupKey = membership.getGroupKey();
-				BusinessGroupShort group = keyToGroupMap.get(groupKey);
-				memberView.addGroup(group);
-			}
-		}
 		
-		for(RepositoryEntryMembership membership:repoMemberships) {
-			Long identityKey = membership.getIdentityKey();
-			MemberView memberView = keyToMemberMap.get(identityKey);
-			if(memberView != null) {
-				memberView.setFirstTime(membership.getCreationDate());
-				memberView.setLastTime(membership.getLastModified());
-				memberView.getMembership().setManagedMembersRepo(managedMembersRepo);
-				if(membership.isOwner()) {
-					memberView.getMembership().setRepoOwner(true);
-				}
-				if(membership.isCoach()) {
-					memberView.getMembership().setRepoTutor(true);
-				}
-				if(membership.isParticipant()) {
-					memberView.getMembership().setRepoParticipant(true);
-				}
-			}
-		}
-		
-		if(repoEntry != null) {
+		if(repoEntry != null && isLastVisitVisible) {
 			Map<Long,Date> lastLaunchDates = userInfosMgr.getRecentLaunchDates(repoEntry.getOlatResource());
-			for(MemberView memberView:keyToMemberMap.values()) {
-				Long identityKey = memberView.getIdentityKey();
+			for(MemberRow memberView:keyToMemberMap.values()) {
+				Long identityKey = memberView.getView().getIdentityKey();
 				Date date = lastLaunchDates.get(identityKey);
 				memberView.setLastTime(date);
 			}
 		}
 		
 		//the order of the filter is important
-		filterByRoles(memberList, params);
-		filterByOrigin(memberList, params);
+		//filterByRoles(memberList, params);
+		//filterByOrigin(memberList, params);
 		
 		memberListModel.setObjects(memberList);
 		membersTable.reset(true, true, true);
 		return memberList;
 	}
 	
-	private List<Identity> filterIdentities(SearchMembersParams params, Collection<Long> identityKeys) {
-		SearchIdentityParams idParams = new SearchIdentityParams();
-		if(StringHelper.containsNonWhitespace(params.getSearchString())) {
-			String searchString = params.getSearchString();
-			
-			Map<String,String> propertiesSearch = new HashMap<>();
-			for(UserPropertyHandler handler:userPropertyHandlers) {
-				propertiesSearch.put(handler.getName(), searchString);
-			}
-			idParams.setLogin(searchString);
-			idParams.setUserProperties(propertiesSearch);
-		} else {
-			if(params.getUserPropertiesSearch() != null && !params.getUserPropertiesSearch().isEmpty()) {
-				idParams.setUserProperties(params.getUserPropertiesSearch());
-			}
-			if(StringHelper.containsNonWhitespace(params.getLogin())) {
-				idParams.setLogin(params.getLogin());
-			}
-		}
-		
-		List<Long> identityKeyList = new ArrayList<>(identityKeys);
-		List<Identity> identities = new ArrayList<>(identityKeyList.size());
-
-		int count = 0;
-		int batch = 500;
-		do {
-			int toIndex = Math.min(count + batch, identityKeyList.size());
-			List<Long> toLoad = identityKeyList.subList(count, toIndex);
-			idParams.setIdentityKeys(toLoad);
-
-			List<Identity> batchOfIdentities = securityManager.getIdentitiesByPowerSearch(idParams, 0, -1);
-			identities.addAll(batchOfIdentities);
-			count += batch;
-		} while(count < identityKeyList.size());
-		
-		return identities;
-	}
-	
-	protected void forgeLinks(MemberView row) {
+	protected void forgeLinks(MemberRow row) {
 		FormLink toolsLink = uifactory.addFormLink("tools_" + counter.incrementAndGet(), "tools", "", null, null, Link.NONTRANSLATED);
 		toolsLink.setIconLeftCSS("o_icon o_icon_actions o_icon-lg");
 		toolsLink.setUserObject(row);
@@ -966,95 +819,6 @@ public abstract class AbstractMemberListController extends FormBasicController i
 		row.setChatLink(chatLink);
 	}
 	
-	private void filterByOrigin(List<MemberView> memberList, SearchMembersParams params) {
-		if(params.isGroupOrigin() && params.isRepoOrigin()) {
-			//do nothing not very useful :-)
-		} else if(params.isGroupOrigin()) {
-			for(Iterator<MemberView> it=memberList.iterator(); it.hasNext(); ) {
-				CourseMembership m = it.next().getMembership();
-				if(!m.isGroupTutor() && !m.isGroupParticipant() && !m.isGroupWaiting()) {
-					it.remove();
-				}
-			}
-		} else if(params.isRepoOrigin()) {
-			for(Iterator<MemberView> it=memberList.iterator(); it.hasNext(); ) {
-				CourseMembership m = it.next().getMembership();
-				if(!m.isRepoOwner() && !m.isRepoTutor() && !m.isRepoParticipant()) {
-					it.remove();
-				}
-			}
-		}
-	}
-	
-	/**
-	 * This filter method preserve the multiple roles of a member. If we want only the waiting list but
-	 * a member is in the waiting list and owner of the course, we want it to know.
-	 * @param memberList
-	 * @param params
-	 * @return
-	 */
-	private void filterByRoles(List<MemberView> memberList, SearchMembersParams params) {
-		List<MemberView> members = new ArrayList<MemberView>(memberList);
-
-		if(params.isRepoOwners()) {
-			for(Iterator<MemberView> it=members.iterator(); it.hasNext(); ) {
-				if(it.next().getMembership().isRepoOwner()) {
-					it.remove();
-				}
-			}
-		}
-		
-		if(params.isRepoTutors()) {
-			for(Iterator<MemberView> it=members.iterator(); it.hasNext(); ) {
-				if(it.next().getMembership().isRepoTutor()) {
-					it.remove();
-				}
-			}
-		}
-		
-		if(params.isRepoParticipants()) {
-			for(Iterator<MemberView> it=members.iterator(); it.hasNext(); ) {
-				if(it.next().getMembership().isRepoParticipant()) {
-					it.remove();
-				}
-			}
-		}
-		
-		if(params.isGroupTutors()) {
-			for(Iterator<MemberView> it=members.iterator(); it.hasNext(); ) {
-				if(it.next().getMembership().isGroupTutor()) {
-					it.remove();
-				}
-			}
-		}
-		
-		if(params.isGroupParticipants()) {
-			for(Iterator<MemberView> it=members.iterator(); it.hasNext(); ) {
-				if(it.next().getMembership().isGroupParticipant()) {
-					it.remove();
-				}
-			}
-		}
-		
-		if(params.isGroupWaitingList()) {
-			for(Iterator<MemberView> it=members.iterator(); it.hasNext(); ) {
-				if(it.next().getMembership().isGroupWaiting()) {
-					it.remove();
-				}
-			}
-		}
-		
-		if(params.isPending()) {
-			for(Iterator<MemberView> it=members.iterator(); it.hasNext(); ) {
-				if(it.next().getMembership().isPending()) {
-					it.remove();
-				}
-			}
-		}
-		
-		memberList.removeAll(members);
-	}
-	
 	private class MailConfirmation {
 		private final List<Identity> members;
 		private final MemberPermissionChangeEvent e;
@@ -1075,11 +839,11 @@ public abstract class AbstractMemberListController extends FormBasicController i
 	
 	private class ToolsController extends BasicController {
 		
-		private final MemberView row;
+		private final MemberRow row;
 		
 		private final VelocityContainer mainVC;
 		
-		public ToolsController(UserRequest ureq, WindowControl wControl, MemberView row) {
+		public ToolsController(UserRequest ureq, WindowControl wControl, MemberRow row) {
 			super(ureq, wControl);
 			this.row = row;
 			
@@ -1095,15 +859,16 @@ public abstract class AbstractMemberListController extends FormBasicController i
 			
 			links.add("-");
 			
-			if(row.getMembership().isGroupWaiting() && !readOnly) {
+			if(row.getMembership().isBusinessGroupWaiting() && !readOnly) {
 				addLink("table.header.graduate", TABLE_ACTION_GRADUATE, "o_icon o_icon_graduate", links);
 			}
 
-			if(!readOnly) {
+			if(!readOnly && (row.getMembership().isRepositoryEntryMember() || row.getMembership().isBusinessGroupMember())) {
 				addLink("edit.member", TABLE_ACTION_EDIT, "o_icon o_icon_edit", links);
 			}
 			
-			if(!globallyManaged || overrideManaged) {
+			if((!globallyManaged || overrideManaged)
+					&& (row.getMembership().isRepositoryEntryMember() || row.getMembership().isBusinessGroupMember())) {
 				addLink("table.header.remove", TABLE_ACTION_REMOVE, "o_icon o_icon_remove", links);
 			}
 
diff --git a/src/main/java/org/olat/group/ui/main/CourseMembership.java b/src/main/java/org/olat/group/ui/main/CourseMembership.java
index 926e0ed192e84b102f63709a574ed65b9d65d79f..3ea445b99fec02e4ab9b44a0dd33e9cfd18ce976 100644
--- a/src/main/java/org/olat/group/ui/main/CourseMembership.java
+++ b/src/main/java/org/olat/group/ui/main/CourseMembership.java
@@ -19,18 +19,26 @@
  */
 package org.olat.group.ui.main;
 
+import org.olat.basesecurity.GroupRoles;
+
 /**
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
 public class CourseMembership {
 	
-	private boolean repoOwner;
-	private boolean repoTutor;
-	private boolean repoParticipant;
-	private boolean groupTutor;
-	private boolean groupParticipant;
-	private boolean groupWaiting;
+	private boolean repositoryEntryOwner;
+	private boolean repositoryEntryCoach;
+	private boolean repositoryEntryParticipant;
+	
+	private boolean businessGroupCoach;
+	private boolean businessGroupParticipant;
+	private boolean businessGroupWaiting;
+	
+	private boolean curriculumElementCoach;
+	private boolean curriculumElementParticipant;
+	private boolean curriculumElementOwner;
+	
 	private boolean pending;
 	private boolean managedMembersRepo;
 	
@@ -39,19 +47,27 @@ public class CourseMembership {
 	}
 
 	public boolean isOwner() {
-		return repoOwner;
+		return repositoryEntryOwner || curriculumElementOwner;
 	}
 	
-	public boolean isTutor() {
-		return repoTutor || groupTutor;
+	public boolean isCoach() {
+		return repositoryEntryCoach || businessGroupCoach || curriculumElementCoach;
 	}
 	
 	public boolean isParticipant() {
-		return repoParticipant || groupParticipant;
+		return repositoryEntryParticipant || businessGroupParticipant || curriculumElementParticipant;
+	}
+	
+	public boolean isRepositoryEntryMember() {
+		return repositoryEntryOwner || repositoryEntryCoach || repositoryEntryParticipant;
+	}
+	
+	public boolean isBusinessGroupMember() {
+		return businessGroupCoach || businessGroupParticipant || businessGroupWaiting;
 	}
 
 	public boolean isWaiting() {
-		return groupWaiting;
+		return businessGroupWaiting;
 	}
 
 	public boolean isPending() {
@@ -70,51 +86,106 @@ public class CourseMembership {
 		this.managedMembersRepo = managedMembersRepo;
 	}
 
-	public boolean isRepoOwner() {
-		return repoOwner;
+	public boolean isRepositoryEntryOwner() {
+		return repositoryEntryOwner;
+	}
+
+	public void setRepositoryEntryOwner(boolean repositoryEntryOwner) {
+		this.repositoryEntryOwner = repositoryEntryOwner;
+	}
+
+	public boolean isRepositoryEntryCoach() {
+		return repositoryEntryCoach;
+	}
+
+	public void setRepositoryEntryCoach(boolean repositoryEntryCoach) {
+		this.repositoryEntryCoach = repositoryEntryCoach;
+	}
+
+	public boolean isRepositoryEntryParticipant() {
+		return repositoryEntryParticipant;
+	}
+
+	public void setRepositoryEntryParticipant(boolean repositoryEntryParticipant) {
+		this.repositoryEntryParticipant = repositoryEntryParticipant;
 	}
 	
-	public void setRepoOwner(boolean repoOwner) {
-		this.repoOwner = repoOwner;
+	public void setRepositoryEntryRole(String role) {
+		if(GroupRoles.participant.name().equals(role)) {
+			setRepositoryEntryParticipant(true);
+		} else if(GroupRoles.coach.name().equals(role)) {
+			setRepositoryEntryCoach(true);
+		} else if(GroupRoles.owner.name().equals(role)) {
+			setRepositoryEntryOwner(true);
+		}
 	}
 
-	public boolean isRepoTutor() {
-		return repoTutor;
+	public boolean isBusinessGroupCoach() {
+		return businessGroupCoach;
 	}
 
-	public void setRepoTutor(boolean repoTutor) {
-		this.repoTutor = repoTutor;
+	public void setBusinessGroupCoach(boolean businessGroupCoach) {
+		this.businessGroupCoach = businessGroupCoach;
 	}
 
-	public boolean isRepoParticipant() {
-		return repoParticipant;
+	public boolean isBusinessGroupParticipant() {
+		return businessGroupParticipant;
 	}
 
-	public void setRepoParticipant(boolean repoParticipant) {
-		this.repoParticipant = repoParticipant;
+	public void setBusinessGroupParticipant(boolean businessGroupParticipant) {
+		this.businessGroupParticipant = businessGroupParticipant;
 	}
 
-	public boolean isGroupTutor() {
-		return groupTutor;
+	public boolean isBusinessGroupWaiting() {
+		return businessGroupWaiting;
 	}
 
-	public void setGroupTutor(boolean groupTutor) {
-		this.groupTutor = groupTutor;
+	public void setBusinessGroupWaiting(boolean businessGroupWaiting) {
+		this.businessGroupWaiting = businessGroupWaiting;
+	}
+	
+	public void setBusinessGroupRole(String role) {
+		if(GroupRoles.participant.name().equals(role)) {
+			setBusinessGroupParticipant(true);
+		} else if(GroupRoles.coach.name().equals(role)) {
+			setBusinessGroupCoach(true);
+		} else if(GroupRoles.waiting.name().equals(role)) {
+			setBusinessGroupWaiting(true);
+		}
 	}
 
-	public boolean isGroupParticipant() {
-		return groupParticipant;
+	public boolean isCurriculumElementOwner() {
+		return curriculumElementOwner;
 	}
 
-	public void setGroupParticipant(boolean groupParticipant) {
-		this.groupParticipant = groupParticipant;
+	public void setCurriculumElementOwner(boolean curriculumElementOwner) {
+		this.curriculumElementOwner = curriculumElementOwner;
 	}
 
-	public boolean isGroupWaiting() {
-		return groupWaiting;
+	public boolean isCurriculumElementCoach() {
+		return curriculumElementCoach;
 	}
 
-	public void setGroupWaiting(boolean groupWaiting) {
-		this.groupWaiting = groupWaiting;
+	public void setCurriculumElementCoach(boolean curriculumElementCoach) {
+		this.curriculumElementCoach = curriculumElementCoach;
 	}
+
+	public boolean isCurriculumElementParticipant() {
+		return curriculumElementParticipant;
+	}
+
+	public void setCurriculumElementParticipant(boolean curriculumElementParticipant) {
+		this.curriculumElementParticipant = curriculumElementParticipant;
+	}
+	
+	public void setCurriculumElementRole(String role) {
+		if(GroupRoles.participant.name().equals(role)) {
+			setCurriculumElementParticipant(true);
+		} else if(GroupRoles.coach.name().equals(role)) {
+			setCurriculumElementCoach(true);
+		} else if(GroupRoles.owner.name().equals(role)) {
+			setCurriculumElementOwner(true);
+		}
+	}
+
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/main/CourseMembershipComparator.java b/src/main/java/org/olat/group/ui/main/CourseMembershipComparator.java
index 24023401057cd08f24c5c1fef005ebd26e7b7f06..514c5e2d9bcefba76a690f58202cf18cef2fe323 100644
--- a/src/main/java/org/olat/group/ui/main/CourseMembershipComparator.java
+++ b/src/main/java/org/olat/group/ui/main/CourseMembershipComparator.java
@@ -32,57 +32,66 @@ public class CourseMembershipComparator implements Comparator<CourseMembership>
 
 	@Override
 	public int compare(CourseMembership m1, CourseMembership m2) {
-		if(m1.isRepoOwner()) {
-			if(m2.isRepoOwner()) {
+		if(m1.isRepositoryEntryOwner()) {
+			if(m2.isRepositoryEntryOwner()) {
 				return 0;
 			}
 			return 1;
-		} else if(m2.isRepoOwner()) {
+		} else if(m2.isRepositoryEntryOwner()) {
 			return -1;
 		}
 		
-		if(m1.isGroupTutor()) {
-			if(m2.isGroupTutor()) {
+		if(m1.isCurriculumElementOwner()) {
+			if(m2.isCurriculumElementOwner()) {
 				return 0;
 			}
 			return 1;
-		} else if(m2.isGroupTutor()) {
+		} else if(m2.isCurriculumElementOwner()) {
 			return -1;
 		}
 		
-		if(m1.isRepoTutor()) {
-			if(m2.isRepoTutor()) {
+		if(m1.isBusinessGroupCoach()) {
+			if(m2.isBusinessGroupCoach()) {
 				return 0;
 			}
 			return 1;
-		} else if(m2.isRepoTutor()) {
+		} else if(m2.isBusinessGroupCoach()) {
 			return -1;
 		}
 		
-		if(m1.isGroupWaiting()) {
-			if(m2.isGroupWaiting()) {
+		if(m1.isRepositoryEntryCoach()) {
+			if(m2.isRepositoryEntryCoach()) {
 				return 0;
 			}
 			return 1;
-		} else if(m2.isGroupWaiting()) {
+		} else if(m2.isRepositoryEntryCoach()) {
 			return -1;
 		}
 		
-		if(m1.isGroupParticipant()) {
-			if(m2.isGroupParticipant()) {
+		if(m1.isBusinessGroupWaiting()) {
+			if(m2.isBusinessGroupWaiting()) {
 				return 0;
 			}
 			return 1;
-		} else if(m2.isGroupParticipant()) {
+		} else if(m2.isBusinessGroupWaiting()) {
 			return -1;
 		}
 		
-		if(m1.isRepoParticipant()) {
-			if(m2.isRepoParticipant()) {
+		if(m1.isBusinessGroupParticipant()) {
+			if(m2.isBusinessGroupParticipant()) {
 				return 0;
 			}
 			return 1;
-		} else if(m2.isRepoParticipant()) {
+		} else if(m2.isBusinessGroupParticipant()) {
+			return -1;
+		}
+		
+		if(m1.isRepositoryEntryParticipant()) {
+			if(m2.isRepositoryEntryParticipant()) {
+				return 0;
+			}
+			return 1;
+		} else if(m2.isRepositoryEntryParticipant()) {
 			return -1;
 		}
 		return 0;
diff --git a/src/main/java/org/olat/group/ui/main/CourseRoleCellRenderer.java b/src/main/java/org/olat/group/ui/main/CourseRoleCellRenderer.java
index b5ac5f0b0a756c9470c2badf941f413c04337b3f..75a828cbb6f59adba55a797268228db774a0e55a 100644
--- a/src/main/java/org/olat/group/ui/main/CourseRoleCellRenderer.java
+++ b/src/main/java/org/olat/group/ui/main/CourseRoleCellRenderer.java
@@ -23,7 +23,6 @@ import java.util.Locale;
 
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent;
-import org.olat.core.gui.components.table.CustomCellRenderer;
 import org.olat.core.gui.render.Renderer;
 import org.olat.core.gui.render.StringOutput;
 import org.olat.core.gui.render.URLBuilder;
@@ -34,7 +33,7 @@ import org.olat.core.util.Util;
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class CourseRoleCellRenderer implements CustomCellRenderer, FlexiCellRenderer {
+public class CourseRoleCellRenderer implements FlexiCellRenderer {
 	
 	private final Translator translator;
 	
@@ -49,13 +48,6 @@ public class CourseRoleCellRenderer implements CustomCellRenderer, FlexiCellRend
 			render(target, (CourseMembership) cellValue);
 		}
 	}
-
-	@Override
-	public void render(StringOutput sb, Renderer renderer, Object val, Locale locale, int alignment, String action) {
-		if (val instanceof CourseMembership) {
-			render(sb, (CourseMembership) val);
-		}
-	}
 	
 	private void render(StringOutput sb, CourseMembership membership) {
 		boolean and = false;
@@ -63,22 +55,35 @@ public class CourseRoleCellRenderer implements CustomCellRenderer, FlexiCellRend
 			and = and(sb, and);
 			sb.append(translator.translate("role.repo.owner"));
 		}
-		if(membership.isRepoTutor()) {
+		if(membership.isRepositoryEntryCoach()) {
 			and = and(sb, and);
 			sb.append(translator.translate("role.repo.tutor"));
 		}
-		if(membership.isGroupTutor()) {
+		if(membership.isBusinessGroupCoach()) {
 			and = and(sb, and);
 			sb.append(translator.translate("role.group.tutor"));
 		}
-		if(membership.isRepoParticipant()) {
+		if(membership.isRepositoryEntryParticipant()) {
 			and = and(sb, and);
 			sb.append(translator.translate("role.repo.participant"));
 		}
-		if(membership.isGroupParticipant()) {
+		if(membership.isBusinessGroupParticipant()) {
 			and = and(sb, and);
 			sb.append(translator.translate("role.group.participant"));
 		}
+		if(membership.isCurriculumElementParticipant()) {
+			and = and(sb, and);
+			sb.append(translator.translate("role.curriculum.participant"));
+		}
+		if(membership.isCurriculumElementCoach()) {
+			and = and(sb, and);
+			sb.append(translator.translate("role.curriculum.coach"));
+		}
+		if(membership.isCurriculumElementOwner()) {
+			and = and(sb, and);
+			sb.append(translator.translate("role.curriculum.owner"));
+		}
+		
 		if(membership.isWaiting()) {
 			and = and(sb, and);
 			sb.append(translator.translate("role.group.waiting"));
diff --git a/src/main/java/org/olat/group/ui/main/GraduateColumnDescriptor.java b/src/main/java/org/olat/group/ui/main/GraduateColumnDescriptor.java
index a920940af4e03700e286611e997f260618b055a9..e45ea0c3a3ce61a89d28e456f1389bbf83ebbab8 100644
--- a/src/main/java/org/olat/group/ui/main/GraduateColumnDescriptor.java
+++ b/src/main/java/org/olat/group/ui/main/GraduateColumnDescriptor.java
@@ -43,7 +43,7 @@ public class GraduateColumnDescriptor extends DefaultColumnDescriptor {
 		CourseMembership membership = (CourseMembership)table.getTableDataModel()
 				.getValueAt(sortedRow, MemberListTableModel.Cols.role.ordinal());
 		
-		if(membership.isGroupWaiting()) {
+		if(membership.isBusinessGroupWaiting()) {
 			return super.getAction(row);
 		}
 		return null;
@@ -56,7 +56,7 @@ public class GraduateColumnDescriptor extends DefaultColumnDescriptor {
 		CourseMembership membership = (CourseMembership)table.getTableDataModel()
 				.getValueAt(sortedRow, MemberListTableModel.Cols.role.ordinal());
 		
-		if(membership.isGroupWaiting()) {
+		if(membership.isBusinessGroupWaiting()) {
 			sb.append(translator.translate(getHeaderKey()));
 		}
 	}
diff --git a/src/main/java/org/olat/group/ui/main/GroupCellRenderer.java b/src/main/java/org/olat/group/ui/main/GroupCellRenderer.java
index ff004d30fd7385dc12d62be150b2a7b6606ff755..5088ea1ffb74c762dc4a5974bc9b7954d0b27c70 100644
--- a/src/main/java/org/olat/group/ui/main/GroupCellRenderer.java
+++ b/src/main/java/org/olat/group/ui/main/GroupCellRenderer.java
@@ -20,52 +20,56 @@
 package org.olat.group.ui.main;
 
 import java.util.List;
-import java.util.Locale;
 
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent;
-import org.olat.core.gui.components.table.CustomCellRenderer;
 import org.olat.core.gui.render.Renderer;
 import org.olat.core.gui.render.StringOutput;
 import org.olat.core.gui.render.URLBuilder;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.util.StringHelper;
 import org.olat.group.BusinessGroupShort;
+import org.olat.modules.curriculum.CurriculumElementShort;
 
 /**
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class GroupCellRenderer implements CustomCellRenderer, FlexiCellRenderer {
+public class GroupCellRenderer implements FlexiCellRenderer {
 
 	@Override
 	public void render(Renderer renderer, StringOutput target, Object cellValue, int row,
 			FlexiTableComponent source, URLBuilder ubu, Translator translator) {
-		if (cellValue instanceof MemberView) {
-			render(target, (MemberView) cellValue);
-		}
-	}
-
-	@Override
-	public void render(StringOutput sb, Renderer renderer, Object val, Locale locale, int alignment, String action) {
-		if (val instanceof MemberView) {
-			render(sb, (MemberView) val);
+		if (cellValue instanceof MemberRow) {
+			render(target, (MemberRow) cellValue);
 		}
 	}
 	
-	private void render(StringOutput sb, MemberView member) {
+	private void render(StringOutput sb, MemberRow member) {
+		boolean and = false;
 		List<BusinessGroupShort> groups = member.getGroups();
 		if(groups != null && !groups.isEmpty()) {
-			boolean and = false;
 			for(BusinessGroupShort group:groups) {
 				and = and(sb, and);
-				if(group.getName() == null) {
+				if(group.getName() == null && group.getKey() != null) {
 					sb.append(group.getKey());
 				} else {
 					sb.append(StringHelper.escapeHtml(group.getName()));
 				}
 			}
 		}
+
+		List<CurriculumElementShort> curriculumElements = member.getCurriculumElements();
+		if(curriculumElements != null && !curriculumElements.isEmpty()) {
+			for(CurriculumElementShort curriculumElement:curriculumElements) {
+				and = and(sb, and);
+				if(curriculumElement.getDisplayName() == null && curriculumElement.getKey() != null) {
+					sb.append(curriculumElement.getKey());
+				} else {
+					sb.append(StringHelper.escapeHtml(curriculumElement.getDisplayName()));
+				}
+			}
+		}
 	}
 	
 	private final boolean and(StringOutput sb, boolean and) {
diff --git a/src/main/java/org/olat/group/ui/main/GroupMemberViewComparator.java b/src/main/java/org/olat/group/ui/main/GroupMemberViewComparator.java
index c81cdbbe0d409e63a4d37587ab9745b42c5e50fd..08e11ed8a5d57d2ca32863aa4b5002063bf6d7b0 100644
--- a/src/main/java/org/olat/group/ui/main/GroupMemberViewComparator.java
+++ b/src/main/java/org/olat/group/ui/main/GroupMemberViewComparator.java
@@ -32,7 +32,7 @@ import org.olat.group.BusinessGroupShort;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class GroupMemberViewComparator implements Comparator<MemberView> {
+public class GroupMemberViewComparator implements Comparator<MemberRow> {
 	
 	private Collator collator;
 	
@@ -41,7 +41,7 @@ public class GroupMemberViewComparator implements Comparator<MemberView> {
 	}
 
 	@Override
-	public int compare(MemberView m1, MemberView m2) {
+	public int compare(MemberRow m1, MemberRow m2) {
 		List<BusinessGroupShort> g1 = m1.getGroups();
 		List<BusinessGroupShort> g2 = m2.getGroups();
 		
diff --git a/src/main/java/org/olat/group/ui/main/LeaveColumnDescriptor.java b/src/main/java/org/olat/group/ui/main/LeaveColumnDescriptor.java
index e3507315c635894d57e83ccde3f53fcd63fbebc1..b1ab318fd68c43b8171123f430ab18691d310bb9 100644
--- a/src/main/java/org/olat/group/ui/main/LeaveColumnDescriptor.java
+++ b/src/main/java/org/olat/group/ui/main/LeaveColumnDescriptor.java
@@ -44,7 +44,7 @@ public class LeaveColumnDescriptor extends DefaultColumnDescriptor {
 	@Override
 	public String getAction(int row) {
 		int sortedRow = table.getSortedRow(row);
-		MemberView membership = (MemberView)table.getTableDataModel()
+		MemberRow membership = (MemberRow)table.getTableDataModel()
 				.getValueAt(sortedRow, MemberListTableModel.Cols.groups.ordinal());
 		
 		return membership.isFullyManaged() ? null : super.getAction(row);
@@ -53,7 +53,7 @@ public class LeaveColumnDescriptor extends DefaultColumnDescriptor {
 	@Override
 	public void renderValue(StringOutput sb, int row, Renderer renderer) {
 		int sortedRow = table.getSortedRow(row);
-		MemberView membership = (MemberView)table.getTableDataModel()
+		MemberRow membership = (MemberRow)table.getTableDataModel()
 				.getValueAt(sortedRow, MemberListTableModel.Cols.groups.ordinal());
 		
 		if(!membership.isFullyManaged()) {
diff --git a/src/main/java/org/olat/group/ui/main/MemberListTableModel.java b/src/main/java/org/olat/group/ui/main/MemberListTableModel.java
index b2fa54cb7a319ef8a7a5b2f781027e2dddf8693e..08985a9bba39e2ff8950bde4aa72ed21805bdc1d 100644
--- a/src/main/java/org/olat/group/ui/main/MemberListTableModel.java
+++ b/src/main/java/org/olat/group/ui/main/MemberListTableModel.java
@@ -33,7 +33,7 @@ import org.olat.instantMessaging.model.Presence;
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class MemberListTableModel extends DefaultFlexiTableDataModel<MemberView> implements SortableFlexiTableDataModel<MemberView> {
+public class MemberListTableModel extends DefaultFlexiTableDataModel<MemberRow> implements SortableFlexiTableDataModel<MemberRow> {
 	
 	private final boolean onlineStatusEnabled;
 	
@@ -45,22 +45,22 @@ public class MemberListTableModel extends DefaultFlexiTableDataModel<MemberView>
 	@Override
 	public void sort(SortKey orderBy) {
 		if(orderBy != null) {
-			List<MemberView> views = new MemberListTableSort(orderBy, this, null).sort();
+			List<MemberRow> views = new MemberListTableSort(orderBy, this, null).sort();
 			super.setObjects(views);
 		}
 	}
 
 	@Override
 	public Object getValueAt(int row, int col) {
-		MemberView member = getObject(row);
+		MemberRow member = getObject(row);
 		return getValueAt(member, col);
 	}
 
 	@Override
-	public Object getValueAt(MemberView row, int col) {
+	public Object getValueAt(MemberRow row, int col) {
 		if(col >= 0 && col < Cols.values().length) {
 			switch(Cols.values()[col]) {
-				case username: return row.getIdentityName();
+				case username: return row.getView().getIdentityName();
 				case firstTime: return row.getFirstTime();
 				case lastTime: return row.getLastTime();
 				case role: return row.getMembership();
@@ -95,7 +95,7 @@ public class MemberListTableModel extends DefaultFlexiTableDataModel<MemberView>
 		}
 		
 		int propPos = col - AbstractMemberListController.USER_PROPS_OFFSET;
-		return row.getIdentityProp(propPos);
+		return row.getView().getIdentityProp(propPos);
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/group/ui/main/MemberListTableSort.java b/src/main/java/org/olat/group/ui/main/MemberListTableSort.java
index 808fd2104bd96a13bd2aa7ebb24c014ac8e232d3..eda39c5d450b7df83c728f7b8a96309787649193 100644
--- a/src/main/java/org/olat/group/ui/main/MemberListTableSort.java
+++ b/src/main/java/org/olat/group/ui/main/MemberListTableSort.java
@@ -35,14 +35,14 @@ import org.olat.group.ui.main.MemberListTableModel.Cols;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class MemberListTableSort extends SortableFlexiTableModelDelegate<MemberView> {
+public class MemberListTableSort extends SortableFlexiTableModelDelegate<MemberRow> {
 
-	public MemberListTableSort(SortKey orderBy, SortableFlexiTableDataModel<MemberView> tableModel, Locale locale) {
+	public MemberListTableSort(SortKey orderBy, SortableFlexiTableDataModel<MemberRow> tableModel, Locale locale) {
 		super(orderBy, tableModel, locale);
 	}
 
 	@Override
-	protected void sort(List<MemberView> rows) {
+	protected void sort(List<MemberRow> rows) {
 		int columnIndex = getColumnIndex();
 		if(columnIndex >= AbstractMemberListController.USER_PROPS_OFFSET) {
 			super.sort(rows);
@@ -62,12 +62,12 @@ public class MemberListTableSort extends SortableFlexiTableModelDelegate<MemberV
 		}
 	}
 
-	private static class RoleMemberViewComparator implements Comparator<MemberView> {
+	private static class RoleMemberViewComparator implements Comparator<MemberRow> {
 		
 		private final CourseMembershipComparator comparator = new CourseMembershipComparator();
 
 		@Override
-		public int compare(MemberView o1, MemberView o2) {
+		public int compare(MemberRow o1, MemberRow o2) {
 			return comparator.compare(o1.getMembership(), o2.getMembership());
 		}
 	}
diff --git a/src/main/java/org/olat/group/ui/main/MemberView.java b/src/main/java/org/olat/group/ui/main/MemberRow.java
similarity index 67%
rename from src/main/java/org/olat/group/ui/main/MemberView.java
rename to src/main/java/org/olat/group/ui/main/MemberRow.java
index e7fdf035b58d46af6f064dc9ad12dd919f51228b..2e3cb8969f00ba3cebf21baf9a1df8787fdec1b7 100644
--- a/src/main/java/org/olat/group/ui/main/MemberView.java
+++ b/src/main/java/org/olat/group/ui/main/MemberRow.java
@@ -19,33 +19,33 @@
  */
 package org.olat.group.ui.main;
 
-import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
-import java.util.Locale;
 
 import org.olat.core.gui.components.form.flexible.elements.FormLink;
-import org.olat.core.id.Identity;
 import org.olat.group.BusinessGroupManagedFlag;
 import org.olat.group.BusinessGroupShort;
-import org.olat.user.UserPropertiesRow;
-import org.olat.user.propertyhandlers.UserPropertyHandler;
+import org.olat.group.model.MemberView;
+import org.olat.modules.curriculum.CurriculumElementShort;
 
 /**
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class MemberView extends UserPropertiesRow {
+public class MemberRow {
 	
 	private Date firstTime;
 	private Date lastTime;
-	private final CourseMembership membership = new CourseMembership();
-	private List<BusinessGroupShort> groups;
+	
 	private String onlineStatus;
 	private FormLink toolsLink, chatLink;
 	
-	public MemberView(Identity identity, List<UserPropertyHandler> userPropertyHandlers, Locale locale) {
-		super(identity, userPropertyHandlers, locale);
+	private final MemberView view;
+	
+	public MemberRow(MemberView view) {
+		this.view = view;
+		firstTime = view.getCreationDate();
+		lastTime = view.getLastModified();
 	}
 
 	public FormLink getToolsLink() {
@@ -71,40 +71,43 @@ public class MemberView extends UserPropertiesRow {
 	public void setOnlineStatus(String onlineStatus) {
 		this.onlineStatus = onlineStatus;
 	}
+	
+	public MemberView getView() {
+		return view;
+	}
+	
+	public Long getIdentityKey() {
+		return view.getIdentityKey();
+	}
 
 	public CourseMembership getMembership() {
-		return membership;
+		return view.getMemberShip();
 	}
 
 	public List<BusinessGroupShort> getGroups() {
-		return groups;
+		return view.getGroups();
 	}
 
-	public void setGroups(List<BusinessGroupShort> groups) {
-		this.groups = groups;
-	}
 
-	public void addGroup(BusinessGroupShort group) {
-		if(group == null) return;
-		if(groups == null) {
-			groups = new ArrayList<BusinessGroupShort>(3);
-		}
-		groups.add(group);
+	public List<CurriculumElementShort> getCurriculumElements() {
+		return view.getCurriculumElements();
 	}
-	
+
 	public boolean isFullyManaged() {
+		CourseMembership membership = getMembership();
 		if(membership != null && !membership.isManagedMembersRepo() &&
-				(membership.isRepoOwner() || membership.isRepoTutor() || membership.isRepoParticipant())) {
+				(membership.isRepositoryEntryOwner() || membership.isRepositoryEntryCoach() || membership.isRepositoryEntryParticipant())) {
 			return false;
 		}
 
-		if(groups != null) {
-			for(BusinessGroupShort group:groups) {
+		if(view.getGroups() != null) {
+			for(BusinessGroupShort group:view.getGroups()) {
 				if(!BusinessGroupManagedFlag.isManaged(group.getManagedFlags(), BusinessGroupManagedFlag.membersmanagement)) {
 					return false;
 				}
 			}
 		}
+		
 		return true;
 	}
 	
@@ -132,7 +135,7 @@ public class MemberView extends UserPropertiesRow {
 
 	@Override
 	public int hashCode() {
-		return getIdentityKey() == null ? 2878 : getIdentityKey().hashCode();
+		return view.getIdentityKey() == null ? 2878 : view.getIdentityKey().hashCode();
 	}
 
 	@Override
@@ -140,9 +143,9 @@ public class MemberView extends UserPropertiesRow {
 		if(this == obj) {
 			return true;
 		}
-		if(obj instanceof MemberView) {
-			MemberView member = (MemberView)obj;
-			return getIdentityKey() != null && getIdentityKey().equals(member.getIdentityKey());
+		if(obj instanceof MemberRow) {
+			MemberRow member = (MemberRow)obj;
+			return view.getIdentityKey() != null && view.getIdentityKey().equals(member.getView().getIdentityKey());
 		}
 		return false;
 	}
@@ -150,8 +153,7 @@ public class MemberView extends UserPropertiesRow {
 	@Override
 	public String toString() {
 		StringBuilder sb = new StringBuilder();
-		sb.append("memberView[identityKey=").append(getIdentityKey() == null ? "" : getIdentityKey())
-			.append(":login=").append(getIdentityName()).append("]");
+		sb.append("memberView[identityKey=").append(view.getIdentityKey() == null ? "" : view.getIdentityKey()).append("]");
 		return sb.toString();
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/main/SearchMembersParams.java b/src/main/java/org/olat/group/ui/main/SearchMembersParams.java
index e6cbeb9fe05642dc286c1bcfd55f77ec94f311a0..67c53bd436403b54dcf535af56f1316c90561ba7 100644
--- a/src/main/java/org/olat/group/ui/main/SearchMembersParams.java
+++ b/src/main/java/org/olat/group/ui/main/SearchMembersParams.java
@@ -21,6 +21,7 @@ package org.olat.group.ui.main;
 
 import java.util.Map;
 
+import org.olat.basesecurity.GroupRoles;
 import org.olat.core.gui.control.Event;
 
 /**
@@ -30,84 +31,49 @@ import org.olat.core.gui.control.Event;
 public class SearchMembersParams extends Event {
 	private static final long serialVersionUID = -8842738563007496141L;
 	
-	private boolean repoOwners;
-	private boolean repoTutors;
-	private boolean repoParticipants;
-	private boolean groupTutors;
-	private boolean groupParticipants;
-	private boolean groupWaitingList;
+	private GroupRoles[] roles;
 	private boolean pending;
 	
-	private boolean repoOrigin = true;
-	private boolean groupOrigin = true;
+	private Origin origin;
 	
 	private String login;
-	private String searchString;
 	private Map<String, String> userPropertiesSearch;
 	
 	public SearchMembersParams() {
 		super("search_members");
 	}
 	
-	public SearchMembersParams(boolean repoOwners, boolean repoTutors, boolean repoParticipants,
-			boolean groupTutors, boolean groupParticipants, boolean groupWaitingList,
-			boolean pending) {
+	public SearchMembersParams(boolean pending, GroupRoles... roles) {
 		this();
-		this.repoOwners = repoOwners;
-		this.repoTutors = repoTutors;
-		this.repoParticipants = repoParticipants;
-		this.groupTutors = groupTutors;
-		this.groupParticipants = groupParticipants;
-		this.groupWaitingList = groupWaitingList;
 		this.pending = pending;
+		this.roles = roles;
 	}
 	
-	public boolean isRepoOwners() {
-		return repoOwners;
+	public GroupRoles[] getRoles() {
+		return roles;
 	}
 	
-	public void setRepoOwners(boolean repoOwners) {
-		this.repoOwners = repoOwners;
+	public void setRole(GroupRoles role) {
+		if(role == null) {
+			roles = null;
+		} else {
+			roles = new GroupRoles[] { role };
+		}
 	}
 	
-	public boolean isRepoTutors() {
-		return repoTutors;
+	public void setRoles(GroupRoles[] roles) {
+		this.roles = roles;
 	}
 	
-	public void setRepoTutors(boolean repoTutors) {
-		this.repoTutors = repoTutors;
-	}
-	
-	public boolean isRepoParticipants() {
-		return repoParticipants;
-	}
-	
-	public void setRepoParticipants(boolean repoParticipants) {
-		this.repoParticipants = repoParticipants;
-	}
-	
-	public boolean isGroupTutors() {
-		return groupTutors;
-	}
-	
-	public void setGroupTutors(boolean groupTutors) {
-		this.groupTutors = groupTutors;
-	}
-	
-	public boolean isGroupParticipants() {
-		return groupParticipants;
-	}
-	
-	public void setGroupParticipants(boolean groupParticipants) {
-		this.groupParticipants = groupParticipants;
-	}
-	
-	public boolean isGroupWaitingList() {
-		return groupWaitingList;
-	}
-	
-	public void setGroupWaitingList(boolean groupWaitingList) {
-		this.groupWaitingList = groupWaitingList;
+	public boolean isRole(GroupRoles role) {
+		if(roles != null) {
+			for(GroupRoles r:roles) {
+				if(r == role) {
+					return true;
+				}
+			}
+		}
+		return false;
 	}
 
 	public boolean isPending() {
@@ -118,20 +84,12 @@ public class SearchMembersParams extends Event {
 		this.pending = pending;
 	}
 
-	public boolean isRepoOrigin() {
-		return repoOrigin;
-	}
-
-	public void setRepoOrigin(boolean repoOrigin) {
-		this.repoOrigin = repoOrigin;
-	}
-
-	public boolean isGroupOrigin() {
-		return groupOrigin;
+	public Origin getOrigin() {
+		return origin == null ? Origin.all : origin;
 	}
 
-	public void setGroupOrigin(boolean groupOrigin) {
-		this.groupOrigin = groupOrigin;
+	public void setOrigin(Origin origin) {
+		this.origin = origin;
 	}
 
 	public String getLogin() {
@@ -142,14 +100,6 @@ public class SearchMembersParams extends Event {
 		this.login = login;
 	}
 
-	public String getSearchString() {
-		return searchString;
-	}
-
-	public void setSearchString(String searchString) {
-		this.searchString = searchString;
-	}
-
 	public Map<String, String> getUserPropertiesSearch() {
 		return userPropertiesSearch;
 	}
@@ -157,4 +107,11 @@ public class SearchMembersParams extends Event {
 	public void setUserPropertiesSearch(Map<String, String> userPropertiesSearch) {
 		this.userPropertiesSearch = userPropertiesSearch;
 	}
+	
+	public enum Origin {
+		all,
+		repositoryEntry,
+		businessGroup,
+		curriculum
+	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties
index 64ce196f7d2218eb0309bfc69893552d06f0da04..70b11c27d07ff94dcc5beae3d080f94c25607ba0 100644
--- a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties
@@ -156,7 +156,9 @@ edit.member.groups=Gruppenmitgliedschaften
 import.member=Mitglieder hinzuf\u00FCgen
 
 
-
+role.curriculum.participant=Curriculumteilnehmer
+role.curriculum.coach=Curriculumbetreuers
+role.curriculum.owner=Curriculumkursbesitzer
 role.group.tutor=Gruppenbetreuer
 role.group.participant=Gruppenteilnehmer
 role.group.waiting=Warteliste
diff --git a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_en.properties
index 26dd51cca070c0cd1f37d85290cfd2289a42364d..bd56d14521591305bb41c0bd8f3ebb8ac28fa126 100644
--- a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_en.properties
@@ -99,6 +99,9 @@ remove.send.mail.label=Send E-mail
 request.leaving.body=Dear group coach<br /><br />Please remove me from this group.<br /><br />Best regards<br />{3} {4}<br /><br />Group name\: {0}<br />Group ID\: {1}<br />Group used in course\: {2}
 request.leaving.subject=Request to leave group "{0}" (ID {1})
 reservation.coach=as coach
+role.curriculum.coach=Curriculum coach
+role.curriculum.owner=Curriculum course owner
+role.curricullum.participant=Curriculum member
 role.group.participant=Group member
 role.group.tutor=Group coach
 role.group.waiting=Waiting list
diff --git a/src/main/java/org/olat/modules/curriculum/CurriculumElementShort.java b/src/main/java/org/olat/modules/curriculum/CurriculumElementShort.java
new file mode 100644
index 0000000000000000000000000000000000000000..86c61b8167af1e4f81ce0ab6da94387ec04802d0
--- /dev/null
+++ b/src/main/java/org/olat/modules/curriculum/CurriculumElementShort.java
@@ -0,0 +1,34 @@
+/**
+ * <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.modules.curriculum;
+
+/**
+ * 
+ * Initial date: 6 juin 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public interface CurriculumElementShort extends CurriculumElementRef {
+	
+	public String getDisplayName();
+	
+	public CurriculumElementManagedFlag[] getManagedFlags();
+
+}
diff --git a/src/main/java/org/olat/modules/curriculum/CurriculumRoles.java b/src/main/java/org/olat/modules/curriculum/CurriculumRoles.java
index 6dca311f822bd75660d682e12f30b32521c58bda..f7ec99039f1669b7333fdcb93ecb7d786d569072 100644
--- a/src/main/java/org/olat/modules/curriculum/CurriculumRoles.java
+++ b/src/main/java/org/olat/modules/curriculum/CurriculumRoles.java
@@ -19,6 +19,8 @@
  */
 package org.olat.modules.curriculum;
 
+import org.olat.core.util.StringHelper;
+
 /**
  * 
  * Initial date: 9 mai 2018<br>
@@ -27,6 +29,19 @@ package org.olat.modules.curriculum;
  */
 public enum CurriculumRoles {
 	
-	supervisor,
-
+	curriculummanager,
+	owner, //same as GroupRoles
+	coach, //same as GroupRoles
+	participant; //same as GroupRoles
+	
+	public static final boolean isValueOf(String val) {
+		if(StringHelper.containsNonWhitespace(val)) {
+			for(CurriculumRoles role:values()) {
+				if(role.name().equals(val)) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
 }
diff --git a/src/main/java/org/olat/modules/curriculum/CurriculumService.java b/src/main/java/org/olat/modules/curriculum/CurriculumService.java
index 2ea8768b7db82ee251d86859d442cb6861c3b757..754229852495cb305f32aa5ea307705d83524bb7 100644
--- a/src/main/java/org/olat/modules/curriculum/CurriculumService.java
+++ b/src/main/java/org/olat/modules/curriculum/CurriculumService.java
@@ -153,6 +153,15 @@ public interface CurriculumService {
 	 */
 	public List<CurriculumElementMember> getMembers(CurriculumElement element);
 	
+	/**
+	 * The list of members of the specified curriculum element with the specified role.
+	 * 
+	 * @param element The curriculum element
+	 * @param role The role
+	 * @return The list of memberships
+	 */
+	public List<Identity> getMembersIdentity(CurriculumElementRef element, CurriculumRoles role);
+	
 	/**
 	 * Add a member with the specified role to the curriculum element. The
 	 * inheritance mode of the membership is per default "none".
@@ -171,6 +180,15 @@ public interface CurriculumService {
 	 */
 	public void removeMember(CurriculumElement element, IdentityRef member);
 	
+	/**
+	 * Remove the membership of a user with the specified role.
+	 * 
+	 * @param element The curriculum element
+	 * @param member The identity which loose the membership
+	 * @param role The role
+	 */
+	public void removeMember(CurriculumElement element, IdentityRef member, CurriculumRoles role);
+	
 	/**
 	 * The all list of repository entries hold by the specified curriculum element.
 	 * 
@@ -179,6 +197,16 @@ public interface CurriculumService {
 	 */
 	public List<RepositoryEntry> getRepositoryEntries(CurriculumElementRef element);
 	
+	/**
+	 * Check if the repository entry is already in relation with the specified
+	 * curriculum element.
+	 * 
+	 * @param element The curriculum element
+	 * @param entry The repository entry
+	 * @return True if the repository entry and curriculum element share a group
+	 */
+	public boolean hasRepositoryEntry(CurriculumElement element, RepositoryEntryRef entry);
+	
 	/**
 	 * This will add a relation between the curriculum element and the repository
 	 * entry and it will add the base group of the curriculum to the set of groups
@@ -191,6 +219,9 @@ public interface CurriculumService {
 	 */
 	public void addRepositoryEntry(CurriculumElement element, RepositoryEntryRef entry, boolean master);
 	
+
+	public void removeRepositoryEntry(CurriculumElement element, RepositoryEntryRef entry);
+	
 	
 	public List<CurriculumElementRepositoryEntryViews> getCurriculumElements(Identity identity, Roles roles, CurriculumRef curriculum);
 
diff --git a/src/main/java/org/olat/modules/curriculum/manager/CurriculumDAO.java b/src/main/java/org/olat/modules/curriculum/manager/CurriculumDAO.java
index b255ac824284e69d19a762b785a4ff677ee6023f..180ef74fbb38de99d0cb481758bf9e753b08807c 100644
--- a/src/main/java/org/olat/modules/curriculum/manager/CurriculumDAO.java
+++ b/src/main/java/org/olat/modules/curriculum/manager/CurriculumDAO.java
@@ -30,6 +30,7 @@ import org.olat.core.commons.persistence.DB;
 import org.olat.core.commons.persistence.PersistenceHelper;
 import org.olat.core.id.Organisation;
 import org.olat.core.id.OrganisationRef;
+import org.olat.core.util.StringHelper;
 import org.olat.modules.curriculum.Curriculum;
 import org.olat.modules.curriculum.model.CurriculumImpl;
 import org.olat.modules.curriculum.model.CurriculumSearchParameters;
@@ -88,6 +89,25 @@ public class CurriculumDAO {
 			where = PersistenceHelper.appendAnd(sb, where);
 			sb.append(" cur.organisation.key in (:organisationKeys)");
 		}
+		
+		Long key = null;
+		String ref = null;
+		String fuzzyRef = null;
+		if(StringHelper.containsNonWhitespace(params.getSearchString())) {
+			ref = params.getSearchString();
+			fuzzyRef = PersistenceHelper.makeFuzzyQueryString(ref);
+			
+			where = PersistenceHelper.appendAnd(sb, where);
+			sb.append(" (cur.externalId=:ref or ");
+			PersistenceHelper.appendFuzzyLike(sb, "cur.displayName", "fuzzyRef", dbInstance.getDbVendor());
+			sb.append(" or ");
+			PersistenceHelper.appendFuzzyLike(sb, "cur.identifier", "fuzzyRef", dbInstance.getDbVendor());
+			if(StringHelper.isLong(ref)) {
+				key = Long.valueOf(ref);
+				sb.append(" or cur.key=:curriculumKey");
+			}
+			sb.append(")");	
+		}
 
 		TypedQuery<Curriculum> query = dbInstance.getCurrentEntityManager()
 				.createQuery(sb.toString(), Curriculum.class);
@@ -96,6 +116,15 @@ public class CurriculumDAO {
 					.stream().map(OrganisationRef::getKey).collect(Collectors.toList());
 			query.setParameter("organisationKeys", organisationKeys);
 		}
+		if(key != null) {
+			query.setParameter("curriculumKey", key);
+		}
+		if(ref != null) {
+			query.setParameter("ref", ref);
+		}
+		if(fuzzyRef != null) {
+			query.setParameter("fuzzyRef", fuzzyRef);
+		}
 		return query.getResultList();
 	}
 	
diff --git a/src/main/java/org/olat/modules/curriculum/manager/CurriculumElementDAO.java b/src/main/java/org/olat/modules/curriculum/manager/CurriculumElementDAO.java
index 328ebc6fe7507e30cf247db885235602730dc7ae..1d57622bfa8adb85dec12c805a3f89161919adff 100644
--- a/src/main/java/org/olat/modules/curriculum/manager/CurriculumElementDAO.java
+++ b/src/main/java/org/olat/modules/curriculum/manager/CurriculumElementDAO.java
@@ -197,6 +197,7 @@ public class CurriculumElementDAO {
 		  .append(" inner join el.group baseGroup")
 		  .append(" inner join baseGroup.members membership")
 		  .append(" inner join membership.identity ident")
+		  .append(" inner join fetch ident.user identUser")
 		  .append(" where el.key=:elementKey");
 		List<Object[]> objects = dbInstance.getCurrentEntityManager()
 				.createQuery(sb.toString(), Object[].class)
@@ -216,6 +217,21 @@ public class CurriculumElementDAO {
 		return members;
 	}
 	
+	public List<Identity> getMembersIdentity(CurriculumElementRef element, String role) {
+		StringBuilder sb = new StringBuilder(256);
+		sb.append("select ident from curriculumelement el")
+		  .append(" inner join el.group baseGroup")
+		  .append(" inner join baseGroup.members membership")
+		  .append(" inner join membership.identity ident")
+		  .append(" inner join fetch ident.user identUser")
+		  .append(" where el.key=:elementKey and membership.role=:role");
+		return dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), Identity.class)
+				.setParameter("elementKey", element.getKey())
+				.setParameter("role", role)
+				.getResultList();
+	}
+	
 	private static class PathMaterializedPathLengthComparator implements Comparator<CurriculumElement> {
 		@Override
 		public int compare(CurriculumElement c1, CurriculumElement c2) {
diff --git a/src/main/java/org/olat/modules/curriculum/manager/CurriculumRepositoryEntryRelationDAO.java b/src/main/java/org/olat/modules/curriculum/manager/CurriculumRepositoryEntryRelationDAO.java
index bad5f5dc2da52c9325cc8e43b0a573d92678b87c..b69f64fb796ea0e9cf79acda667e1d1f0884c28f 100644
--- a/src/main/java/org/olat/modules/curriculum/manager/CurriculumRepositoryEntryRelationDAO.java
+++ b/src/main/java/org/olat/modules/curriculum/manager/CurriculumRepositoryEntryRelationDAO.java
@@ -59,6 +59,25 @@ public class CurriculumRepositoryEntryRelationDAO {
 		return relation;
 	}
 	
+	public List<CurriculumRepositoryEntryRelation> getRelations(RepositoryEntryRef entry, CurriculumElementRef element) {
+		StringBuilder sb = new StringBuilder(256);
+		sb.append("select rel from repoentrytocurriculumelement as rel")
+		  .append(" where rel.entry.key=:repoKey and rel.curriculumElement.key=:elementKey");
+
+		return dbInstance.getCurrentEntityManager()
+			.createQuery(sb.toString(), CurriculumRepositoryEntryRelation.class)
+			.setParameter("repoKey", entry.getKey())
+			.setParameter("elementKey", element.getKey())
+			.getResultList();
+	}
+	
+	public void deleteRelation(RepositoryEntryRef entry, CurriculumElementRef element) {
+		List<CurriculumRepositoryEntryRelation> relations = getRelations(entry, element);
+		for(CurriculumRepositoryEntryRelation relation:relations) {
+			dbInstance.getCurrentEntityManager().remove(relation);
+		}
+	}
+	
 	public List<CurriculumElement> getCurriculumElements(RepositoryEntryRef entry) {
 		StringBuilder sb = new StringBuilder(256);
 		sb.append("select el from curriculumelement as el")
diff --git a/src/main/java/org/olat/modules/curriculum/manager/CurriculumServiceImpl.java b/src/main/java/org/olat/modules/curriculum/manager/CurriculumServiceImpl.java
index 27a2854da3d7d227940ab3859b6f8d3b10c01972..7db12eb009bb52d1004975940fabb69cc1fdc67a 100644
--- a/src/main/java/org/olat/modules/curriculum/manager/CurriculumServiceImpl.java
+++ b/src/main/java/org/olat/modules/curriculum/manager/CurriculumServiceImpl.java
@@ -198,6 +198,11 @@ public class CurriculumServiceImpl implements CurriculumService {
 	public List<CurriculumElementMember> getMembers(CurriculumElement element) {
 		return curriculumElementDao.getMembers(element);
 	}
+	
+	@Override
+	public List<Identity> getMembersIdentity(CurriculumElementRef element, CurriculumRoles role) {
+		return curriculumElementDao.getMembersIdentity(element, role.name());
+	}
 
 	@Override
 	public void addMember(CurriculumElement element, Identity member, CurriculumRoles role) {
@@ -211,6 +216,11 @@ public class CurriculumServiceImpl implements CurriculumService {
 		groupDao.removeMembership(element.getGroup(), member);
 	}
 
+	@Override
+	public void removeMember(CurriculumElement element, IdentityRef member, CurriculumRoles role) {
+		groupDao.removeMembership(element.getGroup(), member, role.name());
+	}
+
 	@Override
 	public List<RepositoryEntry> getRepositoryEntries(CurriculumElementRef element) {
 		return curriculumRepositoryEntryRelationDao.getRepositoryEntries(element);
@@ -223,6 +233,17 @@ public class CurriculumServiceImpl implements CurriculumService {
 		curriculumRepositoryEntryRelationDao.createRelation(repoEntry, element, master);
 	}
 
+	@Override
+	public boolean hasRepositoryEntry(CurriculumElement element, RepositoryEntryRef entry) {
+		return repositoryEntryRelationDao.hasRelation(element.getGroup(), entry);
+	}
+
+	@Override
+	public void removeRepositoryEntry(CurriculumElement element, RepositoryEntryRef entry) {
+		repositoryEntryRelationDao.removeRelation(element.getGroup(), entry);
+		curriculumRepositoryEntryRelationDao.deleteRelation(entry, element);
+	}
+
 	@Override
 	public List<CurriculumElementRepositoryEntryViews> getCurriculumElements(Identity identity, Roles roles, CurriculumRef curriculum) {
 		if(curriculum == null) return Collections.emptyList();
diff --git a/src/main/java/org/olat/modules/curriculum/model/CurriculumSearchParameters.java b/src/main/java/org/olat/modules/curriculum/model/CurriculumSearchParameters.java
index 5f55323df0465b474cf8e313be40dad8a4a39ee1..4367f160272ee2d7c88c800acc26654dbe8f689b 100644
--- a/src/main/java/org/olat/modules/curriculum/model/CurriculumSearchParameters.java
+++ b/src/main/java/org/olat/modules/curriculum/model/CurriculumSearchParameters.java
@@ -32,6 +32,7 @@ import org.olat.core.id.OrganisationRef;
  */
 public class CurriculumSearchParameters {
 	
+	private String searchString;
 	private List<OrganisationRef> organisations;
 
 	public List<OrganisationRef> getOrganisations() {
@@ -44,7 +45,12 @@ public class CurriculumSearchParameters {
 	public void setOrganisations(List<OrganisationRef> organisations) {
 		this.organisations = organisations;
 	}
-	
-	
 
+	public String getSearchString() {
+		return searchString;
+	}
+
+	public void setSearchString(String searchString) {
+		this.searchString = searchString;
+	}
 }
diff --git a/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementMemberVO.java b/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementMemberVO.java
new file mode 100644
index 0000000000000000000000000000000000000000..c81bb22ddf723c0675493a9a437e088200a6b491
--- /dev/null
+++ b/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementMemberVO.java
@@ -0,0 +1,82 @@
+/**
+ * <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.modules.curriculum.restapi;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.olat.modules.curriculum.model.CurriculumElementMember;
+
+/**
+ * 
+ * Initial date: 4 juin 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlRootElement(name = "curriculumElementMemberVO")
+public class CurriculumElementMemberVO {
+	
+	private Long identityKey;
+	private String role;
+	private String inheritanceMode;
+	
+	public CurriculumElementMemberVO() {
+		//
+	}
+	
+	public static final CurriculumElementMemberVO valueOf(CurriculumElementMember membership) {
+		CurriculumElementMemberVO vo = new CurriculumElementMemberVO();
+		vo.setIdentityKey(membership.getIdentity().getKey());
+		vo.setRole(membership.getRole());
+		if(membership.getInheritanceMode() != null) {
+			vo.setInheritanceMode(membership.getInheritanceMode().name());
+		}
+		return vo;
+	}
+
+	public Long getIdentityKey() {
+		return identityKey;
+	}
+
+	public void setIdentityKey(Long identityKey) {
+		this.identityKey = identityKey;
+	}
+
+	public String getRole() {
+		return role;
+	}
+
+	public void setRole(String role) {
+		this.role = role;
+	}
+
+	public String getInheritanceMode() {
+		return inheritanceMode;
+	}
+
+	public void setInheritanceMode(String inheritanceMode) {
+		this.inheritanceMode = inheritanceMode;
+	}
+	
+	
+
+}
diff --git a/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementsWebService.java b/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementsWebService.java
index 4dbbfb1a342cb392b1818e4aa797324a645c03b0..3ff22a8cd14ae1833a7f94122a06c34a38c18919 100644
--- a/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementsWebService.java
+++ b/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementsWebService.java
@@ -24,27 +24,38 @@ import java.util.List;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 
+import org.olat.basesecurity.BaseSecurity;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.persistence.DB;
+import org.olat.core.id.Identity;
 import org.olat.modules.curriculum.Curriculum;
 import org.olat.modules.curriculum.CurriculumElement;
 import org.olat.modules.curriculum.CurriculumElementManagedFlag;
 import org.olat.modules.curriculum.CurriculumElementType;
+import org.olat.modules.curriculum.CurriculumRoles;
 import org.olat.modules.curriculum.CurriculumService;
+import org.olat.modules.curriculum.model.CurriculumElementMember;
 import org.olat.modules.curriculum.model.CurriculumElementRefImpl;
 import org.olat.modules.curriculum.model.CurriculumElementTypeRefImpl;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryService;
+import org.olat.user.restapi.UserVO;
+import org.olat.user.restapi.UserVOFactory;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * The security checks are done by the CurriculumsWebService.
@@ -55,10 +66,20 @@ import org.olat.modules.curriculum.model.CurriculumElementTypeRefImpl;
  */
 public class CurriculumElementsWebService {
 	
+	@Autowired
+	private DB dbInstance;
+	@Autowired
+	private BaseSecurity securityManager;
+	@Autowired
+	private CurriculumService curriculumService;
+	@Autowired
+	private RepositoryService repositoryService;
+	
 	private final Curriculum curriculum;
 	
 	public CurriculumElementsWebService(Curriculum curriculum) {
 		this.curriculum = curriculum;
+		CoreSpringFactory.autowireObject(this);
 	}
 	
 	/**
@@ -76,7 +97,6 @@ public class CurriculumElementsWebService {
 	@GET
 	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
 	public Response getCurriculumElements() {
-		CurriculumService curriculumService = CoreSpringFactory.getImpl(CurriculumService.class);
 		List<CurriculumElement> elements = curriculumService.getCurriculumElements(curriculum);
 		List<CurriculumElementVO> voes = new ArrayList<>(elements.size());
 		for(CurriculumElement element:elements) {
@@ -101,7 +121,6 @@ public class CurriculumElementsWebService {
 	@Path("{curriculumElementKey}")
 	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
 	public Response getCurriculumElement(@PathParam("curriculumElementKey") Long curriculumElementKey, @Context HttpServletRequest httpRequest) {
-		CurriculumService curriculumService = CoreSpringFactory.getImpl(CurriculumService.class);
 		CurriculumElement curriculumElement = curriculumService.getCurriculumElement(new CurriculumElementRefImpl(curriculumElementKey));
 		if(!curriculumElement.getCurriculum().getKey().equals(curriculum.getKey())) {
 			return Response.serverError().status(Status.UNAUTHORIZED).build();
@@ -190,8 +209,6 @@ public class CurriculumElementsWebService {
 	
 	
 	private CurriculumElement saveCurriculumElement(CurriculumElementVO curriculumElement) {
-		CurriculumService curriculumService = CoreSpringFactory.getImpl(CurriculumService.class);
-		
 		CurriculumElement elementToSave = null;
 		CurriculumElementType type = null;
 		if(curriculumElement.getCurriculumElementTypeKey() != null) {
@@ -229,15 +246,582 @@ public class CurriculumElementsWebService {
 		CurriculumElement savedElement = curriculumService.updateCurriculumElement(elementToSave);
 		if(move) {
 			curriculumService.moveCurriculumElement(savedElement, parentElement);
-			CoreSpringFactory.getImpl(DB.class).commit();
+			dbInstance.commit();
 			savedElement = curriculumService.getCurriculumElement(savedElement);
 		}
 		return savedElement;
 	}
 	
-	public void checkCurriculum(CurriculumElement element) {
+	private void checkCurriculum(CurriculumElement element) {
 		if(element.getCurriculum() != null && !element.getCurriculum().getKey().equals(curriculum.getKey())) {
 			throw new WebApplicationException(Response.serverError().status(Status.CONFLICT).build());
 		}
 	}
+	
+	/**
+	 * Add a relation between a repository entry and a curriculum element.
+	 * 
+	 * @response.representation.200.doc The relation was added
+	 * @response.representation.304.doc There is already a relation, nothing changed
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The curriculum element or the repository entry was not found
+	 * @param curriculumElementKey The curriculum element
+	 * @param repositoryEntryKey The repository entry
+	 * @return Nothing
+	 */
+	@PUT
+	@Path("{curriculumElementKey}/entries/{repositoryEntryKey}")
+	public Response addRepositoryEntryToElement(@PathParam("curriculumElementKey") Long curriculumElementKey,
+			@PathParam("repositoryEntryKey") Long repositoryEntryKey) {
+		CurriculumElement curriculumElement = curriculumService.getCurriculumElement(new CurriculumElementRefImpl(curriculumElementKey));
+		if(curriculumElement == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+		if(!curriculumElement.getCurriculum().getKey().equals(curriculum.getKey())) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		RepositoryEntry entry = repositoryService.loadByKey(repositoryEntryKey);
+		if(entry == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+		
+		if(!curriculumService.hasRepositoryEntry(curriculumElement, entry)) {
+			curriculumService.addRepositoryEntry(curriculumElement, entry, false);
+			return Response.ok().build();
+		}
+		return Response.ok().status(Status.NOT_MODIFIED).build();
+	}
+	
+	
+	/**
+	 * Remove a relation between a curriculum element and a repository entry.
+	 * 
+	 * @response.representation.200.doc The relation was successfully removed. 
+	 * @response.representation.304.doc There is no relation to remove
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The curriculum element or the repository entry was not found
+	 * @param curriculumElementKey The curriculum element
+	 * @param repositoryEntryKey The repository entry
+	 * @return Nothing
+	 */
+	@DELETE
+	@Path("{curriculumElementKey}/entries/{repositoryEntryKey}")
+	public Response removeRepositoryEntryToElement(@PathParam("curriculumElementKey") Long curriculumElementKey,
+			@PathParam("repositoryEntryKey") Long repositoryEntryKey) {
+		CurriculumElement curriculumElement = curriculumService.getCurriculumElement(new CurriculumElementRefImpl(curriculumElementKey));
+		if(curriculumElement == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+		if(!curriculumElement.getCurriculum().getKey().equals(curriculum.getKey())) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		RepositoryEntry entry = repositoryService.loadByKey(repositoryEntryKey);
+		if(entry == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+		
+		if(curriculumService.hasRepositoryEntry(curriculumElement, entry)) {
+			curriculumService.removeRepositoryEntry(curriculumElement, entry);
+			return Response.ok().build();
+		}
+		return Response.ok().status(Status.NOT_MODIFIED).build();
+	}
+	
+	/**
+	 * Get the memberships informations of the specified curriculum element.
+	 * 
+	 * @response.representation.200.qname {http://www.example.com}curriculumElementMemberVO
+	 * @response.representation.200.mediaType application/xml, application/json
+	 * @response.representation.200.doc The curriculum element membership
+	 * @response.representation.200.example {@link org.olat.modules.curriculum.restapi.Examples#SAMPLE_CURRICULUMELEMENTMEMBERVO}
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @param curriculumElementKey The curriculum element primary key
+	 * @param httpRequest The HTTP request
+	 * @return The curriculum element
+	 */
+	@GET
+	@Path("{curriculumElementKey}/members")
+	public Response getMembers(@PathParam("curriculumElementKey") Long curriculumElementKey) {
+		CurriculumElement curriculumElement = curriculumService.getCurriculumElement(new CurriculumElementRefImpl(curriculumElementKey));
+		if(curriculumElement == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+		if(!curriculumElement.getCurriculum().getKey().equals(curriculum.getKey())) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		
+		List<CurriculumElementMember> members = curriculumService.getMembers(curriculumElement);
+		List<CurriculumElementMemberVO> voList = new ArrayList<>(members.size());
+		for(CurriculumElementMember member:members) {
+			voList.add(CurriculumElementMemberVO.valueOf(member));
+		}
+		return Response.ok(voList.toArray(new CurriculumElementMemberVO[voList.size()])).build();
+	}
+	
+	/**
+	 * Get all members of the specified curriculum element. A query parameter can
+	 * specify the role of them.
+	 * 
+	 * @response.representation.200.qname {http://www.example.com}userVO
+	 * @response.representation.200.mediaType application/xml, application/json
+	 * @response.representation.200.doc The array of authors
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The course not found
+	 * @param httpRequest The HTTP request
+	 * @return It returns an array of <code>UserVO</code>
+	 */
+	@GET
+	@Path("{curriculumElementKey}/users")
+	public Response getUsers(@PathParam("curriculumElementKey") Long curriculumElementKey, @QueryParam("role") String role) {
+		CurriculumElement curriculumElement = curriculumService.getCurriculumElement(new CurriculumElementRefImpl(curriculumElementKey));
+		if(curriculumElement == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+		if(!curriculumElement.getCurriculum().getKey().equals(curriculum.getKey())) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		if(role != null && !CurriculumRoles.isValueOf(role)) {
+			return Response.serverError().status(Status.CONFLICT).build();
+		}
+		
+		List<Identity> members = curriculumService.getMembersIdentity(curriculumElement, CurriculumRoles.valueOf(role));
+		List<UserVO> voList = new ArrayList<>(members.size());
+		for(Identity member:members) {
+			voList.add(UserVOFactory.get(member));
+		}
+		return Response.ok(voList.toArray(new UserVO[voList.size()])).build();
+	}
+	
+	/**
+	 * Add a membership to the specified curriculum element.
+	 * 
+	 * @response.representation.qname {http://www.example.com}curriculumElementMemberVO
+	 * @response.representation.mediaType application/xml, application/json
+	 * @response.representation.doc The curriculum element membership to persist
+	 * @response.representation.example {@link org.olat.modules.curriculum.restapi.Examples#SAMPLE_CURRICULUMELEMENTMEMBERVO}
+	 * @response.representation.200.doc The membership was persisted
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The curriculum element or the identity was not found
+	 * @response.representation.409.doc The role is not allowed
+	 * @param curriculumElementKey The curriculum element primary key
+	 * @param membership The membership informations
+	 * @return Nothing
+	 */
+	@PUT
+	@Path("{curriculumElementKey}/members")
+	public Response putMembers(@PathParam("curriculumElementKey") Long curriculumElementKey,
+			CurriculumElementMemberVO membership) {
+		CurriculumElement curriculumElement = curriculumService.getCurriculumElement(new CurriculumElementRefImpl(curriculumElementKey));
+		if(curriculumElement == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+		if(!curriculumElement.getCurriculum().getKey().equals(curriculum.getKey())) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		Identity identity = securityManager.loadIdentityByKey(membership.getIdentityKey());
+		if(identity == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+		
+		String role = membership.getRole();
+		if(!CurriculumRoles.isValueOf(role)) {
+			return Response.serverError().status(Status.CONFLICT).build();
+		}
+		curriculumService.addMember(curriculumElement, identity, CurriculumRoles.valueOf(role));
+		return Response.ok().build();
+	}
+	
+	/**
+	 * Remove all memberships of the identity from the specified curriculum element.
+	 * 
+	 * @response.representation.200.doc The membership was removed
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The curriculum element or the identity was not found
+	 * @param curriculumElementKey The curriculum element primary key
+	 * @param identityKey The member to remove
+	 * @return Nothing
+	 */
+	@DELETE
+	@Path("{curriculumElementKey}/members/{identityKey}")
+	public Response deleteMembers(@PathParam("curriculumElementKey") Long curriculumElementKey,
+			@PathParam("identityKey") Long identityKey) {
+		CurriculumElement curriculumElement = curriculumService.getCurriculumElement(new CurriculumElementRefImpl(curriculumElementKey));
+		if(curriculumElement == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+		if(!curriculumElement.getCurriculum().getKey().equals(curriculum.getKey())) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		Identity identity = securityManager.loadIdentityByKey(identityKey);
+		if(identity == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+		
+		curriculumService.removeMember(curriculumElement, identity);
+		return Response.ok().build();
+	}
+	
+	/**
+	 * Get all participants of the specified curriculum element.
+	 * 
+	 * @response.representation.200.qname {http://www.example.com}userVO
+	 * @response.representation.200.mediaType application/xml, application/json
+	 * @response.representation.200.doc The array of participants
+	 * @response.representation.200.example {@link org.olat.user.restapi.Examples#SAMPLE_USERVOes}
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The curriculum element not found
+	 * @param httpRequest The HTTP request
+	 * @return It returns an array of <code>UserVO</code>
+	 */
+	@GET
+	@Path("{curriculumElementKey}/participants")
+	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+	public Response getParticipants(@PathParam("curriculumElementKey") Long curriculumElementKey) {
+		return getMembers(curriculumElementKey, CurriculumRoles.participant);
+	}
+	
+	/**
+	 * Get all coaches of the specified curriculum element.
+	 * 
+	 * @response.representation.200.qname {http://www.example.com}userVO
+	 * @response.representation.200.mediaType application/xml, application/json
+	 * @response.representation.200.doc The array of coaches
+	 * @response.representation.200.example {@link org.olat.user.restapi.Examples#SAMPLE_USERVOes}
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The curriculum element not found
+	 * @param httpRequest The HTTP request
+	 * @return It returns an array of <code>UserVO</code>
+	 */
+	@GET
+	@Path("{curriculumElementKey}/coaches")
+	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+	public Response getCoaches(@PathParam("curriculumElementKey") Long curriculumElementKey) {
+		return getMembers(curriculumElementKey, CurriculumRoles.coach);
+	}
+	
+	/**
+	 * Get all owners of the specified curriculum element.
+	 * 
+	 * @response.representation.200.qname {http://www.example.com}userVO
+	 * @response.representation.200.mediaType application/xml, application/json
+	 * @response.representation.200.doc The array of coaches
+	 * @response.representation.200.example {@link org.olat.user.restapi.Examples#SAMPLE_USERVOes}
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The curriculum element not found
+	 * @param httpRequest The HTTP request
+	 * @return It returns an array of <code>UserVO</code>
+	 */
+	@GET
+	@Path("{curriculumElementKey}/owners")
+	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+	public Response getOwners(@PathParam("curriculumElementKey") Long curriculumElementKey) {
+		return getMembers(curriculumElementKey, CurriculumRoles.owner);
+	}
+	
+	/**
+	 * Get all curriculum managers of the specified curriculum element.
+	 * 
+	 * @response.representation.200.qname {http://www.example.com}userVO
+	 * @response.representation.200.mediaType application/xml, application/json
+	 * @response.representation.200.doc The array of coaches
+	 * @response.representation.200.example {@link org.olat.user.restapi.Examples#SAMPLE_USERVOes}
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The curriculum element not found
+	 * @param httpRequest The HTTP request
+	 * @return It returns an array of <code>UserVO</code>
+	 */
+	@GET
+	@Path("{curriculumElementKey}/curriculummanagers")
+	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+	public Response getCurriculumManagers(@PathParam("curriculumElementKey") Long curriculumElementKey) {
+		return getMembers(curriculumElementKey, CurriculumRoles.curriculummanager);
+	}
+	
+	private Response getMembers(Long curriculumElementKey, CurriculumRoles role) {
+		CurriculumElement curriculumElement = curriculumService.getCurriculumElement(new CurriculumElementRefImpl(curriculumElementKey));
+		if(curriculumElement == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+		if(!curriculumElement.getCurriculum().getKey().equals(curriculum.getKey())) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		List<Identity> members = curriculumService.getMembersIdentity(curriculumElement, role);
+		List<UserVO> voList = new ArrayList<>(members.size());
+		for(Identity member:members) {
+			voList.add(UserVOFactory.get(member));
+		}
+		return Response.ok(voList.toArray(new UserVO[voList.size()])).build();
+	}
+	
+	/**
+	 * Make the specified user a participant of the curriculum element.
+	 * 
+	 * @response.representation.200.doc The membership was added
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The curriculum element or the identity was not found
+	 * @param curriculumElementKey The curriculum element primary key
+	 * @param identityKey The member to make a participant of
+	 * @return Nothing
+	 */
+	@PUT
+	@Path("{curriculumElementKey}/participants/{identityKey}")
+	public Response putParticipant(@PathParam("curriculumElementKey") Long curriculumElementKey, @PathParam("identityKey") Long identityKey) {
+		return putMember(curriculumElementKey, identityKey, CurriculumRoles.participant);
+	}
+	
+	/**
+	 * Make the specified user a coach of the curriculum element.
+	 * 
+	 * @response.representation.200.doc The membership was added
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The curriculum element or the identity was not found
+	 * @param curriculumElementKey The curriculum element primary key
+	 * @param identityKey The member to make a coach of
+	 * @return Nothing
+	 */
+	@PUT
+	@Path("{curriculumElementKey}/coaches/{identityKey}")
+	public Response putCoach(@PathParam("curriculumElementKey") Long curriculumElementKey, @PathParam("identityKey") Long identityKey) {
+		return putMember(curriculumElementKey, identityKey, CurriculumRoles.coach);
+	}
+	
+	/**
+	 * Make the specified user a course owner of the curriculum element.
+	 * 
+	 * @response.representation.200.doc The membership was added
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The curriculum element or the identity was not found
+	 * @param curriculumElementKey The curriculum element primary key
+	 * @param identityKey The member to make a course owner of
+	 * @return Nothing
+	 */
+	@PUT
+	@Path("{curriculumElementKey}/owners/{identityKey}")
+	public Response putOwner(@PathParam("curriculumElementKey") Long curriculumElementKey, @PathParam("identityKey") Long identityKey) {
+		return putMember(curriculumElementKey, identityKey, CurriculumRoles.owner);
+	}
+	
+	/**
+	 * Make the specified user a curricullum manager of the curriculum element.
+	 * 
+	 * @response.representation.200.doc The membership was added
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The curriculum element or the identity was not found
+	 * @param curriculumElementKey The curriculum element primary key
+	 * @param identityKey The member to make a curriculum manager of
+	 * @return Nothing
+	 */
+	@PUT
+	@Path("{curriculumElementKey}/curriculummanagers/{identityKey}")
+	public Response putCurriculumManager(@PathParam("curriculumElementKey") Long curriculumElementKey, @PathParam("identityKey") Long identityKey) {
+		return putMember(curriculumElementKey, identityKey, CurriculumRoles.curriculummanager);
+	}
+	
+	private Response putMember(Long curriculumElementKey, Long identityKey, CurriculumRoles role) {
+		CurriculumElement curriculumElement = curriculumService.getCurriculumElement(new CurriculumElementRefImpl(curriculumElementKey));
+		if(curriculumElement == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+		if(!curriculumElement.getCurriculum().getKey().equals(curriculum.getKey())) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		Identity identity = securityManager.loadIdentityByKey(identityKey);
+		if(identity == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+
+		curriculumService.addMember(curriculumElement, identity, role);
+		return Response.ok().build();
+	}
+	
+	/**
+	 * Make the array of users participant of the specified curriculum element.
+	 * 
+	 * @response.representation.qname {http://www.example.com}userVO
+	 * @response.representation.mediaType application/xml, application/json
+	 * @response.representation.doc The curriculum element membership to persist
+	 * @response.representation.example {@link org.olat.user.restapi.Examples#SAMPLE_USERVOes}
+	 * @response.representation.200.doc The memberships was persisted
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The curriculum element or the identity was not found
+	 * @response.representation.409.doc The role is not allowed
+	 * @param curriculumElementKey The curriculum element primary key
+	 * @param participants The future participants
+	 * @return Nothing
+	 */
+	@PUT
+	@Path("{curriculumElementKey}/participants")
+	@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+	public Response putParticipants(@PathParam("curriculumElementKey") Long curriculumElementKey, UserVO[] participants) {
+		return putMembers(curriculumElementKey, participants, CurriculumRoles.participant);
+	}
+	
+	/**
+	 * Make the array of users coach of the specified curriculum element.
+	 * 
+	 * @response.representation.qname {http://www.example.com}userVO
+	 * @response.representation.mediaType application/xml, application/json
+	 * @response.representation.doc The curriculum element membership to persist
+	 * @response.representation.example {@link org.olat.user.restapi.Examples#SAMPLE_USERVOes}
+	 * @response.representation.200.doc The memberships was persisted
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The curriculum element or the identity was not found
+	 * @response.representation.409.doc The role is not allowed
+	 * @param curriculumElementKey The curriculum element primary key
+	 * @param participants The future coaches
+	 * @return Nothing
+	 */
+	@PUT
+	@Path("{curriculumElementKey}/coaches")
+	@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+	public Response putCoaches(@PathParam("curriculumElementKey") Long curriculumElementKey, UserVO[] coaches) {
+		return putMembers(curriculumElementKey, coaches, CurriculumRoles.coach);
+	}
+	
+	/**
+	 * Make the array of users course owner of the specified curriculum element.
+	 * 
+	 * @response.representation.qname {http://www.example.com}userVO
+	 * @response.representation.mediaType application/xml, application/json
+	 * @response.representation.doc The curriculum element membership to persist
+	 * @response.representation.example {@link org.olat.user.restapi.Examples#SAMPLE_USERVOes}
+	 * @response.representation.200.doc The memberships was persisted
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The curriculum element or the identity was not found
+	 * @response.representation.409.doc The role is not allowed
+	 * @param curriculumElementKey The curriculum element primary key
+	 * @param participants The future course owners
+	 * @return Nothing
+	 */
+	@PUT
+	@Path("{curriculumElementKey}/owners")
+	@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+	public Response putOwners(@PathParam("curriculumElementKey") Long curriculumElementKey, UserVO[] coaches) {
+		return putMembers(curriculumElementKey, coaches, CurriculumRoles.owner);
+	}
+	
+	/**
+	 * Make the array of users curriculum managers of the specified curriculum element.
+	 * 
+	 * @response.representation.qname {http://www.example.com}userVO
+	 * @response.representation.mediaType application/xml, application/json
+	 * @response.representation.doc The curriculum element membership to persist
+	 * @response.representation.example {@link org.olat.user.restapi.Examples#SAMPLE_USERVOes}
+	 * @response.representation.200.doc The memberships was persisted
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The curriculum element or the identity was not found
+	 * @response.representation.409.doc The role is not allowed
+	 * @param curriculumElementKey The curriculum element primary key
+	 * @param participants The future curriculum manages
+	 * @return Nothing
+	 */
+	@PUT
+	@Path("{curriculumElementKey}/curriculummanagers")
+	@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+	public Response putCurriculumManagers(@PathParam("curriculumElementKey") Long curriculumElementKey, UserVO[] coaches) {
+		return putMembers(curriculumElementKey, coaches, CurriculumRoles.curriculummanager);
+	}
+	
+	private Response putMembers(Long curriculumElementKey, UserVO[] members, CurriculumRoles role) {
+		CurriculumElement curriculumElement = curriculumService.getCurriculumElement(new CurriculumElementRefImpl(curriculumElementKey));
+		if(curriculumElement == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+		if(!curriculumElement.getCurriculum().getKey().equals(curriculum.getKey())) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		
+		for(UserVO member:members) {
+			Identity identity = securityManager.loadIdentityByKey(member.getKey());
+			if(identity != null) {
+				curriculumService.addMember(curriculumElement, identity, role);
+			}
+		}
+		return Response.ok().build();
+	}
+	
+	/**
+	 * Remove the participant membership of the identity from the specified curriculum element.
+	 * 
+	 * @response.representation.200.doc The membership was removed
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The curriculum element or the identity was not found
+	 * @param curriculumElementKey The curriculum element primary key
+	 * @param identityKey The member to remove
+	 * @return Nothing
+	 */
+	@DELETE
+	@Path("{curriculumElementKey}/participants/{identityKey}")
+	public Response deleteParticipant(@PathParam("curriculumElementKey") Long curriculumElementKey,
+			@PathParam("identityKey") Long identityKey) {
+		return deleteMember(curriculumElementKey, identityKey, CurriculumRoles.participant);
+	}
+	
+	/**
+	 * Remove the coach membership of the identity from the specified curriculum element.
+	 * 
+	 * @response.representation.200.doc The membership was removed
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The curriculum element or the identity was not found
+	 * @param curriculumElementKey The curriculum element primary key
+	 * @param identityKey The member to remove
+	 * @return Nothing
+	 */
+	@DELETE
+	@Path("{curriculumElementKey}/coaches/{identityKey}")
+	public Response deleteCoach(@PathParam("curriculumElementKey") Long curriculumElementKey,
+			@PathParam("identityKey") Long identityKey) {
+		return deleteMember(curriculumElementKey, identityKey, CurriculumRoles.coach);
+	}
+	
+	/**
+	 * Remove the owner membership of the identity from the specified curriculum element.
+	 * 
+	 * @response.representation.200.doc The membership was removed
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The curriculum element or the identity was not found
+	 * @param curriculumElementKey The curriculum element primary key
+	 * @param identityKey The member to remove
+	 * @return Nothing
+	 */
+	@DELETE
+	@Path("{curriculumElementKey}/owners/{identityKey}")
+	public Response deleteOwner(@PathParam("curriculumElementKey") Long curriculumElementKey,
+			@PathParam("identityKey") Long identityKey) {
+		return deleteMember(curriculumElementKey, identityKey, CurriculumRoles.owner);
+	}
+	
+	/**
+	 * Remove the curriculum manager membership of the identity from the specified curriculum element.
+	 * 
+	 * @response.representation.200.doc The membership was removed
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The curriculum element or the identity was not found
+	 * @param curriculumElementKey The curriculum element primary key
+	 * @param identityKey The member to remove
+	 * @return Nothing
+	 */
+	@DELETE
+	@Path("{curriculumElementKey}/curriculummanagers/{identityKey}")
+	public Response deleteCurriculumManager(@PathParam("curriculumElementKey") Long curriculumElementKey,
+			@PathParam("identityKey") Long identityKey) {
+		return deleteMember(curriculumElementKey, identityKey, CurriculumRoles.curriculummanager);
+	}
+	
+	private Response deleteMember(Long curriculumElementKey, Long identityKey, CurriculumRoles role) {
+		CurriculumElement curriculumElement = curriculumService.getCurriculumElement(new CurriculumElementRefImpl(curriculumElementKey));
+		if(curriculumElement == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+		if(!curriculumElement.getCurriculum().getKey().equals(curriculum.getKey())) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		Identity identity = securityManager.loadIdentityByKey(identityKey);
+		if(identity == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+		
+		curriculumService.removeMember(curriculumElement, identity, role);
+		return Response.ok().build();
+	}
 }
diff --git a/src/main/java/org/olat/modules/curriculum/restapi/CurriculumsWebService.java b/src/main/java/org/olat/modules/curriculum/restapi/CurriculumsWebService.java
index a8371cb259276b3da52e2b4bbe1c92c1ba11525a..e649932c395a0b5767b7e2ae96dc75d1d67cc4a9 100644
--- a/src/main/java/org/olat/modules/curriculum/restapi/CurriculumsWebService.java
+++ b/src/main/java/org/olat/modules/curriculum/restapi/CurriculumsWebService.java
@@ -214,6 +214,9 @@ public class CurriculumsWebService {
 			@Context HttpServletRequest httpRequest) {
 		CurriculumService curriculumService = CoreSpringFactory.getImpl(CurriculumService.class);
 		Curriculum curriculum = curriculumService.getCurriculum(new CurriculumRefImpl(curriculumKey));
+		if(curriculum == null) {
+			throw new WebApplicationException(Status.NOT_FOUND);
+		}
 		allowedOrganisation(curriculum.getOrganisation(), getRoles(httpRequest));
 		return new CurriculumElementsWebService(curriculum);
 	}
diff --git a/src/main/java/org/olat/modules/curriculum/restapi/Examples.java b/src/main/java/org/olat/modules/curriculum/restapi/Examples.java
index 3be4ab6fed98ba5a9640b8a7a04f1d2f0059f644..4ff2e338ff34a87820a03dfef33fcc0e34a7a81d 100644
--- a/src/main/java/org/olat/modules/curriculum/restapi/Examples.java
+++ b/src/main/java/org/olat/modules/curriculum/restapi/Examples.java
@@ -35,6 +35,8 @@ public class Examples {
 	
 	public static final CurriculumElementTypeVO SAMPLE_CURRICULUMELEMENTTYPEVO = new CurriculumElementTypeVO();
 	
+	public static final CurriculumElementMemberVO SAMPLE_CURRICULUMELEMENTMEMBERVO = new CurriculumElementMemberVO();
+	
 	static {
 		SAMPLE_CURRICULUMVO.setKey(2l);
 		SAMPLE_CURRICULUMVO.setDisplayName("Dipl. engineer");
@@ -64,5 +66,9 @@ public class Examples {
 		SAMPLE_CURRICULUMELEMENTTYPEVO.setExternalId("CET-1001");
 		SAMPLE_CURRICULUMELEMENTTYPEVO.setDescription("This is the description of a type");
 		SAMPLE_CURRICULUMELEMENTTYPEVO.setManagedFlagsString("displayName");
+		
+		SAMPLE_CURRICULUMELEMENTMEMBERVO.setIdentityKey(111l);
+		SAMPLE_CURRICULUMELEMENTMEMBERVO.setInheritanceMode("none");
+		SAMPLE_CURRICULUMELEMENTMEMBERVO.setRole("participant");
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementUserManagementController.java b/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementUserManagementController.java
index 10c764bcf21342a938edaa6c42866e916b6f354b..1ce1db9398c1e23f48b03c8c70aef6c1cb404f0c 100644
--- a/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementUserManagementController.java
+++ b/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementUserManagementController.java
@@ -108,8 +108,8 @@ public class CurriculumElementUserManagementController extends FormBasicControll
 		
 		membersManaged = CurriculumElementManagedFlag.isManaged(curriculumElement, CurriculumElementManagedFlag.members);
 
-		
 		initForm(ureq);
+		loadModel(true);
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/modules/curriculum/ui/CurriculumListController.java b/src/main/java/org/olat/modules/curriculum/ui/CurriculumListController.java
index 7f13273be280fe580b6723e3e37af9339c26104a..312937f8b86e99b7a8c3af1d5f7b84f33c51fa90 100644
--- a/src/main/java/org/olat/modules/curriculum/ui/CurriculumListController.java
+++ b/src/main/java/org/olat/modules/curriculum/ui/CurriculumListController.java
@@ -83,7 +83,7 @@ public class CurriculumListController extends FormBasicController implements Act
 		toolsCol.setAlwaysVisible(true);
 		columnsModel.addFlexiColumnModel(toolsCol);
 		
-		tableModel = new CurriculumManagerDataModel(columnsModel);
+		tableModel = new CurriculumManagerDataModel(columnsModel, getLocale());
 		tableEl = uifactory.addTableElement(getWindowControl(), "table", tableModel, 20, false, getTranslator(), formLayout);
 		tableEl.setCustomizeColumns(true);
 		tableEl.setEmtpyTableMessageKey("table.curriculum.empty");
diff --git a/src/main/java/org/olat/modules/curriculum/ui/CurriculumListManagerController.java b/src/main/java/org/olat/modules/curriculum/ui/CurriculumListManagerController.java
index ef489937689919242eaf27d795dc43462eda4e71..7acfbbfc96514b8fd1d60deccfc77abe77063258 100644
--- a/src/main/java/org/olat/modules/curriculum/ui/CurriculumListManagerController.java
+++ b/src/main/java/org/olat/modules/curriculum/ui/CurriculumListManagerController.java
@@ -34,6 +34,7 @@ import org.olat.core.gui.components.form.flexible.impl.FormEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableSearchEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.link.LinkFactory;
@@ -88,7 +89,7 @@ public class CurriculumListManagerController extends FormBasicController impleme
 		this.secCallback = secCallback;
 		
 		initForm(ureq);
-		loadModel(true);
+		loadModel(null, true);
 	}
 	
 	@Override
@@ -111,15 +112,17 @@ public class CurriculumListManagerController extends FormBasicController impleme
 		toolsCol.setAlwaysVisible(true);
 		columnsModel.addFlexiColumnModel(toolsCol);
 		
-		tableModel = new CurriculumManagerDataModel(columnsModel);
+		tableModel = new CurriculumManagerDataModel(columnsModel, getLocale());
 		tableEl = uifactory.addTableElement(getWindowControl(), "table", tableModel, 20, false, getTranslator(), formLayout);
 		tableEl.setCustomizeColumns(true);
 		tableEl.setEmtpyTableMessageKey("table.curriculum.empty");
 		tableEl.setAndLoadPersistedPreferences(ureq, "cur-curriculum-manage");
+		tableEl.setSearchEnabled(true);
 	}
 	
-	private void loadModel(boolean reset) {
+	private void loadModel(String searchString, boolean reset) {
 		CurriculumSearchParameters params = new CurriculumSearchParameters();
+		params.setSearchString(searchString);
 		List<Curriculum> curriculums = curriculumService.getCurriculums(params);
 		List<CurriculumRow> rows = curriculums.stream()
 				.map(this::forgeRow).collect(Collectors.toList());
@@ -149,13 +152,13 @@ public class CurriculumListManagerController extends FormBasicController impleme
 	protected void event(UserRequest ureq, Controller source, Event event) {
 		if(newCurriculumCtrl == source) {
 			if(event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) {
-				loadModel(true);
+				loadModel(tableEl.getQuickSearchString(), true);
 			}
 			cmc.deactivate();
 			cleanUp();
 		} else if(editCurriculumCtrl == source) {
 			if(event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) {
-				loadModel(false);
+				loadModel(tableEl.getQuickSearchString(), false);
 			}
 			cmc.deactivate();
 			cleanUp();
@@ -192,6 +195,8 @@ public class CurriculumListManagerController extends FormBasicController impleme
 					CurriculumRow row = tableModel.getObject(se.getIndex());
 					doSelectCurriculum(ureq, row);
 				}
+			} else if(event instanceof FlexiTableSearchEvent) {
+				doSearch((FlexiTableSearchEvent)event);
 			}
 		} else if (source instanceof FormLink) {
 			FormLink link = (FormLink)source;
@@ -203,6 +208,10 @@ public class CurriculumListManagerController extends FormBasicController impleme
 		super.formInnerEvent(ureq, source, event);
 	}
 	
+	private void doSearch(FlexiTableSearchEvent event) {
+		loadModel(event.getSearch(), true);
+	}
+	
 	private void doNewCurriculum(UserRequest ureq) {
 		if(newCurriculumCtrl != null) return;
 
diff --git a/src/main/java/org/olat/modules/curriculum/ui/CurriculumManagerDataModel.java b/src/main/java/org/olat/modules/curriculum/ui/CurriculumManagerDataModel.java
index 19596b80c10e2b33cfe0df4d239773da4b31d433..c00e3a680f808f484f465cd3d79c9ed0cd845354 100644
--- a/src/main/java/org/olat/modules/curriculum/ui/CurriculumManagerDataModel.java
+++ b/src/main/java/org/olat/modules/curriculum/ui/CurriculumManagerDataModel.java
@@ -19,6 +19,9 @@
  */
 package org.olat.modules.curriculum.ui;
 
+import java.util.List;
+import java.util.Locale;
+
 import org.olat.core.commons.persistence.SortKey;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiSortableColumnDef;
@@ -34,13 +37,19 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFl
 public class CurriculumManagerDataModel extends DefaultFlexiTableDataModel<CurriculumRow>
 implements SortableFlexiTableDataModel<CurriculumRow> {
 	
-	public CurriculumManagerDataModel(FlexiTableColumnModel columnsModel) {
+	private final Locale locale;
+	
+	public CurriculumManagerDataModel(FlexiTableColumnModel columnsModel, Locale locale) {
 		super(columnsModel);
+		this.locale = locale;
 	}
 
 	@Override
-	public void sort(SortKey sortKey) {
-		//
+	public void sort(SortKey orderBy) {
+		if(orderBy != null) {
+			List<CurriculumRow> rows = new CurriculumManagerTableSort(orderBy, this, locale).sort();
+			super.setObjects(rows);
+		}
 	}
 	
 	@Override
@@ -62,7 +71,7 @@ implements SortableFlexiTableDataModel<CurriculumRow> {
 
 	@Override
 	public CurriculumManagerDataModel createCopyWithEmptyList() {
-		return new CurriculumManagerDataModel(getTableColumnModel());
+		return new CurriculumManagerDataModel(getTableColumnModel(), locale);
 	}
 	
 	public enum CurriculumCols implements FlexiSortableColumnDef {
diff --git a/src/main/java/org/olat/modules/curriculum/ui/CurriculumManagerTableSort.java b/src/main/java/org/olat/modules/curriculum/ui/CurriculumManagerTableSort.java
new file mode 100644
index 0000000000000000000000000000000000000000..9b5787ef89543eb85b6b393cc01264093889cda0
--- /dev/null
+++ b/src/main/java/org/olat/modules/curriculum/ui/CurriculumManagerTableSort.java
@@ -0,0 +1,39 @@
+/**
+ * <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.modules.curriculum.ui;
+
+import java.util.Locale;
+
+import org.olat.core.commons.persistence.SortKey;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate;
+
+/**
+ * 
+ * Initial date: 4 juin 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CurriculumManagerTableSort extends SortableFlexiTableModelDelegate<CurriculumRow> {
+	
+	public CurriculumManagerTableSort(SortKey orderBy, CurriculumManagerDataModel model, Locale locale) {
+		super(orderBy, model, locale);
+	}
+
+}
diff --git a/src/main/java/org/olat/modules/curriculum/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/curriculum/ui/_i18n/LocalStrings_de.properties
index 9bb522b152dfe958ae96e5c8bbb9ad9b2de77a28..f46efc3fea41e76fc2565a98318704022e7567e2 100644
--- a/src/main/java/org/olat/modules/curriculum/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/modules/curriculum/ui/_i18n/LocalStrings_de.properties
@@ -10,6 +10,8 @@ admin.description=Curriculum Konfiguration
 admin.menu.title=Curriculum
 admin.menu.title.alt=Curriculum
 admin.title=$\:admin.menu.title
+role.coach=Betreuer
+role.curriculummanager=Curriculumverwalter
 confirm.delete.element.type.sucessfull=Der Typ "{0}" wurde erfolgreich gel\u00F6scht.
 confirmation.delete.type=Wollen Sie wirklich den Typ "{0}" l\u00F6schen?
 confirmation.delete.type.title=Typ "{0}" l\u00F6schen
@@ -34,6 +36,8 @@ details.copy=Kopieren
 details.delete=L\u00F6schen
 info.copy.element.type.sucessfull=Der Typ "{0}" wurde erfolgreich kopiert.
 move.element=Element schieben
+role.owner=Kursbesitzer
+role.participant=Teilnehmer
 remove.memberships=Entfernen
 resources.add=$add.resources
 resources.add.title=
diff --git a/src/main/java/org/olat/modules/curriculum/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/curriculum/ui/_i18n/LocalStrings_en.properties
index d2d1d8fd4e79835de2a9eee3481ed8ac7646ca6c..1a204932b748788a4b7caed76ad13983e7ecb8d5 100644
--- a/src/main/java/org/olat/modules/curriculum/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/modules/curriculum/ui/_i18n/LocalStrings_en.properties
@@ -10,6 +10,8 @@ admin.description=Curriculum configuration
 admin.menu.title=Curriculum
 admin.menu.title.alt=Curriculum
 admin.title=$\:admin.menu.title
+role.coach=Coach
+role.curriculummanager=Curriculum manager
 confirm.delete.element.type.sucessfull=The type "{0}" was successfully deleted.
 confirmation.delete.type=Do you really want to delete this type "{0}"?
 confirmation.delete.type.title=Delete type "{0}"
@@ -34,6 +36,8 @@ details.copy=Copy
 details.delete=Delete
 info.copy.element.type.sucessfull=The type "{0}" was successfully copied.
 move.element=Move element
+role.owner=Course owner
+role.participant=Participant
 remove.memberships=Remove
 resources.add=$add.resources
 supervisor=Fachvorsteher (supervisor)
diff --git a/src/main/java/org/olat/repository/RepositoryManager.java b/src/main/java/org/olat/repository/RepositoryManager.java
index d0ef89acf617ff63dd9db1a84470fbd114a2cb1e..41a26aa00f9b242b434e359aba37f292a265dcff 100644
--- a/src/main/java/org/olat/repository/RepositoryManager.java
+++ b/src/main/java/org/olat/repository/RepositoryManager.java
@@ -1974,21 +1974,6 @@ public class RepositoryManager {
 		return new ArrayList<>(memberships.values());
 	}
 
-	public List<RepositoryEntryMembership> getOwnersMembership2(List<RepositoryEntry> res) {
-		if(res== null || res.isEmpty()) return Collections.emptyList();
-
-		StringBuilder sb = new StringBuilder(400);
-		sb.append("select distinct membership from ").append(RepositoryEntryMembership.class.getName()).append(" membership ")
-		  .append(" where membership.repoKey in (:repoKey)");
-
-		List<Long> repoKeys = PersistenceHelper.toKeys(res);
-		TypedQuery<RepositoryEntryMembership> query = dbInstance.getCurrentEntityManager()
-				.createQuery(sb.toString(), RepositoryEntryMembership.class)
-				.setParameter("repoKey", repoKeys);
-
-		return query.getResultList();
-	}
-
 	public void updateRepositoryEntryMemberships(Identity ureqIdentity, Roles ureqRoles, RepositoryEntry re,
 			List<RepositoryEntryPermissionChangeEvent> changes, MailPackage mailing) {
 
diff --git a/src/main/java/org/olat/repository/manager/RepositoryEntryRelationDAO.java b/src/main/java/org/olat/repository/manager/RepositoryEntryRelationDAO.java
index 4edcdb658076114804c08e19bd32cab926b3ceef..d49ff8f2865db9bb82c0d14bccfebcd2ae72e633 100644
--- a/src/main/java/org/olat/repository/manager/RepositoryEntryRelationDAO.java
+++ b/src/main/java/org/olat/repository/manager/RepositoryEntryRelationDAO.java
@@ -637,6 +637,22 @@ public class RepositoryEntryRelationDAO {
 			.getResultList();
 	}
 	
+	public boolean hasRelation(Group group, RepositoryEntryRef re) {
+		if(re == null || group == null) return false;
+		
+		String query = "select rel.key from repoentrytogroup as rel where rel.entry.key=:repoKey and rel.group.key=:groupKey";
+
+		List<Long> relations = dbInstance.getCurrentEntityManager()
+			.createQuery(query, Long.class)
+			.setParameter("repoKey", re.getKey())
+			.setParameter("groupKey", group.getKey())
+			.setFirstResult(0)
+			.setMaxResults(1)
+			.getResultList();
+		return relations != null && !relations.isEmpty() && relations.get(0) != null;
+	}
+	
+	
 	/**
 	 * Get the relation from a base group to the repository entries
 	 * 
diff --git a/src/main/java/org/olat/repository/model/RepositoryEntryMembership.java b/src/main/java/org/olat/repository/model/RepositoryEntryMembership.java
index d56ab13ecedfe5125a349ba72705a29c75bb8cad..4df56e42fe658f9bca7977980e68e09a986fbacc 100644
--- a/src/main/java/org/olat/repository/model/RepositoryEntryMembership.java
+++ b/src/main/java/org/olat/repository/model/RepositoryEntryMembership.java
@@ -1,4 +1,5 @@
 /**
+
  * <a href="http://www.openolat.org">
  * OpenOLAT - Online Learning and Training</a><br>
  * <p>
diff --git a/src/main/java/org/olat/repository/ui/author/RepositoryMembersController.java b/src/main/java/org/olat/repository/ui/author/RepositoryMembersController.java
index 3a1d9b7b2bccb10dc43483c819da2715f7ff0a2e..fe0189aec8ca465208f1cd7eded58fb78a92d1ca 100644
--- a/src/main/java/org/olat/repository/ui/author/RepositoryMembersController.java
+++ b/src/main/java/org/olat/repository/ui/author/RepositoryMembersController.java
@@ -21,6 +21,7 @@ package org.olat.repository.ui.author;
 
 import java.util.List;
 
+import org.olat.basesecurity.GroupRoles;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
@@ -47,7 +48,7 @@ import org.olat.group.BusinessGroupService;
 import org.olat.group.model.BusinessGroupMembershipChange;
 import org.olat.group.ui.main.AbstractMemberListController;
 import org.olat.group.ui.main.MemberPermissionChangeEvent;
-import org.olat.group.ui.main.MemberView;
+import org.olat.group.ui.main.MemberRow;
 import org.olat.group.ui.main.SearchMembersParams;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryEntryManagedFlag;
@@ -77,7 +78,7 @@ public class RepositoryMembersController extends AbstractMemberListController {
 				Util.createPackageTranslator(RepositoryService.class, ureq.getLocale(),
 						Util.createPackageTranslator(AbstractMemberListController.class, ureq.getLocale())));
 
-		params = new SearchMembersParams(true, true, true, true, true, true, true);
+		params = new SearchMembersParams(true, GroupRoles.owner, GroupRoles.coach, GroupRoles.participant, GroupRoles.waiting);
 		reloadModel();
 	}
 
@@ -128,7 +129,7 @@ public class RepositoryMembersController extends AbstractMemberListController {
 	}
 	
 	@Override
-	protected void doOpenAssessmentTool(UserRequest ureq, MemberView member) {
+	protected void doOpenAssessmentTool(UserRequest ureq, MemberRow member) {
 		//
 	}
 	
diff --git a/src/main/java/org/olat/user/restapi/OrganisationsWebService.java b/src/main/java/org/olat/user/restapi/OrganisationsWebService.java
index b14a12fd5d9db09a4be0097155048853d127445a..d2a71d8a720ff8f4d52f57fcc19f050135dbc37d 100644
--- a/src/main/java/org/olat/user/restapi/OrganisationsWebService.java
+++ b/src/main/java/org/olat/user/restapi/OrganisationsWebService.java
@@ -21,10 +21,12 @@ package org.olat.user.restapi;
 
 import static org.olat.restapi.security.RestSecurityHelper.isAdmin;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
@@ -36,13 +38,16 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 
+import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.OrganisationManagedFlag;
+import org.olat.basesecurity.OrganisationRoles;
 import org.olat.basesecurity.OrganisationService;
 import org.olat.basesecurity.OrganisationType;
 import org.olat.basesecurity.model.OrganisationRefImpl;
 import org.olat.basesecurity.model.OrganisationTypeRefImpl;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.persistence.DB;
+import org.olat.core.id.Identity;
 import org.olat.core.id.Organisation;
 
 /**
@@ -201,7 +206,8 @@ public class OrganisationsWebService {
 	@Path("{organisationKey}")
 	@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
 	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
-	public Response postOrganisation(@PathParam("organisationKey") Long organisationKey, OrganisationVO organisation, @Context HttpServletRequest httpRequest) {
+	public Response postOrganisation(@PathParam("organisationKey") Long organisationKey, OrganisationVO organisation,
+			@Context HttpServletRequest httpRequest) {
 		boolean isSystemAdministrator = isAdmin(httpRequest);
 		if(!isSystemAdministrator) {
 			return Response.serverError().status(Status.UNAUTHORIZED).build();
@@ -264,6 +270,200 @@ public class OrganisationsWebService {
 		return new OrganisationTypesWebService();
 	}
 	
+	/**
+	 * Get all members of the specified organisation with the specified role.
+	 * 
+	 * @response.representation.200.qname {http://www.example.com}userVO
+	 * @response.representation.200.mediaType application/xml, application/json
+	 * @response.representation.200.doc The array of members
+	 * @response.representation.200.example {@link org.olat.user.restapi.Examples#SAMPLE_USERVOes}
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The organisation was not found
+	 * @response.representation.409.doc The rolle is not valid
+	 * @param httpRequest The HTTP request
+	 * @return It returns an array of <code>UserVO</code>
+	 */
+	@GET
+	@Path("{organisationKey}/{role}")
+	public Response getMembers(@PathParam("organisationKey") Long organisationKey, @PathParam("role") String role,
+			@Context HttpServletRequest httpRequest) {
+		boolean isSystemAdministrator = isAdmin(httpRequest);
+		if(!isSystemAdministrator) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		return getMembers(organisationKey, getRoles(role));
+	}
+	
+	private Response getMembers(Long organisationKey, OrganisationRoles role) {
+		OrganisationService organisationService = CoreSpringFactory.getImpl(OrganisationService.class);
+		
+		Organisation organisation = organisationService.getOrganisation(new OrganisationRefImpl(organisationKey));
+		if(organisation == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+		if(role == null) {
+			return Response.serverError().status(Status.CONFLICT).build();
+		}
+
+		List<Identity> members = organisationService.getMembersIdentity(organisation, role);
+		List<UserVO> voList = new ArrayList<>(members.size());
+		for(Identity member:members) {
+			voList.add(UserVOFactory.get(member));
+		}
+		return Response.ok(voList.toArray(new UserVO[voList.size()])).build();
+	}
+	
+	/**
+	 * Make the specified user a member of the specified organization
+	 * with the specified role.
+	 * 
+	 * @response.representation.200.doc The membership was added
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The organization or the identity was not found
+	 * @param organisationKey The organization primary key
+	 * @param role The role
+	 * @param identityKey The member to make a coach of
+	 * @param httpRequest The HTTP request
+	 * @return Nothing
+	 */
+	@PUT
+	@Path("{organisationKey}/{role}/{identityKey}")
+	public Response putMember(@PathParam("organisationKey") Long organisationKey, @PathParam("role") String role,
+			@PathParam("identityKey") Long identityKey, @Context HttpServletRequest httpRequest) {
+		boolean isSystemAdministrator = isAdmin(httpRequest);
+		if(!isSystemAdministrator) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		return putMember(organisationKey, identityKey, getRoles(role));
+	}
+	
+	private Response putMember(Long organisationKey, Long identityKey, OrganisationRoles role) {
+		OrganisationService organisationService = CoreSpringFactory.getImpl(OrganisationService.class);
+		Organisation organisation = organisationService.getOrganisation(new OrganisationRefImpl(organisationKey));
+		if(organisation == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+		if(role == null) {
+			return Response.serverError().status(Status.CONFLICT).build();
+		}
+
+		BaseSecurity securityManager = CoreSpringFactory.getImpl(BaseSecurity.class);
+		Identity identity = securityManager.loadIdentityByKey(identityKey);
+		if(identity == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+
+		organisationService.addMember(organisation, identity, role);
+		return Response.ok().build();
+	}
+	
+	/**
+	 * Add a membership to the specified curriculum element.
+	 * 
+	 * @response.representation.qname {http://www.example.com}curriculumElementMemberVO
+	 * @response.representation.mediaType application/xml, application/json
+	 * @response.representation.doc The curriculum element membership to persist
+	 * @response.representation.example {@link org.olat.modules.curriculum.restapi.Examples#SAMPLE_CURRICULUMELEMENTMEMBERVO}
+	 * @response.representation.200.doc The membership was persisted
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The curriculum element or the identity was not found
+	 * @response.representation.409.doc The role is not allowed
+	 * @param organisationKey The curriculum element primary key
+	 * @param role The membership informations
+	 * @return Nothing
+	 */
+	@PUT
+	@Path("{organisationKey}/{role}")
+	public Response putMembers(@PathParam("organisationKey") Long organisationKey, @PathParam("role") String role,
+			UserVO[] members, @Context HttpServletRequest httpRequest) {
+		boolean isSystemAdministrator = isAdmin(httpRequest);
+		if(!isSystemAdministrator) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		
+		OrganisationService organisationService = CoreSpringFactory.getImpl(OrganisationService.class);
+		Organisation organisation = organisationService.getOrganisation(new OrganisationRefImpl(organisationKey));
+		if(organisation == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+	
+		if(getRoles(role) == null) {
+			return Response.serverError().status(Status.CONFLICT).build();
+		}
+
+		BaseSecurity securityManager = CoreSpringFactory.getImpl(BaseSecurity.class);
+		for(UserVO member:members) {
+			Identity identity = securityManager.loadIdentityByKey(member.getKey());
+			if(identity != null) {
+				organisationService.addMember(organisation, identity, getRoles(role));
+			}
+		}
+		return Response.ok().build();
+	}
+	
+	/**
+	 * Remove the membership of the identity from the specified organization and role.
+	 * 
+	 * @response.representation.200.doc The membership was removed
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The organization or the identity was not found
+	 * @param curriculumElementKey The curriculum element primary key
+	 * @param identityKey The member to remove
+	 * @return Nothing
+	 */
+	@DELETE
+	@Path("{organisationKey}/{role}/{identityKey}")
+	public Response deleteMember(@PathParam("organisationKey") Long organisationKey, @PathParam("role") String role,
+			@PathParam("identityKey") Long identityKey, @Context HttpServletRequest httpRequest) {
+		boolean isSystemAdministrator = isAdmin(httpRequest);
+		if(!isSystemAdministrator) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		return deleteMember(organisationKey, identityKey, getRoles(role));
+	}
+	
+	private Response deleteMember(Long organisationKey, Long identityKey, OrganisationRoles role) {
+		OrganisationService organisationService = CoreSpringFactory.getImpl(OrganisationService.class);
+		Organisation organisation = organisationService.getOrganisation(new OrganisationRefImpl(organisationKey));
+		if(organisation == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+		if(role == null) {
+			return Response.serverError().status(Status.CONFLICT).build();
+		}
+		
+		BaseSecurity securityManager = CoreSpringFactory.getImpl(BaseSecurity.class);
+		Identity identity = securityManager.loadIdentityByKey(identityKey);
+		if(identity == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+		
+		organisationService.removeMember(organisation, identity, role);
+		return Response.ok().build();
+	}
+	
+	/**
+	 * Convert beautified role to enum.
+	 * 
+	 * @param role
+	 * @return The role enum or null
+	 */
+	private OrganisationRoles getRoles(String role) {
+		if(OrganisationRoles.isValue(role)) {
+			return OrganisationRoles.valueOf(role);
+		} else if("coaches".equals(role)) {
+			return OrganisationRoles.coach;
+		}
+		
+		if(role.endsWith("s")) {
+			role = role.substring(0, role.length() - 1);
+		}
+		if(OrganisationRoles.isValue(role)) {
+			return OrganisationRoles.valueOf(role);
+		}
+		return null;	
+	}
+	
 	
 	private OrganisationVO[] toArrayOfVOes(List<Organisation> organisations) {
 		int i=0;
diff --git a/src/main/java/org/olat/user/restapi/UserVO.java b/src/main/java/org/olat/user/restapi/UserVO.java
index b30341c23f8543ad9c76834ce15273491c8d1676..22dfcbb44d53804968ed405b2bba19e73ed4a73d 100644
--- a/src/main/java/org/olat/user/restapi/UserVO.java
+++ b/src/main/java/org/olat/user/restapi/UserVO.java
@@ -30,8 +30,6 @@ import javax.xml.bind.annotation.XmlRootElement;
 
 /**
  * 
- * Description:<br>
- * TODO: srosse Class Description for UserVO
  * 
  * <P>
  * Initial Date:  7 apr. 2010 <br>
@@ -52,7 +50,7 @@ public class UserVO {
 
 	@XmlElementWrapper(name="properties")
 	@XmlElement(name="property")
-	private List<UserPropertyVO> properties = new ArrayList<UserPropertyVO>();
+	private List<UserPropertyVO> properties = new ArrayList<>();
 
 	public UserVO() {
 		//make JAXB happy
diff --git a/src/main/java/org/olat/user/ui/organisation/RoleListController.java b/src/main/java/org/olat/user/ui/organisation/RoleListController.java
index a8005a306c1dbf201d8ef2ff69c63aabac75161b..cd9e73ed3243946deb2a388628b8227b1d735807 100644
--- a/src/main/java/org/olat/user/ui/organisation/RoleListController.java
+++ b/src/main/java/org/olat/user/ui/organisation/RoleListController.java
@@ -56,7 +56,7 @@ public class RoleListController extends BasicController {
 	}
 	
 	private Link addLink(OrganisationRoles role, List<String> links) {
-		Link link = LinkFactory.createLink(role.name(), role.name(), getTranslator(), mainVC, this, Link.LINK);
+		Link link = LinkFactory.createLink("role." + role.name(), role.name(), getTranslator(), mainVC, this, Link.LINK);
 		link.setUserObject(role);
 		mainVC.put(role.name(), link);
 		links.add(role.name());
diff --git a/src/main/java/org/olat/user/ui/organisation/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/user/ui/organisation/_i18n/LocalStrings_de.properties
index cae64a39b8cf6cfb9ba0a42474af607c74f9462f..8d39503c354efda7b7d42ecf2eb2d50e1c1b26f5 100644
--- a/src/main/java/org/olat/user/ui/organisation/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/user/ui/organisation/_i18n/LocalStrings_de.properties
@@ -6,20 +6,22 @@ add.root.type=Organisationtyp erstellen
 admin.description=Organisationen verwalten
 admin.menu.title=Organisationen
 admin.menu.title.alt=Organisationen
-administrator=Administrator
-author=Author
-coach=Betreuer
+role.administrator=Administrator
+role.author=Author
+role.coach=Betreuer
+role.curriculummanager=Curriculumverwalter
 confirm.remove.text=Wollen Sie wirklich diese Benutzer ihre Mitgliedschaft entfernen?
 confirm.remove.title=Mitglieder entfernen
 create.organisation=Neue Organisation erstellen
-curriculummanager=Curriculumverwalter
+role.curriculummanager=Curriculumverwalter
 edit.type=Organisationtyp editieren
-groupmanager=Gruppenverwalter
-guest=Gast
+role.groupmanager=Gruppenverwalter
+role.guest=Gast
+role.principal=Principal
 institution.to.org=Ressourceverwaltung mit Institutionname zu Organisationen migrieren
 institution.to.org.explain=Erkl\u00E4rung
 institution.to.org.label=Migration
-learnresourcemanager=Lernressourcenverwalter
+role.learnresourcemanager=Lernressourcenverwalter
 migrate=Migrieren
 move.organisation=Organisation schieben
 organisation.admin.enabled=Organisationen einschalten
@@ -34,9 +36,9 @@ organisation.structure=Organisationenstruktur
 organisation.type=Organisationtyp
 organisation.types=Organisationentypen
 organisation.user.management=Benutzerverwaltung
-poolmanager=Poolverwalter
+role.poolmanager=Poolverwalter
 remove.memberships=Entfernen
-sysadmin=Systemadministrator
+role.sysadmin=Systemadministrator
 table.header.displayName=Name
 table.header.edit=Editieren
 table.header.identifier=Org. ID
@@ -57,7 +59,7 @@ type.cssClass=CSS Class
 type.description=Beschreibung
 type.displayname=Name
 type.identifier=Bezeichnung
-user=Benutzer
-usermanager=Benutzerverwalter
+role.user=Benutzer
+role.usermanager=Benutzerverwalter
 warning.atleastone.member=Sie m\u00FCssen mindestens ein Benutzer w\u00E4hlen.
 warning.organisation.deleted=Die Organisation wurde seit kurzem gel\u00F6scht.
diff --git a/src/main/java/org/olat/user/ui/organisation/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/user/ui/organisation/_i18n/LocalStrings_en.properties
index 6bbb8cf4a7fbf9ca4af2d0547fcc86ad4cc230ad..97b79faebc55682e2b0c9008996d469323b3fc22 100644
--- a/src/main/java/org/olat/user/ui/organisation/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/user/ui/organisation/_i18n/LocalStrings_en.properties
@@ -6,20 +6,22 @@ add.root.type=Create organisation type
 admin.description=Manage your organisations
 admin.menu.title=Organisations
 admin.menu.title.alt=Organisations
-administrator=Administrator
-author=Author
-coach=Coach
+role.administrator=Administrator
+role.author=Author
+role.coach=Coach
+role.curriculummanager=Curriculum manager
 confirm.remove.text=Do you really want to remove the memberships of this user?
 confirm.remove.title=Remove membership
 create.organisation=Create new organisation
-curriculummanager=Curriculum manager
+role.curriculummanager=Curriculum manager
 edit.type=Edit organisation type
-groupmanager=Group manager
-guest=Guest
+role.groupmanager=Group manager
+role.guest=Guest
+role.principal=Principal
 institution.to.org=Migrate learn resource management by institution name to organisation
 institution.to.org.explain=Explanation
 institution.to.org.label=Migration
-learnresourcemanager=Learn resource manager
+role.learnresourcemanager=Learn resource manager
 migrate=Migrate
 move.organisation=Move organisation
 organisation.admin.enabled=Enable organisations
@@ -34,9 +36,9 @@ organisation.structure=Organisations structures
 organisation.type=Organisation type
 organisation.types=Organisations types
 organisation.user.management=User management
-poolmanager=Question bank manager
+role.poolmanager=Question bank manager
 remove.memberships=Remove
-sysadmin=System administrator
+role.sysadmin=System administrator
 table.header.displayName=Name
 table.header.edit=Edit
 table.header.identifier=Org. ID
@@ -57,7 +59,7 @@ type.cssClass=CSS class
 type.description=Description
 type.displayname=Name
 type.identifier=Identifier
-user=User
-usermanager=User manager
+role.user=User
+role.usermanager=User manager
 warning.atleastone.member=You need to select at least one user.
 warning.organisation.deleted=The organisation was deleted.
diff --git a/src/main/java/org/olat/user/ui/organisation/component/RoleFlexiCellRenderer.java b/src/main/java/org/olat/user/ui/organisation/component/RoleFlexiCellRenderer.java
index e3077c88c8c9cc439f186bda4420748608d4eb3e..6bbc11551ebb8ef473403af7bd87a17d2c90f3d7 100644
--- a/src/main/java/org/olat/user/ui/organisation/component/RoleFlexiCellRenderer.java
+++ b/src/main/java/org/olat/user/ui/organisation/component/RoleFlexiCellRenderer.java
@@ -47,11 +47,11 @@ public class RoleFlexiCellRenderer implements FlexiCellRenderer {
 			URLBuilder ubu, Translator trans) {
 		if(cellValue instanceof OrganisationRoles) {
 			OrganisationRoles role = (OrganisationRoles)cellValue;
-			target.append(translator.translate(role.name()));
+			target.append(translator.translate("role.".concat(role.name())));
 		} else if(cellValue instanceof String) {
 			String val = (String)cellValue;
 			if(OrganisationRoles.valid(val)) {
-				target.append(translator.translate(OrganisationRoles.valueOf(val).name()));
+				target.append(translator.translate("role.".concat(OrganisationRoles.valueOf(val).name())));
 			} else {
 				target.append(StringHelper.escapeHtml(val));
 			}
diff --git a/src/test/java/org/olat/modules/curriculum/manager/CurriculumDAOTest.java b/src/test/java/org/olat/modules/curriculum/manager/CurriculumDAOTest.java
index 0ca7a0812b192dc0b009f91f22f4fee691d6b703..816ba1b79c8ae14a1e92d2e1f6316bba9f604ee4 100644
--- a/src/test/java/org/olat/modules/curriculum/manager/CurriculumDAOTest.java
+++ b/src/test/java/org/olat/modules/curriculum/manager/CurriculumDAOTest.java
@@ -21,6 +21,7 @@ package org.olat.modules.curriculum.manager;
 
 import java.util.Collections;
 import java.util.List;
+import java.util.UUID;
 
 import org.junit.Assert;
 import org.junit.Test;
@@ -111,4 +112,34 @@ public class CurriculumDAOTest extends OlatTestCase {
 		Assert.assertEquals(organisation, curriculums.get(0).getOrganisation());
 		Assert.assertNotNull(((CurriculumImpl)curriculums.get(0)).getGroup().getKey());
 	}
+	
+	@Test
+	public void search_searchString() {
+		String identifier = UUID.randomUUID().toString();
+		String displayName = UUID.randomUUID().toString();
+		Curriculum curriculum = curriculumDao.createAndPersist(identifier, displayName, "Short desc.", null);
+		dbInstance.commitAndCloseSession();
+		
+		// search something which doesn't exists
+		CurriculumSearchParameters params = new CurriculumSearchParameters();
+		params.setSearchString("AAAAAAAA");
+		List<Curriculum> curriculums = curriculumDao.search(params);
+		Assert.assertTrue(curriculums.isEmpty());
+		
+		// search by identifier
+		params.setSearchString(identifier);
+		List<Curriculum> curriculumById = curriculumDao.search(params);
+		Assert.assertEquals(1, curriculumById.size());
+		Assert.assertEquals(curriculum, curriculumById.get(0));
+		
+		// search by identifier
+		params.setSearchString(displayName.substring(0, 25).toUpperCase());
+		List<Curriculum> curriculumByName = curriculumDao.search(params);
+		Assert.assertTrue(curriculumByName.contains(curriculum));
+		
+		// search by primary key
+		params.setSearchString(curriculum.getKey().toString());
+		List<Curriculum> curriculumByKey = curriculumDao.search(params);
+		Assert.assertTrue(curriculumByKey.contains(curriculum));
+	}
 }
diff --git a/src/test/java/org/olat/modules/curriculum/manager/CurriculumElementDAOTest.java b/src/test/java/org/olat/modules/curriculum/manager/CurriculumElementDAOTest.java
index 42300f605bf6b89a740d53a609062d0d33ca2e1b..673124fba10a9efca345d23410e17b53f7825743 100644
--- a/src/test/java/org/olat/modules/curriculum/manager/CurriculumElementDAOTest.java
+++ b/src/test/java/org/olat/modules/curriculum/manager/CurriculumElementDAOTest.java
@@ -225,7 +225,7 @@ public class CurriculumElementDAOTest extends OlatTestCase {
 		Identity supervisor = JunitTestHelper.createAndPersistIdentityAsRndUser("cur-supervisor-1");
 		Curriculum curriculum = curriculumService.createCurriculum("cur-for-el-4", "Curriculum for element", "Curriculum", null);
 		CurriculumElement element = curriculumService.createCurriculumElement("Element-4", "4. Element", null, null, null, null, curriculum);
-		curriculumService.addMember(element, supervisor, CurriculumRoles.supervisor);
+		curriculumService.addMember(element, supervisor, CurriculumRoles.curriculummanager);
 		dbInstance.commitAndCloseSession();
 		
 		List<CurriculumElementMember> members = curriculumElementDao.getMembers(element);
@@ -233,6 +233,20 @@ public class CurriculumElementDAOTest extends OlatTestCase {
 		Assert.assertEquals(1, members.size());
 		CurriculumElementMember member = members.get(0);
 		Assert.assertEquals(supervisor, member.getIdentity());
-		Assert.assertEquals(CurriculumRoles.supervisor.name(), member.getRole());
+		Assert.assertEquals(CurriculumRoles.curriculummanager.name(), member.getRole());
+	}
+	
+	@Test
+	public void getMembersIdentity() {
+		Identity supervisor = JunitTestHelper.createAndPersistIdentityAsRndUser("cur-supervisor-1");
+		Curriculum curriculum = curriculumService.createCurriculum("cur-for-el-4", "Curriculum for element", "Curriculum", null);
+		CurriculumElement element = curriculumService.createCurriculumElement("Element-4", "4. Element", null, null, null, null, curriculum);
+		curriculumService.addMember(element, supervisor, CurriculumRoles.curriculummanager);
+		dbInstance.commitAndCloseSession();
+		
+		List<Identity> members = curriculumElementDao.getMembersIdentity(element, CurriculumRoles.curriculummanager.name());
+		Assert.assertNotNull(members);
+		Assert.assertEquals(1, members.size());
+		Assert.assertEquals(supervisor, members.get(0));
 	}
 }
diff --git a/src/test/java/org/olat/modules/curriculum/manager/CurriculumRepositoryEntryRelationDAOTest.java b/src/test/java/org/olat/modules/curriculum/manager/CurriculumRepositoryEntryRelationDAOTest.java
index 2bbd97a47b5653eef9c26a8576bb63b207cbac16..e1355c80ddcbf1247a707d4734f2156338abe9db 100644
--- a/src/test/java/org/olat/modules/curriculum/manager/CurriculumRepositoryEntryRelationDAOTest.java
+++ b/src/test/java/org/olat/modules/curriculum/manager/CurriculumRepositoryEntryRelationDAOTest.java
@@ -84,7 +84,6 @@ public class CurriculumRepositoryEntryRelationDAOTest extends OlatTestCase {
 		Assert.assertEquals(entry, entries.get(0));
 	}
 	
-	
 	@Test
 	public void getCurriculumElements() {
 		Curriculum curriculum = curriculumService.createCurriculum("cur-el-rel-2", "Curriculum for relation", "Curriculum", null);
@@ -101,5 +100,43 @@ public class CurriculumRepositoryEntryRelationDAOTest extends OlatTestCase {
 		Assert.assertEquals(element, elements.get(0));
 	}
 	
-
+	@Test
+	public void getRelations() {
+		Curriculum curriculum = curriculumService.createCurriculum("cur-el-rel-3", "Curriculum for relation", "Curriculum", null);
+		CurriculumElement element = curriculumService.createCurriculumElement("Element-for-rel", "Element for relation", null, null, null, null, curriculum);
+		Identity author = JunitTestHelper.createAndPersistIdentityAsRndUser("cur-el-re-auth");
+		RepositoryEntry entry = JunitTestHelper.createRandomRepositoryEntry(author);
+		dbInstance.commit();
+		curriculumService.addRepositoryEntry(element, entry, false);
+		dbInstance.commitAndCloseSession();
+		
+		List<CurriculumRepositoryEntryRelation> relations = curriculumRepositoryEntryRelationDao.getRelations(entry, element);
+		Assert.assertNotNull(relations);
+		Assert.assertEquals(1, relations.size());
+		Assert.assertEquals(element, relations.get(0).getCurriculumElement());
+		Assert.assertEquals(entry, relations.get(0).getEntry());
+	}
+	
+	@Test
+	public void deleteRelations() {
+		Curriculum curriculum = curriculumService.createCurriculum("cur-el-rel-4", "Curriculum for relation", "Curriculum", null);
+		CurriculumElement element = curriculumService.createCurriculumElement("Element-for-rel", "Element for relation", null, null, null, null, curriculum);
+		Identity author = JunitTestHelper.createAndPersistIdentityAsRndUser("cur-el-re-auth");
+		RepositoryEntry entry = JunitTestHelper.createRandomRepositoryEntry(author);
+		dbInstance.commit();
+		curriculumService.addRepositoryEntry(element, entry, false);
+		dbInstance.commitAndCloseSession();
+		
+		// check if the relation is really there.
+		List<CurriculumRepositoryEntryRelation> relations = curriculumRepositoryEntryRelationDao.getRelations(entry, element);
+		Assert.assertEquals(1, relations.size());
+		
+		// delete the relations
+		curriculumRepositoryEntryRelationDao.deleteRelation(entry, element);
+		dbInstance.commitAndCloseSession();
+		
+		// check that there isn't a relation left
+		List<CurriculumRepositoryEntryRelation> deletedRelations = curriculumRepositoryEntryRelationDao.getRelations(entry, element);
+		Assert.assertTrue(deletedRelations.isEmpty());
+	}
 }
diff --git a/src/test/java/org/olat/repository/manager/RepositoryEntryRelationDAOTest.java b/src/test/java/org/olat/repository/manager/RepositoryEntryRelationDAOTest.java
index f72ddc06f9025fc4818e69edbfdf385eb506aae8..9076f8868446350e978f55e7736d2b77fdb5c0d5 100644
--- a/src/test/java/org/olat/repository/manager/RepositoryEntryRelationDAOTest.java
+++ b/src/test/java/org/olat/repository/manager/RepositoryEntryRelationDAOTest.java
@@ -425,8 +425,8 @@ public class RepositoryEntryRelationDAOTest extends OlatTestCase {
 	}
 	
 	@Test
-	public void getRelations() {
-		Identity id = JunitTestHelper.createAndPersistIdentityAsUser("re-member-lc-" + UUID.randomUUID().toString());
+	public void getRelations_group() {
+		Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("re-member-lc-" );
 		RepositoryEntry re1 = JunitTestHelper.createAndPersistRepositoryEntry();
 		RepositoryEntry re2 = JunitTestHelper.createAndPersistRepositoryEntry();
 
@@ -444,6 +444,40 @@ public class RepositoryEntryRelationDAOTest extends OlatTestCase {
 		Assert.assertTrue(relations.get(1).getEntry().equals(re1) || relations.get(1).getEntry().equals(re2));
 	}
 	
+	@Test
+	public void getRelations_repositoryEntry() {
+		Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("re-member-lc-");
+		RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry();
+
+		BusinessGroup group = businessGroupService.createBusinessGroup(null, "get relations", "tg", null, null, false, false, re);
+	    businessGroupRelationDao.addRole(id, group, GroupRoles.coach.name());
+	    dbInstance.commitAndCloseSession();
+	    
+	    //get the relations from the business group's base group to the repository entry
+	    List<RepositoryEntryToGroupRelation> relations = repositoryEntryRelationDao.getRelations(re);
+	    Assert.assertNotNull(relations);
+	    Assert.assertEquals(3, relations.size());
+		Assert.assertTrue(relations.get(0).getEntry().equals(re));
+	}
+	
+	@Test
+	public void hasRelation() {
+		Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("re-member-lc-");
+		RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry();
+		RepositoryEntry reMarker = JunitTestHelper.createAndPersistRepositoryEntry();
+
+		BusinessGroup group = businessGroupService.createBusinessGroup(null, "get relations", "tg", null, null, false, false, re);
+	    businessGroupRelationDao.addRole(id, group, GroupRoles.coach.name());
+	    dbInstance.commitAndCloseSession();
+	    
+	    // The repository entry has a relation with the business group
+	    boolean hasRelation = repositoryEntryRelationDao.hasRelation(group.getBaseGroup(), re);
+		Assert.assertTrue(hasRelation);
+	    // The marker repository entry doesn't have a relation with the business group
+	    boolean hasNotRelation = repositoryEntryRelationDao.hasRelation(group.getBaseGroup(), reMarker);
+		Assert.assertFalse(hasNotRelation);
+	}
+	
 	@Test
 	public void getIdentitiesWithRole() {
 		Identity id1 = JunitTestHelper.createAndPersistIdentityAsRndUser("id-role-1-");
diff --git a/src/test/java/org/olat/restapi/CurriculumElementsWebServiceTest.java b/src/test/java/org/olat/restapi/CurriculumElementsWebServiceTest.java
index ada2e6ef5a0286282b13a91185f23898e1eb5494..466ea2acdfc2f939a810ec8af3ecacac6aa6bb9c 100644
--- a/src/test/java/org/olat/restapi/CurriculumElementsWebServiceTest.java
+++ b/src/test/java/org/olat/restapi/CurriculumElementsWebServiceTest.java
@@ -30,7 +30,9 @@ import java.util.List;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.UriBuilder;
 
+import org.apache.http.HttpEntity;
 import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpDelete;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.methods.HttpPut;
@@ -42,15 +44,23 @@ import org.junit.Assert;
 import org.junit.Test;
 import org.olat.basesecurity.OrganisationService;
 import org.olat.core.commons.persistence.DB;
+import org.olat.core.id.Identity;
 import org.olat.core.id.Organisation;
 import org.olat.modules.curriculum.Curriculum;
 import org.olat.modules.curriculum.CurriculumElement;
 import org.olat.modules.curriculum.CurriculumElementManagedFlag;
 import org.olat.modules.curriculum.CurriculumElementType;
+import org.olat.modules.curriculum.CurriculumRoles;
 import org.olat.modules.curriculum.CurriculumService;
+import org.olat.modules.curriculum.model.CurriculumElementMember;
 import org.olat.modules.curriculum.model.CurriculumElementRefImpl;
+import org.olat.modules.curriculum.restapi.CurriculumElementMemberVO;
 import org.olat.modules.curriculum.restapi.CurriculumElementVO;
+import org.olat.repository.RepositoryEntry;
+import org.olat.test.JunitTestHelper;
 import org.olat.test.OlatJerseyTestCase;
+import org.olat.user.restapi.UserVO;
+import org.olat.user.restapi.UserVOFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
@@ -84,8 +94,7 @@ public class CurriculumElementsWebServiceTest extends OlatJerseyTestCase {
 		HttpGet method = conn.createGet(request, MediaType.APPLICATION_JSON, true);
 		HttpResponse response = conn.execute(method);
 		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
-		InputStream body = response.getEntity().getContent();
-		List<CurriculumElementVO> elementVoes = parseCurriculumElementArray(body);
+		List<CurriculumElementVO> elementVoes = parseCurriculumElementArray(response.getEntity());
 		Assert.assertNotNull(elementVoes);
 		Assert.assertEquals(2, elementVoes.size());
 		
@@ -345,14 +354,505 @@ public class CurriculumElementsWebServiceTest extends OlatJerseyTestCase {
 	}
 	
 	
-	protected List<CurriculumElementVO> parseCurriculumElementArray(InputStream body) {
-		try {
+	@Test
+	public void addRepositoryEntryToCurriculumElement()
+	throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login("administrator", "openolat"));
+		
+		Organisation organisation = organisationService.createOrganisation("REST Parent Organisation 4", "REST-p-4-organisation", "", null, null);
+		Curriculum curriculum = curriculumService.createCurriculum("REST-Curriculum-elements", "REST Curriculum", "A curriculum accessible by REST API for elemets", organisation);
+		CurriculumElement element = curriculumService.createCurriculumElement("Element-11", "Element 11", null, null, null, null, curriculum);
+		dbInstance.commitAndCloseSession();
+
+		Identity author = JunitTestHelper.createAndPersistIdentityAsRndAuthor("rest-auth-1");
+		RepositoryEntry course = JunitTestHelper.createRandomRepositoryEntry(author);
+		dbInstance.commitAndCloseSession();
+
+		// add the relation
+		URI request = UriBuilder.fromUri(getContextURI()).path("curriculum").path(curriculum.getKey().toString())
+				.path("elements").path(element.getKey().toString()).path("entries").path(course.getKey().toString()).build();
+		HttpPut method = conn.createPut(request, MediaType.APPLICATION_JSON, true);
+		
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		EntityUtils.consume(response.getEntity());
+		
+		List<RepositoryEntry> entries = curriculumService.getRepositoryEntries(element);
+		Assert.assertNotNull(entries);
+		Assert.assertEquals(1, entries.size());
+		Assert.assertEquals(course, entries.get(0));
+	}
+	
+	@Test
+	public void removeRepositoryEntryFromCurriculumElement()
+	throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login("administrator", "openolat"));
+		
+		Organisation organisation = organisationService.createOrganisation("REST Parent Organisation 5", "REST-p-5-organisation", "", null, null);
+		Curriculum curriculum = curriculumService.createCurriculum("REST-Curriculum-elements", "REST Curriculum", "A curriculum accessible by REST API for elemets", organisation);
+		CurriculumElement element = curriculumService.createCurriculumElement("Element-12", "Element 12", null, null, null, null, curriculum);
+		dbInstance.commit();
+
+		Identity author = JunitTestHelper.createAndPersistIdentityAsRndAuthor("rest-auth-2");
+		RepositoryEntry entry = JunitTestHelper.createRandomRepositoryEntry(author);
+		dbInstance.commit();
+		
+		curriculumService.addRepositoryEntry(element, entry, false);
+		dbInstance.commitAndCloseSession();
+		
+		List<RepositoryEntry> entries = curriculumService.getRepositoryEntries(element);
+		Assert.assertEquals(1, entries.size());
+		
+
+		//try to delete the relation
+		URI request = UriBuilder.fromUri(getContextURI()).path("curriculum").path(curriculum.getKey().toString())
+				.path("elements").path(element.getKey().toString()).path("entries").path(entry.getKey().toString()).build();
+		HttpDelete method = conn.createDelete(request, MediaType.APPLICATION_JSON);
+		
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		EntityUtils.consume(response.getEntity());
+		
+		List<RepositoryEntry> deletedRelations = curriculumService.getRepositoryEntries(element);
+		Assert.assertNotNull(deletedRelations);
+		Assert.assertTrue(deletedRelations.isEmpty());
+	}
+	
+	@Test
+	public void getMemberships()
+	throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login("administrator", "openolat"));
+		
+		Identity member = JunitTestHelper.createAndPersistIdentityAsRndUser("element-member-1");
+		Organisation organisation = organisationService.createOrganisation("REST Parent Organisation 5", "REST-p-5-organisation", "", null, null);
+		Curriculum curriculum = curriculumService.createCurriculum("REST-Curriculum-elements", "REST Curriculum", "A curriculum accessible by REST API for elemets", organisation);
+		CurriculumElement element = curriculumService.createCurriculumElement("Element-12", "Element 12", null, null, null, null, curriculum);
+		dbInstance.commit();
+		
+		curriculumService.addMember(element, member, CurriculumRoles.participant);
+		dbInstance.commitAndCloseSession();
+		
+		URI request = UriBuilder.fromUri(getContextURI()).path("curriculum").path(curriculum.getKey().toString())
+				.path("elements").path(element.getKey().toString()).path("members").build();
+		HttpGet method = conn.createGet(request, MediaType.APPLICATION_JSON, true);
+		
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		List<CurriculumElementMemberVO> memberVoes = parseCurriculumElementMemberArray(response.getEntity());
+		
+		Assert.assertNotNull(memberVoes);
+		Assert.assertEquals(1, memberVoes.size());
+		Assert.assertEquals(member.getKey(), memberVoes.get(0).getIdentityKey());
+		Assert.assertEquals("participant", memberVoes.get(0).getRole());
+	}
+	
+	@Test
+	public void getUsers()
+	throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login("administrator", "openolat"));
+		
+		Identity member = JunitTestHelper.createAndPersistIdentityAsRndUser("element-member-6");
+		Organisation organisation = organisationService.createOrganisation("REST Parent Organisation 8", "REST-p-8-organisation", "", null, null);
+		Curriculum curriculum = curriculumService.createCurriculum("REST-Curriculum-elements", "REST Curriculum", "A curriculum accessible by REST API for elemets", organisation);
+		CurriculumElement element = curriculumService.createCurriculumElement("Element-14", "Element 14", null, null, null, null, curriculum);
+		dbInstance.commit();
+		
+		curriculumService.addMember(element, member, CurriculumRoles.participant);
+		dbInstance.commitAndCloseSession();
+		
+		URI request = UriBuilder.fromUri(getContextURI()).path("curriculum").path(curriculum.getKey().toString())
+				.path("elements").path(element.getKey().toString()).path("users").queryParam("role", "participant").build();
+		HttpGet method = conn.createGet(request, MediaType.APPLICATION_JSON, true);
+		
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		List<UserVO> memberVoes = parseUserArray(response.getEntity());
+		
+		Assert.assertNotNull(memberVoes);
+		Assert.assertEquals(1, memberVoes.size());
+		Assert.assertEquals(member.getKey(), memberVoes.get(0).getKey());
+	}
+	
+	@Test
+	public void getUsers_curriculumManagers()
+	throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login("administrator", "openolat"));
+		
+		Identity member = JunitTestHelper.createAndPersistIdentityAsRndUser("element-member-6");
+		Organisation organisation = organisationService.createOrganisation("REST Parent Organisation 8", "REST-p-8-organisation", "", null, null);
+		Curriculum curriculum = curriculumService.createCurriculum("REST-Curriculum-elements", "REST Curriculum", "A curriculum accessible by REST API for elemets", organisation);
+		CurriculumElement element = curriculumService.createCurriculumElement("Element-14", "Element 14", null, null, null, null, curriculum);
+		dbInstance.commit();
+		
+		curriculumService.addMember(element, member, CurriculumRoles.curriculummanager);
+		dbInstance.commitAndCloseSession();
+		
+		URI request = UriBuilder.fromUri(getContextURI()).path("curriculum").path(curriculum.getKey().toString())
+				.path("elements").path(element.getKey().toString()).path("users").queryParam("role", "curriculummanager").build();
+		HttpGet method = conn.createGet(request, MediaType.APPLICATION_JSON, true);
+		
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		List<UserVO> memberVoes = parseUserArray(response.getEntity());
+		
+		Assert.assertNotNull(memberVoes);
+		Assert.assertEquals(1, memberVoes.size());
+		Assert.assertEquals(member.getKey(), memberVoes.get(0).getKey());
+	}
+	
+	@Test
+	public void getParticipants()
+	throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login("administrator", "openolat"));
+		
+		Identity member = JunitTestHelper.createAndPersistIdentityAsRndUser("element-member-7");
+		Organisation organisation = organisationService.createOrganisation("REST Parent Organisation 9", "REST-p-9-organisation", "", null, null);
+		Curriculum curriculum = curriculumService.createCurriculum("REST-Curriculum-elements", "REST Curriculum", "A curriculum accessible by REST API for elemets", organisation);
+		CurriculumElement element = curriculumService.createCurriculumElement("Element-15", "Element 15", null, null, null, null, curriculum);
+		dbInstance.commit();
+		
+		curriculumService.addMember(element, member, CurriculumRoles.participant);
+		dbInstance.commitAndCloseSession();
+		
+		URI request = UriBuilder.fromUri(getContextURI()).path("curriculum").path(curriculum.getKey().toString())
+				.path("elements").path(element.getKey().toString()).path("participants").build();
+		HttpGet method = conn.createGet(request, MediaType.APPLICATION_JSON, true);
+		
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		List<UserVO> memberVoes = parseUserArray(response.getEntity());
+		
+		Assert.assertNotNull(memberVoes);
+		Assert.assertEquals(1, memberVoes.size());
+		Assert.assertEquals(member.getKey(), memberVoes.get(0).getKey());
+	}
+	
+	@Test
+	public void getCoaches()
+	throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login("administrator", "openolat"));
+		
+		Identity member = JunitTestHelper.createAndPersistIdentityAsRndUser("element-member-10");
+		Organisation organisation = organisationService.createOrganisation("REST Parent Organisation 10", "REST-p-10-organisation", "", null, null);
+		Curriculum curriculum = curriculumService.createCurriculum("REST-Curriculum-elements", "REST Curriculum", "A curriculum accessible by REST API for elemets", organisation);
+		CurriculumElement element = curriculumService.createCurriculumElement("Element-16", "Element 16", null, null, null, null, curriculum);
+		dbInstance.commit();
+		
+		curriculumService.addMember(element, member, CurriculumRoles.coach);
+		dbInstance.commitAndCloseSession();
+		
+		URI request = UriBuilder.fromUri(getContextURI()).path("curriculum").path(curriculum.getKey().toString())
+				.path("elements").path(element.getKey().toString()).path("coaches").build();
+		HttpGet method = conn.createGet(request, MediaType.APPLICATION_JSON, true);
+		
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		List<UserVO> memberVoes = parseUserArray(response.getEntity());
+		
+		Assert.assertNotNull(memberVoes);
+		Assert.assertEquals(1, memberVoes.size());
+		Assert.assertEquals(member.getKey(), memberVoes.get(0).getKey());
+	}
+	
+	@Test
+	public void getCurriculumManagers()
+	throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login("administrator", "openolat"));
+		
+		Identity member = JunitTestHelper.createAndPersistIdentityAsRndUser("element-member-10");
+		Organisation organisation = organisationService.createOrganisation("REST Parent Organisation 10", "REST-p-10-organisation", "", null, null);
+		Curriculum curriculum = curriculumService.createCurriculum("REST-Curriculum-elements", "REST Curriculum", "A curriculum accessible by REST API for elemets", organisation);
+		CurriculumElement element = curriculumService.createCurriculumElement("Element-16", "Element 16", null, null, null, null, curriculum);
+		dbInstance.commit();
+		
+		curriculumService.addMember(element, member, CurriculumRoles.curriculummanager);
+		dbInstance.commitAndCloseSession();
+		
+		URI request = UriBuilder.fromUri(getContextURI()).path("curriculum").path(curriculum.getKey().toString())
+				.path("elements").path(element.getKey().toString()).path("curriculummanagers").build();
+		HttpGet method = conn.createGet(request, MediaType.APPLICATION_JSON, true);
+		
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		List<UserVO> memberVoes = parseUserArray(response.getEntity());
+		
+		Assert.assertNotNull(memberVoes);
+		Assert.assertEquals(1, memberVoes.size());
+		Assert.assertEquals(member.getKey(), memberVoes.get(0).getKey());
+	}
+	
+	@Test
+	public void addMembership()
+	throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login("administrator", "openolat"));
+		
+		Identity member = JunitTestHelper.createAndPersistIdentityAsRndUser("element-member-1");
+		Organisation organisation = organisationService.createOrganisation("REST Parent Organisation 5", "REST-p-5-organisation", "", null, null);
+		Curriculum curriculum = curriculumService.createCurriculum("REST-Curriculum-elements", "REST Curriculum", "A curriculum accessible by REST API for elemets", organisation);
+		CurriculumElement element = curriculumService.createCurriculumElement("Element-12", "Element 12", null, null, null, null, curriculum);
+		dbInstance.commit();
+		
+		CurriculumElementMemberVO membershipVo = new CurriculumElementMemberVO();
+		membershipVo.setIdentityKey(member.getKey());
+		membershipVo.setRole("participant");
+		membershipVo.setInheritanceMode("none");
+		
+		URI request = UriBuilder.fromUri(getContextURI()).path("curriculum").path(curriculum.getKey().toString())
+				.path("elements").path(element.getKey().toString()).path("members").build();
+		HttpPut method = conn.createPut(request, MediaType.APPLICATION_JSON, true);
+		conn.addJsonEntity(method, membershipVo);
+		
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		EntityUtils.consume(response.getEntity());
+		
+		List<CurriculumElementMember> members = curriculumService.getMembers(element);
+		Assert.assertNotNull(members);
+		Assert.assertEquals(1, members.size());
+		Assert.assertEquals(member, members.get(0).getIdentity());
+		Assert.assertEquals("participant", members.get(0).getRole());
+	}
+	
+	@Test
+	public void addParticipant()
+	throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login("administrator", "openolat"));
+		
+		Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("element-member-11");
+		Organisation organisation = organisationService.createOrganisation("REST Parent Organisation 11", "REST-p-11-organisation", "", null, null);
+		Curriculum curriculum = curriculumService.createCurriculum("REST-Curriculum-elements", "REST Curriculum", "A curriculum accessible by REST API for elemets", organisation);
+		CurriculumElement element = curriculumService.createCurriculumElement("Element-17", "Element 17", null, null, null, null, curriculum);
+		dbInstance.commit();
+		
+		URI request = UriBuilder.fromUri(getContextURI()).path("curriculum").path(curriculum.getKey().toString())
+				.path("elements").path(element.getKey().toString()).path("participants").path(participant.getKey().toString()).build();
+		HttpPut method = conn.createPut(request, MediaType.APPLICATION_JSON, true);
+		
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		EntityUtils.consume(response.getEntity());
+		
+		List<Identity> participants = curriculumService.getMembersIdentity(element, CurriculumRoles.participant);
+		Assert.assertNotNull(participants);
+		Assert.assertEquals(1, participants.size());
+		Assert.assertEquals(participant, participants.get(0));
+	}
+	
+	@Test
+	public void addCoach()
+	throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login("administrator", "openolat"));
+		
+		Identity coach = JunitTestHelper.createAndPersistIdentityAsRndUser("element-member-12");
+		Organisation organisation = organisationService.createOrganisation("REST Parent Organisation 12", "REST-p-12-organisation", "", null, null);
+		Curriculum curriculum = curriculumService.createCurriculum("REST-Curriculum-elements", "REST Curriculum", "A curriculum accessible by REST API for elemets", organisation);
+		CurriculumElement element = curriculumService.createCurriculumElement("Element-18", "Element 18", null, null, null, null, curriculum);
+		dbInstance.commit();
+		
+		URI request = UriBuilder.fromUri(getContextURI()).path("curriculum").path(curriculum.getKey().toString())
+				.path("elements").path(element.getKey().toString()).path("coaches").path(coach.getKey().toString()).build();
+		HttpPut method = conn.createPut(request, MediaType.APPLICATION_JSON, true);
+		
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		EntityUtils.consume(response.getEntity());
+		
+		List<Identity> coaches = curriculumService.getMembersIdentity(element, CurriculumRoles.coach);
+		Assert.assertNotNull(coaches);
+		Assert.assertEquals(1, coaches.size());
+		Assert.assertEquals(coach, coaches.get(0));
+	}
+	
+	@Test
+	public void addParticipants()
+	throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login("administrator", "openolat"));
+		
+		Identity participant1 = JunitTestHelper.createAndPersistIdentityAsRndUser("element-member-13");
+		Identity participant2 = JunitTestHelper.createAndPersistIdentityAsRndUser("element-member-14");
+		Organisation organisation = organisationService.createOrganisation("REST Parent Organisation 13", "REST-p-13-organisation", "", null, null);
+		Curriculum curriculum = curriculumService.createCurriculum("REST-Curriculum-elements", "REST Curriculum", "A curriculum accessible by REST API for elemets", organisation);
+		CurriculumElement element = curriculumService.createCurriculumElement("Element-18", "Element 18", null, null, null, null, curriculum);
+		dbInstance.commit();
+		
+		UserVO[] participants = new UserVO[] {
+			UserVOFactory.get(participant1),
+			UserVOFactory.get(participant2)
+		};
+		URI request = UriBuilder.fromUri(getContextURI()).path("curriculum").path(curriculum.getKey().toString())
+				.path("elements").path(element.getKey().toString()).path("participants").build();
+		HttpPut method = conn.createPut(request, MediaType.APPLICATION_JSON, true);
+		conn.addJsonEntity(method, participants);
+		
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		EntityUtils.consume(response.getEntity());
+		
+		List<Identity> participantList = curriculumService.getMembersIdentity(element, CurriculumRoles.participant);
+		Assert.assertNotNull(participantList);
+		Assert.assertEquals(2, participantList.size());
+	}
+	
+	@Test
+	public void addCoaches()
+	throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login("administrator", "openolat"));
+		
+		Identity coach1 = JunitTestHelper.createAndPersistIdentityAsRndUser("element-member-15");
+		Identity coach2 = JunitTestHelper.createAndPersistIdentityAsRndUser("element-member-16");
+		Organisation organisation = organisationService.createOrganisation("REST Parent Organisation 16", "REST-p-16-organisation", "", null, null);
+		Curriculum curriculum = curriculumService.createCurriculum("REST-Curriculum-elements", "REST Curriculum", "A curriculum accessible by REST API for elemets", organisation);
+		CurriculumElement element = curriculumService.createCurriculumElement("Element-20", "Element 20", null, null, null, null, curriculum);
+		dbInstance.commit();
+		
+		UserVO[] coaches = new UserVO[] {
+			UserVOFactory.get(coach1),
+			UserVOFactory.get(coach2)
+		};
+		URI request = UriBuilder.fromUri(getContextURI()).path("curriculum").path(curriculum.getKey().toString())
+				.path("elements").path(element.getKey().toString()).path("coaches").build();
+		HttpPut method = conn.createPut(request, MediaType.APPLICATION_JSON, true);
+		conn.addJsonEntity(method, coaches);
+		
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		EntityUtils.consume(response.getEntity());
+		
+		List<Identity> coachList = curriculumService.getMembersIdentity(element, CurriculumRoles.coach);
+		Assert.assertNotNull(coachList);
+		Assert.assertEquals(2, coachList.size());
+	}
+	
+	@Test
+	public void removeMembership()
+	throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login("administrator", "openolat"));
+		
+		Identity member = JunitTestHelper.createAndPersistIdentityAsRndUser("element-member-1");
+		Organisation organisation = organisationService.createOrganisation("REST Parent Organisation 5", "REST-p-5-organisation", "", null, null);
+		Curriculum curriculum = curriculumService.createCurriculum("REST-Curriculum-elements", "REST Curriculum", "A curriculum accessible by REST API for elemets", organisation);
+		CurriculumElement element = curriculumService.createCurriculumElement("Element-12", "Element 12", null, null, null, null, curriculum);
+		dbInstance.commit();
+		
+		curriculumService.addMember(element, member, CurriculumRoles.participant);
+		dbInstance.commitAndCloseSession();
+
+		URI request = UriBuilder.fromUri(getContextURI()).path("curriculum").path(curriculum.getKey().toString())
+				.path("elements").path(element.getKey().toString()).path("members").path(member.getKey().toString()).build();
+		HttpDelete method = conn.createDelete(request, MediaType.APPLICATION_JSON);
+		
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		EntityUtils.consume(response.getEntity());
+		
+		List<CurriculumElementMember> members = curriculumService.getMembers(element);
+		Assert.assertNotNull(members);
+		Assert.assertTrue(members.isEmpty());
+	}
+	
+	@Test
+	public void removeParticipant()
+	throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login("administrator", "openolat"));
+		
+		Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("element-member-21");
+		Identity coach = JunitTestHelper.createAndPersistIdentityAsRndUser("element-member-22");
+		Organisation organisation = organisationService.createOrganisation("REST Parent Organisation 21", "REST-p-21-organisation", "", null, null);
+		Curriculum curriculum = curriculumService.createCurriculum("REST-Curriculum-elements", "REST Curriculum", "A curriculum accessible by REST API for elemets", organisation);
+		CurriculumElement element = curriculumService.createCurriculumElement("Element-21", "Element 21", null, null, null, null, curriculum);
+		dbInstance.commit();
+		
+		curriculumService.addMember(element, participant, CurriculumRoles.participant);
+		curriculumService.addMember(element, coach, CurriculumRoles.coach);
+		dbInstance.commitAndCloseSession();
+
+		URI request = UriBuilder.fromUri(getContextURI()).path("curriculum").path(curriculum.getKey().toString())
+				.path("elements").path(element.getKey().toString()).path("participants").path(participant.getKey().toString()).build();
+		HttpDelete method = conn.createDelete(request, MediaType.APPLICATION_JSON);
+		
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		EntityUtils.consume(response.getEntity());
+		
+		List<Identity> participants = curriculumService.getMembersIdentity(element, CurriculumRoles.participant);
+		Assert.assertTrue(participants.isEmpty());
+		List<Identity> coaches = curriculumService.getMembersIdentity(element, CurriculumRoles.coach);
+		Assert.assertEquals(1, coaches.size());
+	}
+	
+	@Test
+	public void removeCoach()
+	throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login("administrator", "openolat"));
+		
+		Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("element-member-23");
+		Identity coach = JunitTestHelper.createAndPersistIdentityAsRndUser("element-member-24");
+		Organisation organisation = organisationService.createOrganisation("REST Parent Organisation 24", "REST-p-24-organisation", "", null, null);
+		Curriculum curriculum = curriculumService.createCurriculum("REST-Curriculum-elements", "REST Curriculum", "A curriculum accessible by REST API for elemets", organisation);
+		CurriculumElement element = curriculumService.createCurriculumElement("Element-24", "Element 24", null, null, null, null, curriculum);
+		dbInstance.commit();
+		
+		curriculumService.addMember(element, participant, CurriculumRoles.participant);
+		curriculumService.addMember(element, coach, CurriculumRoles.coach);
+		dbInstance.commitAndCloseSession();
+
+		URI request = UriBuilder.fromUri(getContextURI()).path("curriculum").path(curriculum.getKey().toString())
+				.path("elements").path(element.getKey().toString()).path("coaches").path(coach.getKey().toString()).build();
+		HttpDelete method = conn.createDelete(request, MediaType.APPLICATION_JSON);
+		
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		EntityUtils.consume(response.getEntity());
+		
+		List<Identity> coaches = curriculumService.getMembersIdentity(element, CurriculumRoles.coach);
+		Assert.assertTrue(coaches.isEmpty());
+		List<Identity> participants = curriculumService.getMembersIdentity(element, CurriculumRoles.participant);
+		Assert.assertEquals(1, participants.size());
+	}
+	
+	protected List<UserVO> parseUserArray(HttpEntity body) {
+		try(InputStream in = body.getContent()) {
 			ObjectMapper mapper = new ObjectMapper(jsonFactory); 
-			return mapper.readValue(body, new TypeReference<List<CurriculumElementVO>>(){/* */});
+			return mapper.readValue(in, new TypeReference<List<UserVO>>(){/* */});
+		} catch (Exception e) {
+			e.printStackTrace();
+			return null;
+		}
+	}
+	
+	protected List<CurriculumElementVO> parseCurriculumElementArray(HttpEntity body) {
+		try(InputStream in = body.getContent()) {
+			ObjectMapper mapper = new ObjectMapper(jsonFactory); 
+			return mapper.readValue(in, new TypeReference<List<CurriculumElementVO>>(){/* */});
+		} catch (Exception e) {
+			e.printStackTrace();
+			return null;
+		}
+	}
+	
+	protected List<CurriculumElementMemberVO> parseCurriculumElementMemberArray(HttpEntity body) {
+		try(InputStream in = body.getContent()) {
+			ObjectMapper mapper = new ObjectMapper(jsonFactory); 
+			return mapper.readValue(in, new TypeReference<List<CurriculumElementMemberVO>>(){/* */});
 		} catch (Exception e) {
 			e.printStackTrace();
 			return null;
 		}
 	}
-
 }
diff --git a/src/test/java/org/olat/restapi/OrganisationsWebServiceTest.java b/src/test/java/org/olat/restapi/OrganisationsWebServiceTest.java
index 16de3bb799f79a16c3be813a100a45d576e8acb5..b147fe14ab83d215fb7bc4bb937272debdaafac5 100644
--- a/src/test/java/org/olat/restapi/OrganisationsWebServiceTest.java
+++ b/src/test/java/org/olat/restapi/OrganisationsWebServiceTest.java
@@ -30,23 +30,31 @@ import java.util.List;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.UriBuilder;
 
+import org.apache.http.HttpEntity;
 import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpDelete;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.methods.HttpPut;
+import org.apache.http.util.EntityUtils;
 import org.codehaus.jackson.map.ObjectMapper;
 import org.codehaus.jackson.type.TypeReference;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Test;
 import org.olat.basesecurity.OrganisationManagedFlag;
+import org.olat.basesecurity.OrganisationRoles;
 import org.olat.basesecurity.OrganisationService;
 import org.olat.basesecurity.OrganisationType;
 import org.olat.basesecurity.model.OrganisationRefImpl;
 import org.olat.core.commons.persistence.DB;
+import org.olat.core.id.Identity;
 import org.olat.core.id.Organisation;
+import org.olat.test.JunitTestHelper;
 import org.olat.test.OlatJerseyTestCase;
 import org.olat.user.restapi.OrganisationVO;
+import org.olat.user.restapi.UserVO;
+import org.olat.user.restapi.UserVOFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
@@ -304,7 +312,117 @@ public class OrganisationsWebServiceTest extends OlatJerseyTestCase {
 		Assert.assertEquals(parentOrganisation, savedOrganisation.getRoot());
 	}
 	
+	@Test
+	public void getMembers_users()
+	throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login("administrator", "openolat"));
+		
+		Identity member = JunitTestHelper.createAndPersistIdentityAsRndUser("org-member-11");
+		Organisation organisation = organisationService.createOrganisation("REST Organisation 5", "REST-p-5-organisation", "", null, null);
+		organisationService.addMember(organisation, member, OrganisationRoles.user);
+		dbInstance.commit();
+		
+		URI request = UriBuilder.fromUri(getContextURI()).path("organisations").path(organisation.getKey().toString())
+				.path("users").build();
+		HttpGet method = conn.createGet(request, MediaType.APPLICATION_JSON, true);
+		
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		List<UserVO> users = parseUserArray(response.getEntity());
+		Assert.assertNotNull(users);
+		Assert.assertEquals(1, users.size());
+		Assert.assertEquals(member.getKey(), users.get(0).getKey());
+	}
 	
+	@Test
+	public void addMember_principal()
+	throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login("administrator", "openolat"));
+		
+		Identity member = JunitTestHelper.createAndPersistIdentityAsRndUser("org-member-12");
+		Organisation organisation = organisationService.createOrganisation("REST Organisation 6", "REST-p-6-organisation", "", null, null);
+		dbInstance.commit();
+		
+		URI request = UriBuilder.fromUri(getContextURI()).path("organisations").path(organisation.getKey().toString())
+				.path("principals").path(member.getKey().toString()).build();
+		HttpPut method = conn.createPut(request, MediaType.APPLICATION_JSON, true);
+		
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		EntityUtils.consume(response.getEntity());
+		
+		List<Identity> principals = organisationService.getMembersIdentity(organisation, OrganisationRoles.principal);
+		Assert.assertNotNull(principals);
+		Assert.assertEquals(1, principals.size());
+		Assert.assertEquals(member, principals.get(0));
+	}
+	
+	@Test
+	public void addMembers_author()
+	throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login("administrator", "openolat"));
+		
+		Identity author1 = JunitTestHelper.createAndPersistIdentityAsRndUser("org-member-14");
+		Identity author2 = JunitTestHelper.createAndPersistIdentityAsRndUser("org-member-15");
+		Organisation organisation = organisationService.createOrganisation("REST Organisation 7", "REST-p-7-organisation", "", null, null);
+		dbInstance.commit();
+		
+		
+		UserVO[] authors = new UserVO[] {
+				UserVOFactory.get(author1),
+				UserVOFactory.get(author2)
+			};
+		URI request = UriBuilder.fromUri(getContextURI()).path("organisations").path(organisation.getKey().toString())
+				.path("authors").build();
+		HttpPut method = conn.createPut(request, MediaType.APPLICATION_JSON, true);
+		conn.addJsonEntity(method, authors);
+		
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		EntityUtils.consume(response.getEntity());
+		
+		List<Identity> authorList = organisationService.getMembersIdentity(organisation, OrganisationRoles.author);
+		Assert.assertNotNull(authorList);
+		Assert.assertEquals(2, authorList.size());
+	}
+	
+	
+	@Test
+	public void removeMember_administrator()
+	throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login("administrator", "openolat"));
+		
+		Identity member = JunitTestHelper.createAndPersistIdentityAsRndUser("org-member-13");
+		Organisation organisation = organisationService.createOrganisation("REST Organisation 7", "REST-p-7-organisation", "", null, null);
+		organisationService.addMember(organisation, member, OrganisationRoles.administrator);
+		dbInstance.commit();
+		
+		URI request = UriBuilder.fromUri(getContextURI()).path("organisations").path(organisation.getKey().toString())
+				.path("administrators").path(member.getKey().toString()).build();
+		HttpDelete method = conn.createDelete(request, MediaType.APPLICATION_JSON);
+		
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		EntityUtils.consume(response.getEntity());
+		
+		List<Identity> administators = organisationService.getMembersIdentity(organisation, OrganisationRoles.administrator);
+		Assert.assertNotNull(administators);
+		Assert.assertTrue(administators.isEmpty());
+	}
+	
+	protected List<UserVO> parseUserArray(HttpEntity entity) {
+		try(InputStream in=entity.getContent()) {
+			ObjectMapper mapper = new ObjectMapper(jsonFactory); 
+			return mapper.readValue(in, new TypeReference<List<UserVO>>(){/* */});
+		} catch (Exception e) {
+			e.printStackTrace();
+			return null;
+		}
+	}
 	
 	protected List<OrganisationVO> parseOrganisationArray(InputStream body) {
 		try {