/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/sam/trunk/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/author/ConfirmPublishAssessmentListener.java $
* $Id: ConfirmPublishAssessmentListener.java 108255 2012-05-17 18:30:57Z ktsao@stanford.edu $
***********************************************************************************
*
* Copyright (c) 2004, 2005, 2006, 2007, 2008 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.ui.listener.author;
import java.util.ArrayList;
import java.util.Date;
import javax.faces.application.FacesMessage;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.component.cover.ServerConfigurationService;
import org.sakaiproject.service.gradebook.shared.GradebookExternalAssessmentService;
import org.sakaiproject.service.gradebook.shared.GradebookService;
import org.sakaiproject.spring.SpringBeanLocator;
import org.sakaiproject.tool.assessment.data.dao.assessment.AssessmentAccessControl;
import org.sakaiproject.tool.assessment.data.ifc.assessment.AssessmentAccessControlIfc;
import org.sakaiproject.tool.assessment.data.ifc.assessment.AssessmentMetaDataIfc;
import org.sakaiproject.tool.assessment.data.ifc.assessment.EvaluationModelIfc;
import org.sakaiproject.tool.assessment.facade.AgentFacade;
import org.sakaiproject.tool.assessment.facade.AssessmentFacade;
import org.sakaiproject.tool.assessment.integration.context.IntegrationContextFactory;
import org.sakaiproject.tool.assessment.integration.helper.ifc.GradebookServiceHelper;
import org.sakaiproject.tool.assessment.services.assessment.AssessmentService;
import org.sakaiproject.tool.assessment.services.assessment.PublishedAssessmentService;
import org.sakaiproject.tool.assessment.ui.bean.author.AssessmentBean;
import org.sakaiproject.tool.assessment.ui.bean.author.AssessmentSettingsBean;
import org.sakaiproject.tool.assessment.ui.bean.author.AuthorBean;
import org.sakaiproject.tool.assessment.ui.bean.author.PublishRepublishNotificationBean;
import org.sakaiproject.tool.assessment.ui.bean.authz.AuthorizationBean;
import org.sakaiproject.tool.assessment.ui.listener.util.ContextUtil;
import org.sakaiproject.tool.assessment.util.TextFormat;
import org.sakaiproject.util.FormattedText;
/**
* <p>Title: Samigo</p>2
* <p>Description: Sakai Assessment Manager</p>
* @author Ed Smiley
* @version $Id: ConfirmPublishAssessmentListener.java 108255 2012-05-17 18:30:57Z ktsao@stanford.edu $
*/
public class ConfirmPublishAssessmentListener
implements ActionListener {
private static Log log = LogFactory.getLog(ConfirmPublishAssessmentListener.class);
//private static ContextUtil cu;
private static final GradebookServiceHelper gbsHelper =
IntegrationContextFactory.getInstance().getGradebookServiceHelper();
private static final boolean integrated =
IntegrationContextFactory.getInstance().isIntegrated();
private boolean isFromActionSelect = false;
public ConfirmPublishAssessmentListener() {
}
public void processAction(ActionEvent ae) throws AbortProcessingException {
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext extContext = context.getExternalContext();
AssessmentSettingsBean assessmentSettings = (AssessmentSettingsBean) ContextUtil.lookupBean("assessmentSettings");
AssessmentBean assessmentBean = (AssessmentBean) ContextUtil.lookupBean("assessmentBean");
AuthorBean author = (AuthorBean) ContextUtil.lookupBean("author");
//#1 - permission checking before proceeding - daisyf
String assessmentId=String.valueOf(assessmentSettings.getAssessmentId());
SaveAssessmentSettings s = new SaveAssessmentSettings();
AssessmentService assessmentService = new AssessmentService();
AssessmentFacade assessment = assessmentService.getAssessment(
assessmentId);
if (!passAuthz(context, assessment.getCreatedBy())){
assessmentSettings.setOutcomePublish("editAssessmentSettings");
author.setIsErrorInSettings(true);
return;
}
assessmentBean.setAssessment(assessment);
// Only if the assessment already have question, this page will be excuted
assessmentSettings.setHasQuestions(true);
//proceed to look for error, save assessment setting and confirm publish
//#2a - look for error: check if core assessment title is unique
boolean error=false;
String assessmentName = TextFormat.convertPlaintextToFormattedTextNoHighUnicode(log, assessmentSettings.getTitle());
if(assessmentName!=null &&(assessmentName.trim()).equals("")){
String nameEmpty_err=ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages","assessmentName_empty");
context.addMessage(null,new FacesMessage(nameEmpty_err));
error=true;
}
if(!assessmentService.assessmentTitleIsUnique(assessmentId,assessmentName,false)){
String nameUnique_err=ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages","assessmentName_error");
context.addMessage(null,new FacesMessage(nameUnique_err));
error=true;
}
// check if start date is valid
if(!assessmentSettings.getIsValidStartDate()){
String startDateErr = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.GeneralMessages","invalid_start_date");
context.addMessage(null,new FacesMessage(startDateErr));
error=true;
}
// check if due date is valid
if(!assessmentSettings.getIsValidDueDate()){
String dueDateErr = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.GeneralMessages","invalid_due_date");
context.addMessage(null,new FacesMessage(dueDateErr));
error=true;
}
// check if retract date is valid
if(!assessmentSettings.getIsValidRetractDate()){
String retractDateErr = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.GeneralMessages","invalid_retrack_date");
context.addMessage(null,new FacesMessage(retractDateErr));
error=true;
}
Date startDate = assessmentSettings.getStartDate();
Date dueDate = assessmentSettings.getDueDate();
Date retractDate = assessmentSettings.getRetractDate();
boolean isRetractEarlierThanAvaliable = false;
if ((dueDate != null && startDate != null && dueDate.before(startDate)) ||
(dueDate != null && startDate == null && dueDate.before(new Date()))) {
String dateError1 = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages","due_earlier_than_avaliable");
context.addMessage(null,new FacesMessage(FacesMessage.SEVERITY_WARN, dateError1, null));
error=true;
assessmentSettings.setStartDate(new Date());
}
if ((retractDate != null && startDate != null && retractDate.before(startDate)) ||
(retractDate != null && startDate == null && retractDate.before(new Date()))) {
String dateError2 = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages","retract_earlier_than_avaliable");
context.addMessage(null,new FacesMessage(FacesMessage.SEVERITY_WARN, dateError2, null));
error=true;
isRetractEarlierThanAvaliable = true;
assessmentSettings.setStartDate(new Date());
}
if (!isRetractEarlierThanAvaliable && (retractDate != null && dueDate != null && retractDate.before(dueDate))) {
String dateError3 = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages","retract_earlier_than_due");
context.addMessage(null,new FacesMessage(FacesMessage.SEVERITY_WARN, dateError3, null));
error=true;
}
// SAM-1088
// if late submissions not allowed and retract date is null, set retract date to due date
if (assessmentSettings.getLateHandling() != null && AssessmentAccessControlIfc.NOT_ACCEPT_LATE_SUBMISSION.toString().equals(assessmentSettings.getLateHandling()) &&
retractDate == null && dueDate != null && assessmentSettings.getAutoSubmit()) {
retractDate = dueDate;
assessmentSettings.setRetractDate(dueDate);
}
// if auto-submit is enabled, make sure retract date is set
if (assessmentSettings.getAutoSubmit() && retractDate == null) {
String autoSubmitEnabled = ServerConfigurationService.getString("samigo.autoSubmit.enabled");
if ("true".equalsIgnoreCase(autoSubmitEnabled)) {
String dateError4 = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages","retract_required_with_auto_submit");
context.addMessage(null,new FacesMessage(FacesMessage.SEVERITY_WARN, dateError4, null));
error=true;
}
}
if (!isFromActionSelect) {
if (assessmentSettings.getReleaseTo().equals(AssessmentAccessControl.RELEASE_TO_SELECTED_GROUPS)) {
String[] groupsAuthorized = assessmentSettings.getGroupsAuthorizedToSave(); //getGroupsAuthorized();
if (groupsAuthorized == null || groupsAuthorized.length == 0) {
String releaseGroupError = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.GeneralMessages","choose_one_group");
context.addMessage(null,new FacesMessage(releaseGroupError));
error=true;
assessmentSettings.setNoGroupSelectedError(true);
}
else {
assessmentSettings.setNoGroupSelectedError(false);
}
}
//#2c - validate if this is a time assessment, is there a time entry?
Object time=assessmentSettings.getValueMap().get("hasTimeAssessment");
boolean isTime=false;
if (time!=null) {
// Because different flow might get different type, we test it before cast.
if (time instanceof java.lang.String) {
isTime = Boolean.getBoolean((String) time);
}
else if (time instanceof java.lang.Boolean) {
isTime=((Boolean)time).booleanValue();
}
}
if ((isTime) &&((assessmentSettings.getTimeLimit().intValue())==0)){
String time_err=ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages","timeSelect_error");
context.addMessage(null,new FacesMessage(time_err));
error=true;
}
boolean ipErr=false;
String ipString = assessmentSettings.getIpAddresses().trim();
String[]arraysIp=(ipString.split("\n"));
//System.out.println("arraysIp.length: "+arraysIp.length);
for(int a=0;a<arraysIp.length;a++){
String currentString=arraysIp[a];
if(!currentString.trim().equals("")){
if(a<(arraysIp.length-1))
currentString=currentString.substring(0,currentString.length()-1);
if(!s.isIpValid(currentString)){
ipErr=true;
break;
}
}
}
if(ipErr){
error=true;
String ip_err=ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages","ip_error");
context.addMessage(null,new FacesMessage(ip_err));
}
String unlimitedSubmissions = assessmentSettings.getUnlimitedSubmissions();
if (unlimitedSubmissions != null && unlimitedSubmissions.equals(AssessmentAccessControlIfc.LIMITED_SUBMISSIONS.toString())) {
String submissionsAllowed = assessmentSettings.getSubmissionsAllowed().trim();
try {
int submissionAllowed = Integer.parseInt(submissionsAllowed);
if (submissionAllowed < 1) {
throw new RuntimeException();
}
}
catch (RuntimeException e){
error=true;
String submission_err = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages","submissions_allowed_error");
context.addMessage(null,new FacesMessage(submission_err));
}
}
String scoringType=assessmentSettings.getScoringType();
if ((scoringType).equals(EvaluationModelIfc.AVERAGE_SCORE.toString()) && "0".equals(assessmentSettings.getUnlimitedSubmissions())) {
try {
String submissionsAllowed = assessmentSettings.getSubmissionsAllowed().trim();
int submissionAllowed = Integer.parseInt(submissionsAllowed);
if (submissionAllowed < 2) {
throw new RuntimeException();
}
}
catch (RuntimeException e){
error=true;
String submission_err = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages","averag_grading_single_submission");
context.addMessage(null,new FacesMessage(submission_err));
}
}
//check feedback - if at specific time then time should be defined.
if((assessmentSettings.getFeedbackDelivery()).equals("2") && ((assessmentSettings.getFeedbackDateString()==null) || (assessmentSettings.getFeedbackDateString().equals("")))){
error=true;
String date_err=ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages","date_error");
context.addMessage(null,new FacesMessage(date_err));
}
}
else {
if (assessmentSettings.getReleaseTo().equals(AssessmentAccessControl.RELEASE_TO_SELECTED_GROUPS)) {
String[] groupsAuthorized = assessmentSettings.getGroupsAuthorized(); //populate groupsAuthorized;
if (groupsAuthorized == null || groupsAuthorized.length == 0) {
String releaseGroupError = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.GeneralMessages","choose_release_to");
context.addMessage(null,new FacesMessage(releaseGroupError));
error=true;
assessmentSettings.setNoGroupSelectedError(true);
}
else {
assessmentSettings.setNoGroupSelectedError(false);
}
}
}
//Gradebook right now only excep if total score >0 check if total score<=0 then throw error.
if(assessmentSettings.getToDefaultGradebook() != null && assessmentSettings.getToDefaultGradebook().equals("1"))
{
if(assessmentBean.getTotalScore()<=0)
{
String gb_err=(String)ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AuthorMessages", "gradebook_exception_min_points");
context.addMessage(null, new FacesMessage(gb_err));
error=true;
}
}
//#2b - check if gradebook exist, if so, if assessment title already exists in GB
GradebookExternalAssessmentService g = null;
if (integrated){
g = (GradebookExternalAssessmentService) SpringBeanLocator.getInstance().
getBean("org.sakaiproject.service.gradebook.GradebookExternalAssessmentService");
}
String toGradebook = assessmentSettings.getToDefaultGradebook();
try{
if (toGradebook!=null && toGradebook.equals(EvaluationModelIfc.TO_DEFAULT_GRADEBOOK.toString()) &&
gbsHelper.isAssignmentDefined(assessmentSettings.getTitle(), g)){
String gbConflict_err= ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages" , "gbConflict_error");
context.addMessage(null,new FacesMessage(gbConflict_err));
error=true;
}
}
catch(Exception e){
log.warn("external assessment in GB has the same title:"+e.getMessage());
}
if (!isFromActionSelect) {
// To convertFormattedTextToPlaintext for the fields that have been through convertPlaintextToFormattedTextNoHighUnicode
assessmentSettings.setTitle(FormattedText.convertFormattedTextToPlaintext(assessmentSettings.getTitle()));
assessmentSettings.setAuthors(FormattedText.convertFormattedTextToPlaintext(assessmentSettings.getAuthors()));
assessmentSettings.setFinalPageUrl(FormattedText.convertFormattedTextToPlaintext(assessmentSettings.getFinalPageUrl()));
assessmentSettings.setBgColor(FormattedText.convertFormattedTextToPlaintext(assessmentSettings.getBgColor()));
assessmentSettings.setBgImage(FormattedText.convertFormattedTextToPlaintext(assessmentSettings.getBgImage()));
assessmentSettings.setKeywords(FormattedText.convertFormattedTextToPlaintext(assessmentSettings.getKeywords()));
assessmentSettings.setObjectives(FormattedText.convertFormattedTextToPlaintext(assessmentSettings.getObjectives()));
assessmentSettings.setRubrics(FormattedText.convertFormattedTextToPlaintext(assessmentSettings.getRubrics()));
assessmentSettings.setUsername(FormattedText.convertFormattedTextToPlaintext(assessmentSettings.getUsername()));
assessmentSettings.setPassword(FormattedText.convertFormattedTextToPlaintext(assessmentSettings.getPassword()));
}
if (error){
assessmentSettings.setOutcomePublish("editAssessmentSettings");
author.setIsErrorInSettings(true);
return;
}
//#3 now u can proceed to save core assessment
if (!isFromActionSelect) {
assessment = s.save(assessmentSettings, true);
//unEscape the TextFormat.convertPlaintextToFormattedTextNoHighUnicode in s.save()
assessment.setTitle(FormattedText.convertFormattedTextToPlaintext(assessment.getTitle()));
assessmentSettings.setAssessment(assessment);
}
// we need a publishedUrl, this is the url used by anonymous user
String releaseTo = assessment.getAssessmentAccessControl().getReleaseTo();
if (releaseTo != null) {
// generate an alias to the pub assessment
String alias = AgentFacade.getAgentString() + (new Date()).getTime();
assessmentSettings.setAlias(alias);
//log.info("servletPath=" + extContext.getRequestServletPath());
String server = ( (javax.servlet.http.HttpServletRequest) extContext.
getRequest()).getRequestURL().toString();
int index = server.indexOf(extContext.getRequestContextPath() + "/"); // "/samigo-app/"
server = server.substring(0, index);
//log.info("servletPath=" + server);
String url = server + extContext.getRequestContextPath();
assessmentSettings.setPublishedUrl(url + "/servlet/Login?id=" + alias);
}
//#4 - before going to confirm publishing, check if the title is unique
PublishedAssessmentService publishedService = new PublishedAssessmentService();
if ( !publishedService.publishedAssessmentTitleIsUnique(assessmentId,assessmentName)){
String err=ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages","published_assessment_title_not_unique_error");
context.addMessage(null,new FacesMessage(err));
assessmentSettings.setOutcomePublish("editAssessmentSettings");
author.setIsErrorInSettings(true);
return;
}
//#4 - regenerate the core assessment list in autor bean again
// sortString can be of these value:title,releaseTo,dueDate,startDate
// get the managed bean, author and reset the list.
// Yes, we need to do that just in case the user change those delivery
// dates and turning an inactive pub to active pub and then go back to assessment list page
ArrayList assessmentList = assessmentService.getBasicInfoOfAllActiveAssessments(author.getCoreAssessmentOrderBy(),author.isCoreAscending());
// get the managed bean, author and set the list
author.setAssessments(assessmentList);
PublishRepublishNotificationBean publishRepublishNotification = (PublishRepublishNotificationBean) ContextUtil.lookupBean("publishRepublishNotification");
publishRepublishNotification.setSendNotification(false);
publishRepublishNotification.setPrePopulateText(ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages","pre_populate_text_publish"));
assessmentSettings.setOutcomePublish("saveSettingsAndConfirmPublish"); // finally goto confirm
SetFromPageAsAuthorSettingsListener setFromPageAsAuthorSettingsListener = new SetFromPageAsAuthorSettingsListener();
setFromPageAsAuthorSettingsListener.processAction(null);
}
public boolean passAuthz(FacesContext context, String ownerId){
AuthorizationBean authzBean = (AuthorizationBean) ContextUtil.lookupBean("authorization");
boolean hasPrivilege_any = authzBean.getPublishAnyAssessment();
boolean hasPrivilege_own0 = authzBean.getPublishOwnAssessment();
boolean hasPrivilege_own = (hasPrivilege_own0 && isOwner(ownerId));
boolean hasPrivilege = (hasPrivilege_any || hasPrivilege_own);
if (!hasPrivilege){
String err=(String)ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AuthorMessages",
"denied_publish_assessment_error");
context.addMessage(null,new FacesMessage(err));
}
return hasPrivilege;
}
public boolean isOwner(String ownerId){
boolean isOwner = false;
String agentId = AgentFacade.getAgentString();
isOwner = agentId.equals(ownerId);
return isOwner;
}
public void setIsFromActionSelect(boolean isFromActionSelect){
this.isFromActionSelect = isFromActionSelect;
}
}