package org.sakaiproject.tool.gradebook.ui.helpers.entity;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import lombok.Setter;
import lombok.extern.apachecommons.CommonsLog;
import org.apache.commons.lang.StringUtils;
import org.sakaiproject.entitybroker.EntityReference;
import org.sakaiproject.entitybroker.EntityView;
import org.sakaiproject.entitybroker.entityprovider.CoreEntityProvider;
import org.sakaiproject.entitybroker.entityprovider.annotations.EntityCustomAction;
import org.sakaiproject.entitybroker.entityprovider.capabilities.ActionsExecutable;
import org.sakaiproject.entitybroker.entityprovider.capabilities.AutoRegisterEntityProvider;
import org.sakaiproject.entitybroker.entityprovider.capabilities.Describeable;
import org.sakaiproject.entitybroker.entityprovider.capabilities.Outputable;
import org.sakaiproject.entitybroker.entityprovider.capabilities.Sampleable;
import org.sakaiproject.entitybroker.entityprovider.extension.Formats;
import org.sakaiproject.entitybroker.util.AbstractEntityProvider;
import org.sakaiproject.exception.IdUnusedException;
import org.sakaiproject.service.gradebook.shared.Assignment;
import org.sakaiproject.service.gradebook.shared.CommentDefinition;
import org.sakaiproject.service.gradebook.shared.GradebookService;
import org.sakaiproject.site.api.Site;
import org.sakaiproject.site.api.SiteService;
import org.sakaiproject.tool.gradebook.ui.helpers.params.GradebookItemViewParams;
import org.sakaiproject.tool.gradebook.ui.helpers.producers.AuthorizationFailedProducer;
import org.sakaiproject.tool.gradebook.ui.helpers.producers.GradebookItemProducer;
import org.sakaiproject.user.api.User;
import org.sakaiproject.user.api.UserDirectoryService;
import org.sakaiproject.user.api.UserNotDefinedException;
import uk.ac.cam.caret.sakai.rsf.entitybroker.EntityViewParamsInferrer;
import uk.org.ponder.rsf.viewstate.SimpleViewParameters;
import uk.org.ponder.rsf.viewstate.ViewParameters;
/*
* This is a provider for looking up and adding/editing Gradebook Items.
* It is actually passing along to a gradebook UI via RSF and does not provide any rest access to grades data
*/
@CommonsLog
public class GradebookEntityProvider extends AbstractEntityProvider implements
AutoRegisterEntityProvider, CoreEntityProvider,
EntityViewParamsInferrer, Describeable, Sampleable, ActionsExecutable,
Outputable {
public final static String ENTITY_PREFIX = "gradebook";
@Setter
private GradebookService gradebookService;
@Setter
private SiteService siteService;
@Setter
private UserDirectoryService userDirectoryService;
public String getEntityPrefix() {
return ENTITY_PREFIX;
}
public boolean entityExists(String id) {
return true;
}
public String[] getHandledPrefixes() {
return new String[] { ENTITY_PREFIX };
}
public Object getSampleEntity() {
return new GradeAssignmentItemDetail();
}
/*
* (non-Javadoc)
*
* @see
* org.sakaiproject.entitybroker.entityprovider.capabilities.Outputable#
* getHandledOutputFormats()
*/
public String[] getHandledOutputFormats() {
return new String[] { Formats.XML, Formats.JSON };
}
public ViewParameters inferDefaultViewParameters(String reference) {
// IdEntityReference ep = new IdEntityReference(reference);
// String contextId = ep.id;
String contextId = new EntityReference(reference).getId();
if (gradebookService.currentUserHasEditPerm(contextId)) {
Long gradebookEntryId = null;
return new GradebookItemViewParams(GradebookItemProducer.VIEW_ID,
contextId, gradebookEntryId);
} else {
return new SimpleViewParameters(AuthorizationFailedProducer.VIEW_ID);
}
}
@EntityCustomAction(action = "site", viewKey = EntityView.VIEW_LIST)
public GradeCourse getCourseGradebook(EntityView view) {
String siteId = view.getPathSegment(2);
// check siteId supplied
if (StringUtils.isBlank(siteId)) {
throw new IllegalArgumentException(
String.format(
"siteId must be set in order to get the gradebook for a site, via the URL /%s/site/{siteId}",
ENTITY_PREFIX));
}
String userId = developerHelperService.getCurrentUserId();
if (userId == null) {
throw new SecurityException("Only logged in users can access");
}
Site site;
try {
site = siteService.getSite(siteId);
} catch (IdUnusedException e) {
throw new IllegalArgumentException(String.format(
"Invalid siteId %s", siteId));
}
// The gradebookUID is the siteId, the gradebookID is a long
if (!gradebookService.isGradebookDefined(siteId)) {
throw new IllegalArgumentException("No gradebook found for site: "
+ siteId);
}
if (developerHelperService.isUserAdmin(userId)
|| siteService.allowUpdateSite(siteId)) {
// admin or instructor
log.info("Admin or instructor accesssing gradebook of site "
+ siteId);
GradeCourse course = new GradeCourse(site);
Collection<String> students = getStudentList(siteId);
@SuppressWarnings("unchecked")
List<Assignment> gbitems = gradebookService.getAssignments(siteId);
for (Assignment assignment : gbitems) {
for (String studentId : students) {
GradeAssignmentItem item = new GradeAssignmentItem(
assignment);
item.setUserId(studentId);
item.setUserName(getUserDisplayName(studentId));
item.setGrade(gradebookService.getAssignmentScoreString(
siteId, assignment.getName(), studentId));
course.assignments.add(item);
}
}
return course;
} else {
// students or the rest
GradeCourse course = new GradeCourse(site);
List<Assignment> gbitems = gradebookService
.getViewableAssignmentsForCurrentUser(siteId);
for (Assignment assignment : gbitems) {
GradeAssignmentItem item = new GradeAssignmentItem(assignment);
item.setUserId(userId);
item.setUserName(getUserDisplayName(userId));
item.setGrade(gradebookService.getAssignmentScoreString(siteId,
assignment.getName(), userId));
course.assignments.add(item);
}
return course;
}
}
private Collection<String> getStudentList(String siteId) {
// this only works in the post-2.5 gradebook -AZ
// Let the gradebook tell use how it defines the students The
// gradebookUID is the siteId
String gbID = siteId;
if (!gradebookService.isGradebookDefined(gbID)) {
throw new IllegalArgumentException(
"No gradebook found for course ("
+ siteId
+ "), gradebook must be installed in each course to use with this");
}
ArrayList<String> result = new ArrayList<String>();
@SuppressWarnings("unchecked")
Map<String, String> studentToPoints = gradebookService
.getFixedPoint(gbID);
ArrayList<String> eids = new ArrayList<String>(studentToPoints.keySet());
List<User> users = userDirectoryService.getUsersByEids(eids);
for(User u: users) {
result.add(u.getId());
}
Collections.sort(result);
return result;
}
private String getUserDisplayName(String uid) {
try {
User user = userDirectoryService.getUser(uid);
return user.getDisplayName();
} catch (UserNotDefinedException e) {
log.warn("Undefined user id (" + uid + ")");
return null;
}
}
@EntityCustomAction(action = "my", viewKey = EntityView.VIEW_LIST)
public List<GradeCourse> getMyGradebook(EntityView view) {
String userId = developerHelperService.getCurrentUserId();
if (userId == null) {
throw new SecurityException(
"Only logged in users can access my gradebook listings");
}
List<GradeCourse> r = new ArrayList<GradeCourse>();
// get list of all sites
List<Site> sites = siteService.getSites(
SiteService.SelectionType.ACCESS, null, null, null,
SiteService.SortType.TITLE_ASC, null);
// no need to check user can access this site, as the get sites only
// returned accessible sites
// get all assignments from each site
for (Site site : sites) {
String siteId = site.getId();
if (!gradebookService.isGradebookDefined(siteId)) {
continue;
}
GradeCourse course = new GradeCourse(site);
List<Assignment> gbitems = gradebookService
.getViewableAssignmentsForCurrentUser(siteId);
for (Assignment assignment : gbitems) {
GradeAssignmentItem item = new GradeAssignmentItem(assignment);
item.setUserId(userId);
item.setUserName(getUserDisplayName(userId));
item.setGrade(gradebookService.getAssignmentScoreString(siteId,
assignment.getName(), userId));
course.assignments.add(item);
}
r.add(course);
}
return r;
}
@EntityCustomAction(action = "item", viewKey = EntityView.VIEW_LIST)
public GradeAssignmentItemDetail getGradeItemDetails(EntityView view) {
String userId = developerHelperService.getCurrentUserId();
if (userId == null) {
throw new SecurityException(
"Only logged in users can access my gradebook listings");
}
String siteId = view.getPathSegment(2);
// check siteId supplied
if (StringUtils.isBlank(siteId)) {
throw new IllegalArgumentException(
String.format(
"siteId must be set in order to get the details of a gradebook item, via the URL /%s/item/{siteId}/{assignmentName}",
ENTITY_PREFIX));
}
String assignmentName = view.getPathSegment(3);
if (StringUtils.isBlank(assignmentName)) {
throw new IllegalArgumentException(
String.format(
"assignment name must be set in order to get the details of a gradebook item, via the URL /%s/item/{siteId}/{assignmentName}",
ENTITY_PREFIX));
}
if (!gradebookService.isGradebookDefined(siteId)) {
throw new IllegalArgumentException(String.format(
"No gradebook for site %s", siteId));
}
// linear search, slow, but no API for non-admin/non-instructor to get a
// single assignment
List<Assignment> gbitems = gradebookService
.getViewableAssignmentsForCurrentUser(siteId);
for (Assignment assignment : gbitems) {
if (assignment.getName().equals(assignmentName)) {
CommentDefinition cd = gradebookService
.getAssignmentScoreComment(siteId,
assignment.getName(), userId);
GradeAssignmentItemDetail item = new GradeAssignmentItemDetail(
assignment, cd);
item.setUserId(userId);
item.setUserName(getUserDisplayName(userId));
item.setGrade(gradebookService.getAssignmentScoreString(siteId,
assignment.getName(), userId));
return item;
}
}
throw new IllegalArgumentException(String.format(
"No assignment %s for site %s", assignmentName, siteId));
}
}