/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/sam/trunk/samigo-services/src/java/org/sakaiproject/tool/assessment/integration/helper/integrated/AssessmentGradeInfoProvider.java $
* $Id: AssessmentGradeInfoProvider.java 127473 2013-07-21 00:04:12Z nbotimer@unicon.net $
***********************************************************************************
*
* Copyright (c) 2011 The Sakai Foundation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.opensource.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/
package org.sakaiproject.tool.assessment.integration.helper.integrated;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.authz.api.Member;
import org.sakaiproject.exception.IdUnusedException;
import org.sakaiproject.service.gradebook.shared.ExternalAssignmentProvider;
import org.sakaiproject.service.gradebook.shared.ExternalAssignmentProviderCompat;
import org.sakaiproject.service.gradebook.shared.GradebookExternalAssessmentService;
import org.sakaiproject.site.api.Group;
import org.sakaiproject.site.api.Site;
import org.sakaiproject.site.api.SiteService;
import org.sakaiproject.tool.assessment.data.dao.assessment.AssessmentAccessControl;
import org.sakaiproject.tool.assessment.data.dao.authz.AuthorizationData;
import org.sakaiproject.tool.assessment.data.ifc.assessment.PublishedAssessmentIfc;
import org.sakaiproject.tool.assessment.facade.PublishedAssessmentFacade;
import org.sakaiproject.tool.assessment.services.PersistenceService;
import org.sakaiproject.tool.assessment.services.assessment.PublishedAssessmentService;
import org.sakaiproject.user.api.UserDirectoryService;
/**
* Provides info to the gradebook about which assessments are visible
*/
public class AssessmentGradeInfoProvider implements ExternalAssignmentProvider, ExternalAssignmentProviderCompat {
private Log log = LogFactory.getLog(AssessmentGradeInfoProvider.class);
private GradebookExternalAssessmentService geaService;
private UserDirectoryService userDirectoryService;
private SiteService siteService;
public void init() {
log.info("INIT and Register Samigo AssessmentGradeInfoProvider");
geaService.registerExternalAssignmentProvider(this);
}
public void destroy() {
log.info("DESTROY and unregister Samigo AssessmentGradeInfoProvider");
geaService.unregisterExternalAssignmentProvider(getAppKey());
}
public String getAppKey() {
return "samigo";
}
private PublishedAssessmentIfc getPublishedAssessment(String id) {
PublishedAssessmentService pas = new PublishedAssessmentService();
PublishedAssessmentIfc a;
try {
a = pas.getPublishedAssessment(id);
} catch (Exception e) {
// NumberFormatException is thrown on non-numeric IDs
if (log.isDebugEnabled()) {
log.debug("Assessment lookup failed for ID: " + id + " -- " + e.getMessage());
}
a = null;
}
return a;
}
public boolean isAssignmentDefined(String id) {
if (log.isDebugEnabled()) {
log.debug("Samigo provider isAssignmentDefined: " + id);
}
return getPublishedAssessment(id) != null;
}
public boolean isAssignmentGrouped(String id) {
if (log.isDebugEnabled()) {
log.debug("Samigo provider isAssignmentGrouped: " + id);
}
PublishedAssessmentService pas = new PublishedAssessmentService();
boolean grouped = false;
try {
grouped = pas.isReleasedToGroups(id);
} catch (Exception e) {
//isReleasedToGroups does not error check
if (log.isDebugEnabled()) {
log.debug("Assignment lookup failed for ID: " + id + " -- " + e.getMessage());
}
}
return grouped;
}
//FIXME: Visibility logic is ripped from LoginServlet, modified some for params we have here
//TODO: Refactor so that permissions logic is exposed in a service method somewhere
public boolean isAssignmentVisible(String id, String userId) {
if (log.isDebugEnabled()) {
log.debug("Samigo provider isAssignmentVisible: " + id + ", " + userId);
}
PublishedAssessmentIfc pub = getPublishedAssessment(id);
if (pub == null) {
return false;
}
boolean isAuthorized = false;
boolean isAuthenticated = false;
String releaseTo = pub.getAssessmentAccessControl().getReleaseTo();
if (releaseTo != null && releaseTo.indexOf("Anonymous Users")> -1){
isAuthenticated = true;
isAuthorized = true;
}
else { // check membership
isAuthenticated = ( userId != null && !("").equals(userId));
if (isAuthenticated){
if (releaseTo.indexOf(AssessmentAccessControl.RELEASE_TO_SELECTED_GROUPS)>-1) {
isAuthorized = checkMembershipForGroupRelease(pub, userId);
}
else {
isAuthorized = checkMembership(pub, userId);
}
}
}
return isAuthorized;
}
public List<String> getExternalAssignmentsForCurrentUser(String gradebookUid) {
List all = PersistenceService.getInstance().getPublishedAssessmentFacadeQueries().
getBasicInfoOfAllPublishedAssessments("title", true, gradebookUid);
ArrayList<String> externalIds = new ArrayList<String>();
for (PublishedAssessmentIfc pub : (List<PublishedAssessmentIfc>) all) {
externalIds.add(pub.getPublishedAssessmentId().toString());
}
return externalIds;
}
public List<String> getAllExternalAssignments(String gradebookUid) {
List allPublished = PersistenceService.getInstance().getPublishedAssessmentFacadeQueries().
getBasicInfoOfAllPublishedAssessments2("title", true, gradebookUid);
List<String> allExternals = new ArrayList<String>();
for (PublishedAssessmentFacade pub : (List<PublishedAssessmentFacade>) allPublished) {
String assessmentId = pub.getPublishedAssessmentId().toString();
allExternals.add(assessmentId);
}
return allExternals;
}
public Map<String, List<String>> getAllExternalAssignments(String gradebookUid, Collection<String> studentIds) {
List allPublished = PersistenceService.getInstance().getPublishedAssessmentFacadeQueries().
getBasicInfoOfAllPublishedAssessments2("title", true, gradebookUid);
//TODO: Update PublishedAssessmentFacadeQueriesAPI to return a list of group IDs
// or member lists instead of only group titles.
// This borrows some releasedTo logic to keep a narrower patch for now.
Map<String, Set<String>> allExternals = new HashMap<String, Set<String>>();
for (String studentId : studentIds) {
allExternals.put(studentId, new HashSet<String>());
}
Set<String> siteUserIds = getSiteUserIds(gradebookUid);
Map<String, Set<String>> userIdGroupIds = getUserGroups(gradebookUid, studentIds);
Map<String, Set<String>> groupIdUserIds = invertMapSet(userIdGroupIds);
// Get all groups for site, and all members therein
// Get access control for each assessment
// 1: anonymous - all site users
// 2: no specific groups - all site users
// 3: specific groups - all users in all specified groups
for (PublishedAssessmentFacade pub : (List<PublishedAssessmentFacade>) allPublished) {
String assessmentId = pub.getPublishedAssessmentId().toString();
String releaseTo = pub.getReleaseTo();
if (releaseTo != null && assessmentId != null) {
if (releaseTo.indexOf("Anonymous Users")> -1) {
for (String studentId : studentIds) {
allExternals.get(studentId).add(assessmentId);
}
} else if (AssessmentAccessControl.RELEASE_TO_SELECTED_GROUPS.equals(releaseTo)) {
//TODO: Add a signature to AuthzQueriesFacadeAPI to get authorized groups for
// a set of assessments, rather than just one.
Set<String> authorizedGroups = getAuthorizedGroups(assessmentId);
for (String groupId : authorizedGroups) {
if (groupIdUserIds.containsKey(groupId)) {
for (String userId : groupIdUserIds.get(groupId)) {
if (allExternals.containsKey(userId)) {
allExternals.get(userId).add(assessmentId);
}
}
}
}
} else {
for (String studentId : studentIds) {
if (siteUserIds.contains(studentId)) {
allExternals.get(studentId).add(assessmentId);
}
}
}
}
}
Map<String, List<String>> allExternalsList = new HashMap<String, List<String>>();
for (String studentId : allExternals.keySet()) {
allExternalsList.put(studentId, new ArrayList<String>(allExternals.get(studentId)));
}
return allExternalsList;
}
private Set<String> getAuthorizedGroups(String assessmentId) {
List authorizations = PersistenceService.getInstance().getAuthzQueriesFacade()
.getAuthorizationByFunctionAndQualifier("TAKE_PUBLISHED_ASSESSMENT", assessmentId);
Set<String> authorizedGroups = new HashSet<String>();
if (authorizations != null && authorizations.size()>0) {
Iterator authsIter = authorizations.iterator();
while (authsIter.hasNext()) {
AuthorizationData ad = (AuthorizationData) authsIter.next();
authorizedGroups.add(ad.getAgentIdString());
}
}
return authorizedGroups;
}
private Set<String> getSiteUserIds(String siteId) {
Set<String> userIds = new HashSet<String>();
try {
Site site = siteService.getSite(siteId);
for (Member m : site.getMembers()) {
userIds.add(m.getUserId());
}
} catch (IdUnusedException e) {
if (log.isDebugEnabled()) {
log.debug("Site not found when attempting to retrieve its users: " + siteId);
}
}
return userIds;
}
// Retrieve a map of student ID -> group IDs for a list of users in a site
private Map<String, Set<String>> getUserGroups(String siteId, Collection<String> studentIds) {
Map<String, Set<String>> userIdGroupIds = new HashMap<String, Set<String>>();
for (String studentId : studentIds) {
userIdGroupIds.put(studentId, new HashSet<String>());
}
try {
Site site = siteService.getSite(siteId);
for (Group g : site.getGroups()) {
for (Member m : g.getMembers()) {
String userId = m.getUserId();
if (userIdGroupIds.containsKey(userId)) {
userIdGroupIds.get(userId).add(g.getId());
}
}
}
} catch (IdUnusedException e) {
if (log.isDebugEnabled()) {
log.debug("Site not found when attempting to retrieve user groups: " + siteId);
}
}
return userIdGroupIds;
}
private Map<String, Set<String>> invertMapSet(Map<String, Set<String>> mapSet) {
Map<String, Set<String>> inverted = new HashMap<String, Set<String>>();
for (String key : mapSet.keySet()) {
Set<String> values = mapSet.get(key);
for (String value : values) {
if (!inverted.containsKey(value)) {
inverted.put(value, new HashSet<String>());
}
inverted.get(value).add(key);
}
}
return inverted;
}
private boolean checkMembership(PublishedAssessmentIfc pub, String userId){
boolean isMember=false;
// get list of site that this published assessment has been released to
List l = PersistenceService.getInstance().getAuthzQueriesFacade().
getAuthorizationByFunctionAndQualifier("VIEW_PUBLISHED_ASSESSMENT",
pub.getPublishedAssessmentId().toString());
for (int i=0;i<l.size();i++){
String siteId = ((AuthorizationData)l.get(i)).getAgentIdString();
try {
isMember = (siteService.getSite(siteId).getUserRole(userId) != null);
} catch (IdUnusedException e) {
log.info("Site with ID: " + siteId + " does not exists but is "
+ "authorized for assessment id: " + pub.getPublishedAssessmentId());
}
if (isMember) {
break;
}
}
return isMember;
}
private boolean checkMembershipForGroupRelease(PublishedAssessmentIfc pub, String userId){
boolean isMember=false;
// get the site that owns the published assessment
List l =PersistenceService.getInstance().getAuthzQueriesFacade().
getAuthorizationByFunctionAndQualifier("OWN_PUBLISHED_ASSESSMENT",
pub.getPublishedAssessmentId().toString());
if (l == null || l.isEmpty()) {
return false;
}
String siteId = ((AuthorizationData)l.get(0)).getAgentIdString();
Collection siteGroupsContainingUser = null;
try {
siteGroupsContainingUser = siteService.getSite(siteId).getGroupsWithMember(userId);
}
catch (IdUnusedException ex) {
// no site found
}
// get list of groups that this published assessment has been released to
l =PersistenceService.getInstance().getAuthzQueriesFacade().
getAuthorizationByFunctionAndQualifier("TAKE_PUBLISHED_ASSESSMENT",
pub.getPublishedAssessmentId().toString());
for (int i=0;i<l.size();i++){
String groupId = ((AuthorizationData)l.get(i)).getAgentIdString();
isMember = isUserInAuthorizedGroup(groupId, siteGroupsContainingUser);
if (isMember) {
break;
}
}
return isMember;
}
private boolean isUserInAuthorizedGroup(String authorizedGroupId, Collection userGroups) {
if (userGroups==null || userGroups.isEmpty()
|| authorizedGroupId==null || authorizedGroupId.equals("")) {
return false;
}
Iterator userGroupsIter = userGroups.iterator();
while (userGroupsIter.hasNext()) {
Group group = (Group) userGroupsIter.next();
if (group.getId().equals(authorizedGroupId)) {
return true;
}
}
return false;
}
public GradebookExternalAssessmentService getGradebookExternalAssessmentService() {
return geaService;
}
public void setGradebookExternalAssessmentService( GradebookExternalAssessmentService geaService) {
this.geaService = geaService;
}
public void setUserDirectoryService(UserDirectoryService userDirectoryService) {
this.userDirectoryService = userDirectoryService;
}
public UserDirectoryService getUserDirectoryService() {
return userDirectoryService;
}
public SiteService getSiteService() {
return siteService;
}
public void setSiteService(SiteService siteService) {
this.siteService = siteService;
}
}