Coverage Report - org.kuali.student.lum.lu.ui.course.client.controllers.CourseAdminController
 
Classes in this File Line Coverage Branch Coverage Complexity
CourseAdminController
0%
0/64
0%
0/18
1.846
CourseAdminController$1
0%
0/3
N/A
1.846
CourseAdminController$2
0%
0/3
N/A
1.846
CourseAdminController$3
0%
0/5
0%
0/2
1.846
CourseAdminController$3$1
0%
0/4
0%
0/2
1.846
CourseAdminController$4
0%
0/5
0%
0/2
1.846
CourseAdminController$5
0%
0/4
0%
0/2
1.846
CourseAdminController$5$1
0%
0/8
0%
0/2
1.846
CourseAdminController$6
0%
0/5
0%
0/2
1.846
CourseAdminController$7
0%
0/6
0%
0/2
1.846
CourseAdminController$8
0%
0/3
N/A
1.846
CourseAdminController$9
0%
0/3
N/A
1.846
CourseAdminController$9$1
0%
0/15
0%
0/10
1.846
 
 1  
 package org.kuali.student.lum.lu.ui.course.client.controllers;
 2  
 
 3  
 import java.util.ArrayList;
 4  
 import java.util.List;
 5  
 
 6  
 import org.kuali.student.common.assembly.data.Metadata;
 7  
 import org.kuali.student.common.assembly.data.QueryPath;
 8  
 import org.kuali.student.common.dto.DtoConstants;
 9  
 import org.kuali.student.common.ui.client.application.Application;
 10  
 import org.kuali.student.common.ui.client.application.ViewContext;
 11  
 import org.kuali.student.common.ui.client.configurable.mvc.FieldDescriptor;
 12  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.Section;
 13  
 import org.kuali.student.common.ui.client.configurable.mvc.views.VerticalSectionView;
 14  
 import org.kuali.student.common.ui.client.event.ActionEvent;
 15  
 import org.kuali.student.common.ui.client.event.SaveActionEvent;
 16  
 import org.kuali.student.common.ui.client.mvc.ActionCompleteCallback;
 17  
 import org.kuali.student.common.ui.client.mvc.Callback;
 18  
 import org.kuali.student.common.ui.client.mvc.DataModel;
 19  
 import org.kuali.student.common.ui.client.mvc.DataModelDefinition;
 20  
 import org.kuali.student.common.ui.client.mvc.ModelRequestCallback;
 21  
 import org.kuali.student.common.ui.client.util.WindowTitleUtils;
 22  
 import org.kuali.student.common.ui.client.widgets.KSButton;
 23  
 import org.kuali.student.common.ui.client.widgets.menus.KSMenuItemData;
 24  
 import org.kuali.student.common.ui.client.widgets.notification.KSNotification;
 25  
 import org.kuali.student.common.ui.client.widgets.notification.KSNotifier;
 26  
 import org.kuali.student.common.ui.shared.IdAttributes.IdType;
 27  
 import org.kuali.student.common.validation.dto.ValidationResultInfo;
 28  
 import org.kuali.student.core.workflow.ui.client.widgets.WorkflowUtilities;
 29  
 import org.kuali.student.lum.common.client.lu.LUUIConstants;
 30  
 import org.kuali.student.lum.common.client.widgets.AppLocations;
 31  
 import org.kuali.student.lum.lu.LUConstants;
 32  
 import org.kuali.student.lum.lu.assembly.data.client.constants.orch.CreditCourseConstants;
 33  
 import org.kuali.student.lum.lu.ui.course.client.configuration.CourseAdminConfigurer;
 34  
 import org.kuali.student.lum.lu.ui.course.client.configuration.CourseProposalConfigurer;
 35  
 import org.kuali.student.lum.lu.ui.course.client.configuration.CourseProposalConfigurer.CourseSections;
 36  
 
 37  
 import com.google.gwt.core.client.GWT;
 38  
 import com.google.gwt.event.dom.client.ClickEvent;
 39  
 import com.google.gwt.event.dom.client.ClickHandler;
 40  
 import com.google.gwt.user.client.DOM;
 41  
 import com.google.gwt.user.client.ui.Widget;
 42  
 
 43  
 /**
 44  
  * Controller for create/modify course with proposal wrapper admin screens. This controller uses a different
 45  
  * configurer for admin screens and attempts to reuse as much of the validation, save & retreive logic coded
 46  
  * in the CourseProposalController.  Also it reuses the menu from CourseProposalController and adds click
 47  
  * handlers to button menu to navigate user b/w sections of the same view.
 48  
  * 
 49  
  * @author Will
 50  
  *
 51  
  */
 52  0
 public class CourseAdminController extends CourseProposalController{
 53  
         
 54  
         //Need to keep track of cancel buttons, so they can be enabled when course has been saved. 
 55  0
         List<KSButton> cancelButtons = new ArrayList<KSButton>();
 56  
         
 57  
         /**
 58  
          * Override the intitailzeController method to use CourseAdminConfigurer 
 59  
          */
 60  
         @Override
 61  
         protected void initializeController() {
 62  
                    
 63  0
                 super.cfg = GWT.create(CourseAdminConfigurer.class);
 64  0
                 super.proposalPath = cfg.getProposalPath();
 65  0
                    super.workflowUtil = new WorkflowUtilities(CourseAdminController.this ,proposalPath);
 66  
                 
 67  0
                    cfg.setState(DtoConstants.STATE_DRAFT.toUpperCase());
 68  0
                    cfg.setNextState(DtoConstants.STATE_APPROVED.toUpperCase());
 69  0
                    super.setDefaultModelId(cfg.getModelId());
 70  0
                    super.registerModelsAndHandlers();
 71  0
                    super.addStyleName("ks-course-admin");
 72  0
                    currentDocType = LUConstants.PROPOSAL_TYPE_COURSE_CREATE_ADMIN;                           
 73  0
     }
 74  
 
 75  
         /**
 76  
          * Override the getSaveButton to provide a new set of buttons for the admin screens
 77  
          */
 78  
         @Override
 79  
         public KSButton getSaveButton(){
 80  0
                 KSButton saveButton = new KSButton("Save", new ClickHandler(){
 81  
             public void onClick(ClickEvent event) {
 82  0
                     handleButtonClick(DtoConstants.STATE_DRAFT);                    
 83  0
             }
 84  
         });                
 85  
                 
 86  0
                 saveButton.addStyleName("ks-button-spacing");
 87  0
                 return saveButton;
 88  
         }
 89  
                 
 90  
         public KSButton getApproveAndActivateButton(){
 91  0
                 return new KSButton("Approve and Activate", new ClickHandler(){
 92  
             public void onClick(ClickEvent event) {
 93  0
                     handleButtonClick(DtoConstants.STATE_ACTIVE);
 94  0
             }
 95  
         });                
 96  
         }
 97  
 
 98  
         public KSButton getCancelButton(){
 99  0
                 KSButton cancelButton = new KSButton("Cancel Proposal", new ClickHandler(){
 100  
             public void onClick(ClickEvent event) {
 101  0
                 if (isNew) {
 102  0
                     Application.navigate(AppLocations.Locations.CURRICULUM_MANAGEMENT.getLocation());
 103  
                 } else {
 104  
                     //Cancel the proposal and navigate the user back to curriculum home if cancel was successful.
 105  0
                     workflowUtil.cancel(new Callback<Boolean>() {
 106  
                         @Override
 107  
                         public void exec(Boolean result) {
 108  0
                             if (result) {
 109  0
                                 Application.navigate(AppLocations.Locations.CURRICULUM_MANAGEMENT.getLocation());
 110  
                             }
 111  0
                         }
 112  
 
 113  
                     });
 114  
                 }
 115  0
             }
 116  
         });
 117  
         
 118  0
                 cancelButton.addStyleName("ks-button-spacing");
 119  0
                 cancelButtons.add(cancelButton);
 120  0
                 return cancelButton;
 121  
     }
 122  
         
 123  
         /**
 124  
          * Processes the save, approve, or approve and activate button clicks. The action is determined
 125  
          * by the value of the state parameter.
 126  
          * 
 127  
          * @param state The state to set on the course when saving course data. DRAFT=Save, APPROVED=Approve, and
 128  
          * ACTIVE=Approve & Activate
 129  
          */
 130  
         protected void handleButtonClick(final String state){
 131  
                 
 132  
             //Set state on course before performing save action
 133  0
                 cluProposalModel.set(QueryPath.parse(CreditCourseConstants.STATE), state);
 134  
             
 135  0
             final SaveActionEvent saveActionEvent = getSaveActionEvent(state);
 136  
             
 137  
             //Store the rules if save was called
 138  0
             if((String)cluProposalModel.get(CreditCourseConstants.ID)!=null && cfg instanceof CourseAdminConfigurer){
 139  0
                     ((CourseAdminConfigurer )cfg).getRequisitesSection().storeRules(new Callback<Boolean>(){
 140  
                             public void exec(Boolean result) {
 141  0
                                         if(result){
 142  0
                                                 doAdminSaveAction(saveActionEvent, state);
 143  
                                         }else{
 144  0
                                                 KSNotifier.show("Error saving rules.");
 145  
                                         }
 146  0
                                 }
 147  
                     });
 148  
             }else{
 149  0
             doAdminSaveAction(saveActionEvent, state);                    
 150  
             }
 151  0
         }
 152  
                 
 153  
         /**
 154  
          * Returns a SaveActionEvent with the appropriate ActionCompleteCallback, which will take additional admin actions once
 155  
          * save is complete. The action (i.e. button clicked) is determined by the value of the state parameter 
 156  
          * 
 157  
          * @param state The state to set on the course when saving course data. DRAFT=Save, ACTIVE=Approve & Activate
 158  
          * @return the save event that will be fired based on the button click
 159  
          */
 160  
         private SaveActionEvent getSaveActionEvent(final String state){
 161  0
             final SaveActionEvent saveActionEvent = new SaveActionEvent(false);
 162  0
                 if (DtoConstants.STATE_ACTIVE.equalsIgnoreCase(state)){
 163  0
                     saveActionEvent.setActionCompleteCallback(new ActionCompleteCallback(){
 164  
                                 @Override
 165  
                                 public void onActionComplete(ActionEvent actionEvent) {
 166  0
                                         if (saveActionEvent.isSaveSuccessful()){
 167  0
                                                 workflowUtil.blanketApprove(new Callback<Boolean>(){
 168  
                                                         @Override
 169  
                                                         public void exec(Boolean result) {
 170  
                                                                 
 171  0
                                                                 final ViewContext viewContext = new ViewContext();
 172  0
                                                 viewContext.setId((String)cluProposalModel.get(CreditCourseConstants.ID));
 173  0
                                                 viewContext.setIdType(IdType.OBJECT_ID);                                                                                                                        
 174  0
                                                                 if (DtoConstants.STATE_ACTIVE.equalsIgnoreCase(state)){
 175  0
                                                                         KSNotifier.show("Course approved and activated. It may take a minute or two for course status to be updated. Refresh to see latest status.");
 176  0
                                                                         Application.navigate(AppLocations.Locations.VIEW_COURSE.getLocation(), viewContext);
 177  
                                                                 }
 178  
                                                                 
 179  0
                                                         }
 180  
                                                 });
 181  
                                         }      
 182  0
                                 }
 183  
                     });
 184  
             } else {
 185  
                     //User clicked Save button. When user clicks save, both document upload and cancel should be enabled
 186  0
                     saveActionEvent.setActionCompleteCallback(new ActionCompleteCallback(){
 187  
                                 @Override
 188  
                                 public void onActionComplete(ActionEvent action) {
 189  0
                                         for (KSButton cancelButton:cancelButtons){
 190  0
                                                 cancelButton.setEnabled(true);
 191  0
                                                 ((CourseAdminConfigurer )cfg).getDocumentTool().beforeShow(NO_OP_CALLBACK);
 192  
                                         }                                        
 193  0
                                 }                            
 194  
                     });
 195  
             }
 196  
                 
 197  0
                 return saveActionEvent;
 198  
         }
 199  
         
 200  
         /**
 201  
          * Fires the SaveActionEvent to be handled by the {@link CourseProposalController}. 
 202  
          * 
 203  
          *  @see CourseProposalController#registerModelsAndHandlers()
 204  
          *  @param saveActionEvent SaveActionEvent to fire
 205  
          *  @param state The state to set on the course when saving course data. DRAFT=Save, APPROVED=Approve, and
 206  
          *  ACTIVE=Approve & Activate
 207  
          */
 208  
         private void doAdminSaveAction(final SaveActionEvent saveActionEvent, String state){
 209  0
                 if (DtoConstants.STATE_APPROVED.equalsIgnoreCase(state) || DtoConstants.STATE_ACTIVE.equalsIgnoreCase(state)){
 210  
                         //For Approved action, validate required fields for next (i.e.Approved) state before firing the save action
 211  0
                         cluProposalModel.validateNextState((new Callback<List<ValidationResultInfo>>() {
 212  
                     @Override
 213  
                     public void exec(List<ValidationResultInfo> result) {
 214  
         
 215  0
                             boolean isSectionValid = isValid(result, true);
 216  
         
 217  0
                             if(isSectionValid){
 218  0
                                     CourseAdminController.this.fireApplicationEvent(saveActionEvent);                    }
 219  
                             else{
 220  0
                                     KSNotifier.add(new KSNotification("Unable to save, please check fields for errors.", false, true, 5000));
 221  
                             }
 222  
         
 223  0
                     }
 224  
                 }));
 225  
                 } else {
 226  0
                     CourseAdminController.this.fireApplicationEvent(saveActionEvent);                        
 227  
                 }                 
 228  0
         }
 229  
         
 230  
         /**
 231  
          * 
 232  
          * Override {@link CourseProposalController} because end term should always be editable 
 233  
          * in admin screens.
 234  
          */
 235  
         protected void progressiveEnableFields(){
 236  
             //Do nothing, the end term should always be editable on admin screens.
 237  0
         }
 238  
         
 239  
         /**
 240  
      * Override the setHeaderTitle to display proper header title for admin screens
 241  
      */
 242  
         @Override
 243  
         protected void setHeaderTitle(){
 244  
             String title;
 245  0
             if (cluProposalModel.get(cfg.getProposalTitlePath()) != null){
 246  0
                     title = getProposalTitle();
 247  
             }
 248  
             else{
 249  0
                     title = "New Course (Admin Proposal)";
 250  
             }
 251  0
             this.setContentTitle(title);
 252  0
             this.setName(title);
 253  0
             WindowTitleUtils.setContextTitle(title);
 254  0
                 currentTitle = title;
 255  0
     }
 256  
     
 257  
         private String getProposalTitle(){
 258  0
                 StringBuffer sb = new StringBuffer();
 259  0
                 sb.append(cluProposalModel.get(cfg.getProposalTitlePath()));
 260  0
                 sb.append(" (Admin Proposal)");
 261  0
                 return sb.toString();
 262  
         }
 263  
         
 264  
         /**
 265  
          * This is a special method for CourseAdminController, which adds a menu item to the navigation menu and navigates
 266  
          * a user to a section within the view rather than a different view.
 267  
          * 
 268  
          * @param parentMenu
 269  
          * @param sectionName
 270  
          * @param sectionId
 271  
          * @param section
 272  
          */
 273  
     public void addMenuItemSection(String parentMenu, final String sectionName, final String widgetId, final Widget widget) {            
 274  0
         KSMenuItemData parentItem = null;
 275  0
         for (int i = 0; i < topLevelMenuItems.size(); i++) {
 276  0
             if (topLevelMenuItems.get(i).getLabel().equals(parentMenu)) {
 277  0
                 parentItem = topLevelMenuItems.get(i);
 278  0
                 break;
 279  
             }
 280  
         }
 281  
 
 282  0
         KSMenuItemData item = new KSMenuItemData(sectionName);
 283  0
             widget.getElement().setId(widgetId);
 284  0
             item.setClickHandler(new ClickHandler(){
 285  
                         public void onClick(ClickEvent event) {                
 286  
                                 //FIXME: This doesn't scroll to exactly the position stuff
 287  0
                                 DOM.getElementById(widgetId).scrollIntoView();
 288  0
                         }                    
 289  
             });
 290  
 
 291  0
         if (parentItem != null) {
 292  0
             parentItem.addSubItem(item);
 293  
         } else {
 294  0
             topLevelMenuItems.add(item);
 295  
         }
 296  
 
 297  0
         menu.refresh();
 298  0
     }
 299  
 
 300  
         @Override
 301  
         protected void configureScreens(DataModelDefinition modelDefinition, final Callback<Boolean> onReadyCallback) {
 302  0
                 super.configureScreens(modelDefinition, previousEndTermConfigurationCallback(onReadyCallback));
 303  0
         }
 304  
 
 305  
         /**
 306  
          * This callback is used to configure the previous end term field after the screens have been configured.
 307  
          * 
 308  
          * @param onReadyCallback
 309  
          * @return
 310  
          */
 311  
         protected Callback<Boolean> previousEndTermConfigurationCallback(final Callback<Boolean> onReadyCallback){
 312  0
                 return new Callback<Boolean>(){
 313  
 
 314  
                         @Override
 315  
                         public void exec(final Boolean result) {
 316  0
                                 requestModel(new ModelRequestCallback<DataModel>(){
 317  
                                         @Override
 318  
                                         public void onModelReady(DataModel model) {
 319  
                                                 //In admin screens add the previous end term field to the active dates section and update it's values   
 320  
                                                 //ONLY when in edit mode. This way it doesn't attempt to retrieve non-existent "Course Info" section;
 321  
                                                 //only the "Summary" section has been configured in non-edit mode.
 322  0
                                                 if (model.getDefinition().getMetadata().isCanEdit()){
 323  0
                                                         String versionedFromId = model.get("versionInfo/versionedFromId");
 324  0
                                                         if(versionedFromId!=null && !versionedFromId.isEmpty()){
 325  
                                                                 //Add the required field 
 326  
                                                                 //See why the required for next state is not set
 327  0
                                                                 VerticalSectionView view = (VerticalSectionView) viewMap.get(CourseSections.COURSE_INFO);                                                        
 328  0
                                                                 Section activeDatesSection = view.getSection(LUUIConstants.ACTIVE_DATES_LABEL_KEY);
 329  0
                                                                 Metadata meta = cfg.getModelDefinition().getMetadata(CourseProposalConfigurer.PROPOSAL_PATH + "/" + CreditCourseConstants.PREV_END_TERM);
 330  0
                                                                 if(meta!=null&&meta.getConstraints().get(0)!=null){
 331  0
                                                                         meta.getConstraints().get(0).setRequiredForNextState(true);
 332  0
                                                                         meta.getConstraints().get(0).setNextState("ACTIVE");
 333  
                                                                 }
 334  0
                                                                 FieldDescriptor fd = cfg.addField(activeDatesSection, CourseProposalConfigurer.PROPOSAL_PATH + "/" + CreditCourseConstants.PREV_END_TERM, cfg.generateMessageInfo(LUUIConstants.PROPOSAL_PREV_END_TERM));
 335  
                                                                 
 336  
                                                                 //FIXME: This static method should not live in WorkflowUtilities
 337  0
                                                                 WorkflowUtilities.updateCrossField(fd, model);
 338  
                                                         }
 339  
                                                 }
 340  
                                                 
 341  0
                                                 onReadyCallback.exec(result);
 342  0
                                         }
 343  
                                         
 344  
                                         @Override
 345  
                                         public void onRequestFail(Throwable cause) {
 346  0
                                                 throw new RuntimeException("Error getting model",cause);
 347  
                                         }
 348  
                                 });
 349  0
                         }
 350  
                 };
 351  
         }
 352  
 }
 353