/**
* OLAT - Online Learning and Training<br>
* http://www.olat.org
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <hr>
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* This file has been modified by the OpenOLAT community. Changes are licensed
* under the Apache 2.0 license as the original file.
*/
package org.olat.course.nodes.projectbroker.service;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import org.hibernate.type.StandardBasicTypes;
import org.olat.basesecurity.BaseSecurity;
import org.olat.basesecurity.GroupRoles;
import org.olat.basesecurity.SecurityGroup;
import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl;
import org.olat.core.commons.persistence.DB;
import org.olat.core.id.Identity;
import org.olat.core.id.OLATResourceable;
import org.olat.core.manager.BasicManager;
import org.olat.core.util.FileUtils;
import org.olat.core.util.cache.CacheWrapper;
import org.olat.core.util.coordinate.CoordinatorManager;
import org.olat.core.util.coordinate.SyncerCallback;
import org.olat.core.util.coordinate.SyncerExecutor;
import org.olat.core.util.resource.OresHelper;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSItem;
import org.olat.core.util.vfs.VFSLeaf;
import org.olat.course.nodes.CourseNode;
import org.olat.course.nodes.ProjectBrokerCourseNode;
import org.olat.course.nodes.projectbroker.ProjectBrokerDropboxController;
import org.olat.course.nodes.projectbroker.ProjectBrokerReturnboxController;
import org.olat.course.nodes.projectbroker.datamodel.Project;
import org.olat.course.nodes.projectbroker.datamodel.Project.EventType;
import org.olat.course.nodes.projectbroker.datamodel.ProjectBroker;
import org.olat.course.nodes.projectbroker.datamodel.ProjectBrokerImpl;
import org.olat.course.nodes.projectbroker.datamodel.ProjectEvent;
import org.olat.course.nodes.projectbroker.datamodel.ProjectImpl;
import org.olat.course.properties.CoursePropertyManager;
import org.olat.course.run.environment.CourseEnvironment;
import org.olat.group.BusinessGroup;
import org.olat.group.BusinessGroupService;
import org.olat.group.manager.BusinessGroupRelationDAO;
import org.olat.properties.Property;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
*
* @author guretzki
*/
@Service
public class ProjectBrokerManagerImpl extends BasicManager implements ProjectBrokerManager {
@Autowired
private DB dbInstance;
@Autowired
private BaseSecurity securityManager;
@Autowired
private ProjectGroupManager projectGroupManager;
@Autowired
private BusinessGroupService businessGroupService;
@Autowired
private BusinessGroupRelationDAO businessGroupRelationDao;
private static final String ATTACHEMENT_DIR_NAME = "projectbroker_attach";
private CacheWrapper<String,ProjectBroker> projectCache;
protected ProjectBrokerManagerImpl() {
// cache name should not be too long e.g. 'projectbroker' is too long, use 'pb' instead.
projectCache = CoordinatorManager.getInstance().getCoordinator().getCacher().getCache(ProjectBrokerManager.class.getSimpleName(), "pb");
}
/**
* @param projectbroker_id
* @return List of projects for certain project-broker
*/
public List<Project> getProjectListBy(final Long projectBrokerId) {
final boolean debug = isLogDebugEnabled();
long rstart = 0;
if(debug){
logDebug("getProjectListBy for projectBroker=" + projectBrokerId);
rstart = System.currentTimeMillis();
}
OLATResourceable projectBrokerOres = OresHelper.createOLATResourceableInstance(this.getClass(),projectBrokerId);
List<Project> projectList = CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync( projectBrokerOres, new SyncerCallback<List<Project>>() {
public List<Project> execute() {
ProjectBroker projectBroker = getOrLoadProjectBoker(projectBrokerId);
return projectBroker.getProjects();
}
});
if(debug){
long rstop = System.currentTimeMillis();
logDebug("time to fetch project with projectbroker_id " + projectBrokerId + " :" + (rstop - rstart), null);
}
return projectList;
}
public ProjectBroker createAndSaveProjectBroker() {
ProjectBroker projectBroker = new ProjectBrokerImpl();
dbInstance.saveObject(projectBroker);
return projectBroker;
}
public Project createAndSaveProjectFor(String title, String description, final Long projectBrokerId, BusinessGroup projectGroup) {
OLATResourceable projectBrokerOres = OresHelper.createOLATResourceableInstance(this.getClass(),projectBrokerId);
final Project project = new ProjectImpl(title, description, projectGroup, getProjectBroker(projectBrokerId));
CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync( projectBrokerOres, new SyncerExecutor() {
public void execute() {
dbInstance.saveObject(project);
ProjectBroker projectBroker = getOrLoadProjectBoker(projectBrokerId);
if(!projectBroker.getProjects().contains(project)) {
projectBroker.getProjects().add(project);
}
projectCache.update(projectBrokerId.toString(), projectBroker);
}
});
return project;
}
@Override
public void updateProject(final Project project) {
final Long projectBrokerId = project.getProjectBroker().getKey();
OLATResourceable projectBrokerOres = OresHelper.createOLATResourceableInstance(this.getClass(),projectBrokerId);
CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync( projectBrokerOres, new SyncerExecutor() {
@Override
public void execute() {
updateProjectAndInvalidateCache(project);
}
});
}
@Override
public boolean existsProject(Long projectKey) {
return dbInstance.findObject(ProjectImpl.class, projectKey) != null;
}
@Override
public boolean enrollProjectParticipant(final Identity identity, final Project project, final ProjectBrokerModuleConfiguration moduleConfig, final int nbrSelectedProjects, final boolean isParticipantInAnyProject) {
final boolean debug = isLogDebugEnabled();
OLATResourceable projectOres = OresHelper.createOLATResourceableInstance(Project.class, project.getKey());
logDebug("enrollProjectParticipant: start identity=" + identity + " project=" + project);
Boolean result = CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(projectOres, new SyncerCallback<Boolean>() {
@Override
public Boolean execute() {
if ( existsProject( project.getKey() ) ) {
// For cluster-safe : reload project object here another node might have changed this in the meantime
Project reloadedProject = (Project) dbInstance.loadObject(project, true);
if(debug) {
logDebug("enrollProjectParticipant: project.getMaxMembers()=" + reloadedProject.getMaxMembers());
logDebug("enrollProjectParticipant: project.getSelectedPlaces()=" + reloadedProject.getSelectedPlaces());
}
if (canBeProjectSelectedBy(identity, reloadedProject, moduleConfig, nbrSelectedProjects, isParticipantInAnyProject) ) {
if (moduleConfig.isAcceptSelectionManually() ) {
securityManager.addIdentityToSecurityGroup(identity, reloadedProject.getCandidateGroup());
logAudit("ProjectBroker: Add as candidate identity=" + identity + " to project=" + reloadedProject);
if (debug) {
logDebug("ProjectBroker: Add as candidate reloadedProject=" + reloadedProject + " CandidateGroup=" + reloadedProject.getCandidateGroup() );
}
} else {
businessGroupRelationDao.addRole(identity, reloadedProject.getProjectGroup(), GroupRoles.participant.name());
logAudit("ProjectBroker: Add as participant identity=" + identity + " to project=" + reloadedProject);
if (debug) {
logDebug("ProjectBroker: Add as participant reloadedProject=" + reloadedProject + " ParticipantGroup=" + reloadedProject.getProjectGroup() );
}
if ( (reloadedProject.getMaxMembers() != Project.MAX_MEMBERS_UNLIMITED) && (reloadedProject.getSelectedPlaces() >= reloadedProject.getMaxMembers()) ) {
reloadedProject.setState(Project.STATE_ASSIGNED);
updateProjectAndInvalidateCache(reloadedProject);
}
}
return Boolean.TRUE;
} else {
if(debug) {
logDebug("ProjectBroker: project-group was full for identity=" + identity + " , project=" + reloadedProject);
}
return Boolean.FALSE;
}
} else {
// project no longer exist
return Boolean.FALSE;
}
}
});// end of doInSync
return result.booleanValue();
}
public boolean cancelProjectEnrollmentOf(final Identity identity, final Project project, final ProjectBrokerModuleConfiguration moduleConfig) {
OLATResourceable projectOres = OresHelper.createOLATResourceableInstance(Project.class, project.getKey());
Boolean result = CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(projectOres, new SyncerCallback<Boolean>(){
public Boolean execute() {
if ( existsProject( project.getKey() ) ) {
// For cluster-safe : reload project object here another node might have changed this in the meantime
Project reloadedProject = (Project) dbInstance.loadObject(project, true);
// User can only cancel enrollment, when state is 'NOT_ASSIGNED'
if (canBeCancelEnrollmentBy(identity, project, moduleConfig)) {
businessGroupRelationDao.removeRole(identity, reloadedProject.getProjectGroup(), GroupRoles.participant.name());
securityManager.removeIdentityFromSecurityGroup(identity, reloadedProject.getCandidateGroup());
logAudit("ProjectBroker: Remove (as participant or waitinglist) identity=" + identity + " from project=" + project);
if (isLogDebugEnabled()) {
logDebug("ProjectBroker: Remove as participant reloadedProject=" + reloadedProject + " ParticipantGroup=" + reloadedProject.getProjectGroup() + " CandidateGroup=" + reloadedProject.getCandidateGroup());
}
if ( (reloadedProject.getMaxMembers() != Project.MAX_MEMBERS_UNLIMITED) && (reloadedProject.getSelectedPlaces() < reloadedProject.getMaxMembers()) ) {
reloadedProject.setState(Project.STATE_NOT_ASSIGNED);
updateProjectAndInvalidateCache(reloadedProject);
}
return Boolean.TRUE;
} else {
return Boolean.FALSE;
}
} else {
// project no longer exist
return Boolean.FALSE;
}
}
});// end of doInSync
return result.booleanValue();
}
/**
* Delete a project and delete project-groups related to this project.
* This method is cluster-save.
* @see org.olat.course.nodes.projectbroker.service.ProjectBrokerManager#deleteProject(org.olat.course.nodes.projectbroker.datamodel.Project)
*/
public void deleteProject(final Project project, final boolean deleteGroup, final CourseEnvironment courseEnv, final CourseNode cNode) {
logDebug("start deleteProject project=" + project);
final Long projectBrokerId = project.getProjectBroker().getKey();
OLATResourceable projectBrokerOres = OresHelper.createOLATResourceableInstance(this.getClass(),projectBrokerId);
CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync( projectBrokerOres, new SyncerExecutor() {
public void execute() {
Project reloadedProject = (Project) dbInstance.loadObject(project, true);
// delete first candidate-group, project-group will be deleted after deleting project
SecurityGroup candidateGroup = reloadedProject.getCandidateGroup();
if ( (courseEnv != null) && (cNode != null) ) {
deleteAllAttachmentFilesOfProject(reloadedProject, courseEnv, cNode);
deleteAllDropboxFilesOfProject(reloadedProject, courseEnv, cNode);
deleteAllReturnboxFilesOfProject(reloadedProject, courseEnv, cNode);
}
dbInstance.deleteObject(reloadedProject);
logInfo("deleteSecurityGroup(project.getCandidateGroup())=" + candidateGroup.getKey());
securityManager.deleteSecurityGroup(candidateGroup);
// invalide with removing from cache
projectCache.remove(projectBrokerId.toString());
}
});
if (deleteGroup) {
logDebug("start deleteProjectGroupFor project=" + project);
projectGroupManager.deleteProjectGroupFor(project);
}
logDebug("DONE deleteProjectGroupFor project=" + project);
}
public int getNbrSelectedProjects(Identity identity, List<Project> projectList) {
int selectedCounter = 0;
for (Iterator<Project> iterator = projectList.iterator(); iterator.hasNext();) {
Project project = iterator.next();
if (businessGroupService.hasRoles(identity, project.getProjectGroup(), GroupRoles.participant.name()) ||
securityManager.isIdentityInSecurityGroup(identity, project.getCandidateGroup()) ) {
selectedCounter++;
}
}
return selectedCounter;
}
/**
* return true, when the project can be selected by the user.
* @see org.olat.course.nodes.projectbroker.datamodel.Project#canBeSelectedBy(org.olat.core.id.Identity)
*/
public boolean canBeProjectSelectedBy(Identity identity, Project project, ProjectBrokerModuleConfiguration moduleConfig, int nbrSelectedProjects, boolean isParticipantInAnyProject) {
logDebug("canBeSelectedBy: identity=" + identity + " project=" + project);
// 1. check if already enrolled
if ( projectGroupManager.isProjectParticipant(identity, project)
|| projectGroupManager.isProjectCandidate(identity, project)) {
logDebug("canBeSelectedBy: return false because identity is already enrolled");
return false;
}
// 2. check number of max project members
int projectMembers = project.getSelectedPlaces();
if ( (project.getMaxMembers() != Project.MAX_MEMBERS_UNLIMITED) && (projectMembers >= project.getMaxMembers()) ) {
logDebug("canBeSelectedBy: return false because projectMembers >= getMaxMembers()");
return false;
}
// 3. number of selected topic per user
int nbrOfParticipantsPerTopicValue = moduleConfig.getNbrParticipantsPerTopic();
if ( (nbrOfParticipantsPerTopicValue != ProjectBrokerModuleConfiguration.NBR_PARTICIPANTS_UNLIMITED) &&
(nbrSelectedProjects >= nbrOfParticipantsPerTopicValue) ) {
logDebug("canBeSelectedBy: return false because number of selected topic per user is " + nbrOfParticipantsPerTopicValue);
return false;
}
// 4. accept is done manually
if (moduleConfig.isAcceptSelectionManually() ) {
// 4.1 and project-state is assigned
if (project.getState().equals(Project.STATE_ASSIGNED) ) {
logDebug("canBeSelectedBy: return false because accept is done manually and project-state is assigned, project.getState()=" + project.getState());
return false;
}
// 4.2. and user is already assigned in another project
if (moduleConfig.isAcceptSelectionManually() && moduleConfig.isAutoSignOut() && isParticipantInAnyProject ) {
logDebug("canBeSelectedBy: return false because accept is done manually and user is already participant in another project" );
return false;
}
}
// 5. date for enrollment ok
if (!isEnrollmentDateOk(project,moduleConfig) ){
logDebug("canBeSelectedBy: return false because enrollment date not valid =" + project.getProjectEvent(EventType.ENROLLMENT_EVENT));
return false;
}
logDebug("canBeSelectedBy: return true");
return true;
}
public boolean canBeCancelEnrollmentBy(Identity identity,Project project,ProjectBrokerModuleConfiguration moduleConfig) {
// 6. date for enrollemnt ok
if (!isEnrollmentDateOk(project,moduleConfig) ){
return false;
}
// disable deselection link
if(!projectGroupManager.isDeselectionAllowed(project)){
return false;
} else {
if (moduleConfig.isAcceptSelectionManually()) {
// could only cancel enrollment, when projectleader did not accept yet
return projectGroupManager.isProjectCandidate(identity, project) && !project.getState().equals(Project.STATE_ASSIGNED);
}
// could always cancel enrollment
return projectGroupManager.isProjectParticipant(identity, project);
}
}
public void signOutFormAllCandidateList(final List<Identity> chosenIdentities, final Long projectBrokerId) {
OLATResourceable projectBrokerOres = OresHelper.createOLATResourceableInstance(this.getClass(),projectBrokerId);
CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync( projectBrokerOres, new SyncerExecutor() {
public void execute() {
ProjectBroker projectBroker = getOrLoadProjectBoker(projectBrokerId);
for (Iterator<Project> iterator = projectBroker.getProjects().iterator(); iterator.hasNext();) {
Project project = iterator.next();
// loop over all identities
for (Iterator<Identity> iterator2 = chosenIdentities.iterator(); iterator2.hasNext();) {
Identity identity = iterator2.next();
securityManager.removeIdentityFromSecurityGroup(identity, project.getCandidateGroup());
logAudit("ProjectBroker: AutoSignOut: identity=" + identity + " from project=" + project);
}
}
}
});
}
public String getStateFor(Project project, Identity identity, ProjectBrokerModuleConfiguration moduleConfig) {
if (moduleConfig.isAcceptSelectionManually() ) {
// Accept manually : unterscheiden Betreuer | Teilnehmer
if (projectGroupManager.isProjectManager(identity, project)) {
// State Betreuer : Teilnehmer prüfen | Teilnemher akzeptiert
if (project.getState().equals(Project.STATE_ASSIGNED)) {
return Project.STATE_ASSIGNED_ACCOUNT_MANAGER;
} else {
if (securityManager.countIdentitiesOfSecurityGroup(project.getCandidateGroup()) > 0) {
return Project.STATE_NOT_ASSIGNED_ACCOUNT_MANAGER;
} else {
return Project.STATE_NOT_ASSIGNED_ACCOUNT_MANAGER_NO_CANDIDATE;
}
}
} else {
// State Teilnehmer : prov. eingeschrieben | definitiv eingeschrieben | belegt | frei
if (projectGroupManager.isProjectParticipant(identity, project)) {
return Project.STATE_FINAL_ENROLLED;
} else if (projectGroupManager.isProjectCandidate(identity, project)){
return Project.STATE_PROV_ENROLLED;
} else {
if ( ((project.getMaxMembers() != Project.MAX_MEMBERS_UNLIMITED) && (project.getSelectedPlaces() >= project.getMaxMembers()))
|| project.getState().equals(Project.STATE_ASSIGNED)) {
return Project.STATE_COMPLETE;
} else {
return Project.STATE_NOT_ASSIGNED;
}
}
}
} else {
// Accept automatically => State : frei | belegt | eingeschrieben
if (projectGroupManager.isProjectParticipant(identity, project)) {
return Project.STATE_ENROLLED;
} else {
if ( (project.getMaxMembers() != Project.MAX_MEMBERS_UNLIMITED) && (project.getSelectedPlaces() >= project.getMaxMembers()) ) {
return Project.STATE_COMPLETE;
} else {
return Project.STATE_NOT_ASSIGNED;
}
}
}
}
public void deleteProjectBroker(Long projectBrokerId, CourseEnvironment courseEnvironment, CourseNode courseNode) {
logDebug("Start deleting projectBrokerId=" + projectBrokerId );
ProjectBroker projectBroker = getOrLoadProjectBoker(projectBrokerId);
// delete all projects of a project-broker
List<Project> deleteProjectList = new ArrayList<Project>();
deleteProjectList.addAll(projectBroker.getProjects());
for (Iterator<Project> iterator = deleteProjectList.iterator(); iterator.hasNext();) {
Project project = iterator.next();
deleteProject(project, true, courseEnvironment, courseNode);
logAudit("ProjectBroker: Deleted project=" + project );
}
logDebug("All projects are deleted for ProjectBroker=" + projectBroker);
projectGroupManager.deleteAccountManagerGroup(courseEnvironment.getCoursePropertyManager(), courseNode);
ProjectBroker reloadedProjectBroker = (ProjectBroker) dbInstance.loadObject(projectBroker, true);
dbInstance.deleteObject(reloadedProjectBroker);
// invalide with removing from cache
projectCache.remove(projectBrokerId.toString());
logAudit("ProjectBroker: Deleted ProjectBroker=" + projectBroker);
}
public void saveAttachedFile(Project project, String fileName, VFSLeaf uploadedItem, CourseEnvironment courseEnv, CourseNode cNode) {
logDebug("saveAttachedFile file-name=" + uploadedItem.getName());
OlatRootFolderImpl uploadVFSContainer = new OlatRootFolderImpl(getAttamchmentRelativeRootPath(project,courseEnv,cNode), null);
logDebug("saveAttachedFile uploadVFSContainer.relPath=" + uploadVFSContainer.getRelPath());
// only one attachment, delete other file
for (Iterator<VFSItem> iterator = uploadVFSContainer.getItems().iterator(); iterator.hasNext();) {
VFSItem item = iterator.next();
// Project.getAttachmentFileName is the previous file-name, will not be deleted; student could have open detail-project page with previous attachemnt-link
if (!item.getName().equals(project.getAttachmentFileName())) {
item.delete();
}
}
VFSLeaf newFile = (VFSLeaf)uploadVFSContainer.resolve(fileName);
if (newFile == null) {
newFile = uploadVFSContainer.createChildLeaf(fileName);
}
BufferedInputStream in = new BufferedInputStream(uploadedItem.getInputStream());
BufferedOutputStream out = new BufferedOutputStream(newFile.getOutputStream(false));
boolean success = false;
if (in != null) {
success = FileUtils.copy(in, out);
}
FileUtils.closeSafely(in);
FileUtils.closeSafely(out);
logDebug("saveAttachedFile success=" + success);
}
public boolean isCustomFieldValueValid(String value, String valueList) {
StringTokenizer tok = new StringTokenizer(valueList,ProjectBrokerManager.CUSTOMFIELD_LIST_DELIMITER);
if (tok.hasMoreTokens()) {
// It is a list of values => check if value is one of them
while (tok.hasMoreTokens()) {
if (tok.nextToken().equalsIgnoreCase(value) ) {
return true;
}
}
return false;
} else {
// no value-list => value can be any value
return true;
}
}
public String getAttamchmentRelativeRootPath(Project project, CourseEnvironment courseEnv, CourseNode cNode) {
return getAttachmentBasePathRelToFolderRoot(courseEnv, cNode) + File.separator + project.getKey();
}
public String getAttachmentBasePathRelToFolderRoot(CourseEnvironment courseEnvironment, CourseNode courseNode) {
return courseEnvironment.getCourseBaseContainer().getRelPath() + File.separator + ATTACHEMENT_DIR_NAME + File.separator + courseNode.getIdent();
}
private void deleteAllAttachmentFilesOfProject(Project project, CourseEnvironment courseEnv, CourseNode cNode) {
VFSContainer attachmentDir = new OlatRootFolderImpl(getAttamchmentRelativeRootPath(project,courseEnv,cNode), null);
attachmentDir.delete();
logDebug("deleteAllAttachmentFilesOfProject path=" + attachmentDir);
}
private void deleteAllDropboxFilesOfProject(Project project, CourseEnvironment courseEnv, CourseNode cNode) {
VFSContainer dropboxDir = new OlatRootFolderImpl(ProjectBrokerDropboxController.getDropboxBasePathForProject(project,courseEnv,cNode), null);
dropboxDir.delete();
logDebug("deleteAllDropboxFilesOfProject path=" + dropboxDir);
}
private void deleteAllReturnboxFilesOfProject(Project project, CourseEnvironment courseEnv, CourseNode cNode) {
VFSContainer returnboxDir = new OlatRootFolderImpl(ProjectBrokerReturnboxController.getReturnboxBasePathForProject(project,courseEnv,cNode), null);
returnboxDir.delete();
logDebug("deleteAllReturnboxFilesOfProject path=" + returnboxDir);
}
///////////////////
// Private Methods
///////////////////
private ProjectBroker getOrLoadProjectBoker(final Long projectBrokerId) {
// 1. check if alreday a projectBroker is in the cache
ProjectBroker projectBroker = projectCache.get(projectBrokerId.toString());
if (projectBroker == null) {
logDebug("find no projectBroker in the cache => create a new one projectBrokerId=" + projectBrokerId);
StringBuilder sb = new StringBuilder();
sb.append("select distinct project from ").append(ProjectImpl.class.getName()).append(" as project ")
.append(" left join fetch project.projectGroup pGroup")
.append(" left join fetch pGroup.baseGroup bGroup")
.append(" where project.projectBroker.key=:projectBrokerKey");
List<Project> projectList = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Project.class)
.setParameter("projectBrokerKey", projectBrokerId)
.getResultList();
projectBroker = getProjectBroker(projectBrokerId);
projectBroker.setProjects(projectList);
projectCache.put(projectBrokerId.toString(), projectBroker);
}
return projectBroker;
}
public ProjectBroker getProjectBroker(Long projectBrokerId) {
return dbInstance.loadObject(ProjectBrokerImpl.class, projectBrokerId);
}
private boolean isEnrollmentDateOk(Project project, ProjectBrokerModuleConfiguration moduleConfig) {
if (moduleConfig.isProjectEventEnabled(EventType.ENROLLMENT_EVENT)) {
ProjectEvent enrollmentEvent = project.getProjectEvent(EventType.ENROLLMENT_EVENT);
Date now = new Date();
if (enrollmentEvent.getStartDate() != null) {
if (now.before(enrollmentEvent.getStartDate())) {
return false;
}
}
if (enrollmentEvent.getEndDate() != null) {
if (now.after(enrollmentEvent.getEndDate())) {
return false;
}
}
if ( (enrollmentEvent.getStartDate() == null ) && (enrollmentEvent.getEndDate() == null) ) {
// no enrollment date define => access ok
return true;
}
}
return true;
}
/**
* return true, when identity is participant in any project of project-list.
* @param identity
* @param projectList
* @return
*/
public boolean isParticipantInAnyProject(Identity identity, List<Project> projectList) {
for (Iterator<Project> iterator = projectList.iterator(); iterator.hasNext();) {
Project project = iterator.next();
if (businessGroupService.hasRoles(identity, project.getProjectGroup(), GroupRoles.participant.name()) ) {
return true;
}
}
return false;
}
@SuppressWarnings("unchecked")
public List<Project> getProjectsWith(BusinessGroup group) {
List<Project> projectList = dbInstance.find(
"select project from org.olat.course.nodes.projectbroker.datamodel.ProjectImpl as project" +
" where project.projectGroup.key = ?", group.getKey(), StandardBasicTypes.LONG);
return projectList;
}
@Override
public void setProjectState(final Project project, final String state) {
final Long projectBrokerId = project.getProjectBroker().getKey();
OLATResourceable projectBrokerOres = OresHelper.createOLATResourceableInstance(this.getClass(),projectBrokerId);
CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync( projectBrokerOres, new SyncerExecutor() {
public void execute() {
// For cluster-safe : reload project object here another node might have changed this in the meantime
Project reloadedProject = (Project) dbInstance.loadObject(project, true);
reloadedProject.setState(state);
updateProjectAndInvalidateCache(reloadedProject);
}
});
}
public Long getProjectBrokerId(CoursePropertyManager cpm, CourseNode courseNode) {
Property projectBrokerKeyProperty = cpm.findCourseNodeProperty(courseNode, null, null, ProjectBrokerCourseNode.CONF_PROJECTBROKER_KEY);
// Check if forum-property exist
if (projectBrokerKeyProperty != null) {
Long projectBrokerId = projectBrokerKeyProperty.getLongValue();
return projectBrokerId;
}
return null;
}
public void saveProjectBrokerId(Long projectBrokerId, CoursePropertyManager cpm, CourseNode courseNode) {
Property projectBrokerKeyProperty = cpm.createCourseNodePropertyInstance(courseNode, null, null, ProjectBrokerCourseNode.CONF_PROJECTBROKER_KEY, null, projectBrokerId, null, null);
cpm.saveProperty(projectBrokerKeyProperty);
}
public boolean existProjectName(Long projectBrokerId, String newProjectTitle) {
StringBuilder sb = new StringBuilder();
sb.append("select count(project.key) from ").append(ProjectImpl.class.getName()).append(" as project")
.append(" where project.projectBroker.key=:projectBrokerId and project.title=:title");
Number count = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Number.class)
.setParameter("projectBrokerId", projectBrokerId).setParameter("title", newProjectTitle)
.getSingleResult();
return count == null ? false : count.intValue() > 0;
}
@Override
public List<Project> getProjectsOf(Identity identity, Long projectBrokerId) {
List<Project> myProjects = new ArrayList<Project>();
List<Project> allProjects = getProjectListBy(projectBrokerId);
//TODO: for better performance should be done with sql query instead of a loop
for (Iterator<Project> iterator = allProjects.iterator(); iterator.hasNext();) {
Project project = iterator.next();
if (businessGroupService.hasRoles(identity, project.getProjectGroup(), GroupRoles.participant.name()) ) {
myProjects.add(project);
}
}
return myProjects;
}
@Override
public Project getProject(Long resourceableId) {
return dbInstance.findObject(ProjectImpl.class, resourceableId);
}
@Override
public List<Project> getCoachedProjectsOf(Identity identity, Long projectBrokerId) {
List<Project> myProjects = new ArrayList<Project>();
List<Project> allProjects = getProjectListBy(projectBrokerId);
//TODO: for better performance should be done with sql query instead of a loop
for (Iterator<Project> iterator = allProjects.iterator(); iterator.hasNext();) {
Project project = iterator.next();
if (businessGroupService
.hasRoles(identity, project.getProjectGroup(), GroupRoles.coach.name())) {
myProjects.add(project);
}
}
return myProjects;
}
private void updateProjectAndInvalidateCache(final Project project) {
// avoid hibernate exception : object with same identifier already exist in session.
// reload object from db, because project is a detached object but could be already in hibernate session
Project reloadedProject = (Project) dbInstance.loadObject(project, true);
// set all value on reloadedProject with values from updated project
reloadedProject.setTitle(project.getTitle());
reloadedProject.setState(project.getState());
for (Project.EventType eventType : Project.EventType.values()) {
reloadedProject.setProjectEvent(project.getProjectEvent(eventType));
}
reloadedProject.setMaxMembers(project.getMaxMembers());
reloadedProject.setMailNotificationEnabled(project.isMailNotificationEnabled());
reloadedProject.setDescription(project.getDescription());
for (int index = 0; index < project.getCustomFieldSize(); index++) {
reloadedProject.setCustomFieldValue(index, project.getCustomFieldValue(index));
}
reloadedProject.setAttachedFileName(project.getAttachmentFileName());
dbInstance.updateObject(reloadedProject);
// invalide with removing from cache
projectCache.remove(project.getProjectBroker().getKey().toString());
}
}