Coverage Report - org.kuali.student.lum.program.client.major.view.MajorViewController
 
Classes in this File Line Coverage Branch Coverage Complexity
MajorViewController
0%
0/91
0%
0/24
2.154
MajorViewController$1
0%
0/7
0%
0/4
2.154
MajorViewController$10
0%
0/4
0%
0/2
2.154
MajorViewController$11
0%
0/6
0%
0/2
2.154
MajorViewController$2
0%
0/3
N/A
2.154
MajorViewController$3
0%
0/12
0%
0/4
2.154
MajorViewController$4
0%
0/8
0%
0/4
2.154
MajorViewController$5
0%
0/3
N/A
2.154
MajorViewController$6
0%
0/5
0%
0/2
2.154
MajorViewController$7
0%
0/4
0%
0/2
2.154
MajorViewController$8
0%
0/12
0%
0/8
2.154
MajorViewController$9
0%
0/6
0%
0/2
2.154
MajorViewController$9$1
0%
0/5
0%
0/2
2.154
 
 1  
 package org.kuali.student.lum.program.client.major.view;
 2  
 
 3  
 
 4  
 
 5  
 import org.kuali.student.common.assembly.data.Data;
 6  
 import org.kuali.student.common.assembly.data.Data.Property;
 7  
 import org.kuali.student.common.rice.authorization.PermissionType;
 8  
 import org.kuali.student.common.ui.client.application.Application;
 9  
 import org.kuali.student.common.ui.client.application.KSAsyncCallback;
 10  
 import org.kuali.student.common.ui.client.application.ViewContext;
 11  
 import org.kuali.student.common.ui.client.mvc.Callback;
 12  
 import org.kuali.student.common.ui.client.mvc.DataModel;
 13  
 import org.kuali.student.common.ui.client.mvc.history.HistoryManager;
 14  
 import org.kuali.student.common.ui.client.security.AuthorizationCallback;
 15  
 import org.kuali.student.common.ui.client.security.RequiresAuthorization;
 16  
 import org.kuali.student.common.ui.client.security.SecurityContext;
 17  
 import org.kuali.student.common.ui.client.widgets.KSButton;
 18  
 import org.kuali.student.common.ui.client.widgets.KSCheckBox;
 19  
 import org.kuali.student.common.ui.client.widgets.KSLabel;
 20  
 import org.kuali.student.common.ui.client.widgets.KSLightBox;
 21  
 import org.kuali.student.common.ui.client.widgets.KSRadioButton;
 22  
 import org.kuali.student.common.ui.shared.IdAttributes;
 23  
 import org.kuali.student.common.ui.shared.IdAttributes.IdType;
 24  
 import org.kuali.student.lum.common.client.lu.LUUIPermissions;
 25  
 import org.kuali.student.lum.common.client.widgets.AppLocations;
 26  
 import org.kuali.student.lum.common.client.widgets.DropdownList;
 27  
 import org.kuali.student.lum.program.client.ProgramConstants;
 28  
 import org.kuali.student.lum.program.client.ProgramRegistry;
 29  
 import org.kuali.student.lum.program.client.ProgramSections;
 30  
 import org.kuali.student.lum.program.client.ProgramStatus;
 31  
 import org.kuali.student.lum.program.client.events.ModelLoadedEvent;
 32  
 import org.kuali.student.lum.program.client.events.ProgramViewEvent;
 33  
 import org.kuali.student.lum.program.client.major.ActionType;
 34  
 import org.kuali.student.lum.program.client.major.MajorController;
 35  
 
 36  
 import com.google.gwt.core.client.GWT;
 37  
 import com.google.gwt.event.dom.client.ChangeEvent;
 38  
 import com.google.gwt.event.dom.client.ChangeHandler;
 39  
 import com.google.gwt.event.dom.client.ClickEvent;
 40  
 import com.google.gwt.event.dom.client.ClickHandler;
 41  
 import com.google.gwt.event.logical.shared.ValueChangeEvent;
 42  
 import com.google.gwt.event.logical.shared.ValueChangeHandler;
 43  
 import com.google.gwt.event.shared.HandlerManager;
 44  
 import com.google.gwt.user.client.ui.Anchor;
 45  
 import com.google.gwt.user.client.ui.VerticalPanel;
 46  
 
 47  
 
 48  0
 public class MajorViewController extends MajorController implements RequiresAuthorization{
 49  
 
 50  
     // TODO: Change to program and copy msgs
 51  
     private static final String MSG_GROUP = "program";
 52  
     
 53  
     /**
 54  
      * Initialize the action drop-down with a list of values.  Note that these values
 55  
      * will be changed further down in the code depending on if we are working with the latest 
 56  
      * version of the program.
 57  
      */
 58  0
     private final DropdownList actionBox = new DropdownList(ActionType.getValuesForMajorDiscipline(false));
 59  
  
 60  
     // Used to pass flag if this is the latest version of the program from
 61  
     // an async call to the light box so we can conditionally decided
 62  
     // to display the use curriculum review process checkbox
 63  
     private boolean isCurrentVersion;
 64  
     
 65  
     /**
 66  
      * Constructor.
 67  
      *
 68  
      * @param programModel
 69  
      */
 70  
     public MajorViewController(DataModel programModel, ViewContext viewContext, HandlerManager eventBus) {
 71  0
         super(programModel, viewContext, eventBus);
 72  0
         configurer = GWT.create(MajorViewConfigurer.class);  
 73  
         
 74  
         // Initialize handlers and action drop-down
 75  0
         initHandlers();
 76  0
      }
 77  
  
 78  
     private void initHandlers() {
 79  
         
 80  
         /*
 81  
          * Action drop-down box on-change
 82  
          */
 83  0
         actionBox.addChangeHandler(new ChangeHandler() {
 84  
             @Override
 85  
             public void onChange(ChangeEvent event) {
 86  
                 
 87  
                 // Get the action selected in the drop-down
 88  0
                 ActionType actionType = ActionType.of(actionBox.getSelectedValue());
 89  0
                 ViewContext viewContext = getViewContext();
 90  
                 
 91  
                 // If modify is selected
 92  0
                 if (actionType == ActionType.MODIFY) {
 93  0
                     processModifyActionType(viewContext);
 94  
                 }
 95  
                 // If retire is selected
 96  0
                 else if (actionType == ActionType.RETIRE) {
 97  
                     // TODO: retire is not implemented yet for program
 98  
                 }
 99  0
             }
 100  
         });
 101  
         /*
 102  
          * Initial value selected in action drop-down
 103  
          */
 104  0
         eventBus.addHandler(ProgramViewEvent.TYPE, new ProgramViewEvent.Handler() {
 105  
             @Override
 106  
             public void onEvent(ProgramViewEvent event) {
 107  0
                 actionBox.setSelectedIndex(0);
 108  0
             }
 109  
         });
 110  
         
 111  
         /* 
 112  
          * Code executed right after model is loaded from service
 113  
          */
 114  0
         eventBus.addHandler(ModelLoadedEvent.TYPE, new ModelLoadedEvent.Handler() {
 115  
             @Override
 116  
             public void onEvent(ModelLoadedEvent event) {
 117  
                 
 118  
                 /*
 119  
                  * Reload values in the drop-down if the data model changes
 120  
                  * since we may have loaded a different version
 121  
                  */
 122  0
                 resetActionList();
 123  
                  
 124  0
                 String type = context.getAttributes().get(ProgramConstants.TYPE);
 125  0
                 if (type != null) {
 126  0
                     context.getAttributes().remove(ProgramConstants.TYPE);
 127  0
                     if (type.equals(ProgramConstants.VARIATION_TYPE_KEY)) {
 128  0
                         showVariationView();
 129  
                     } else {
 130  
                             //Take out the vairationId if it exists for cleaner navigation
 131  0
                             context.getAttributes().remove(ProgramConstants.VARIATION_ID);
 132  0
                         showView(ProgramSections.VIEW_ALL);
 133  
                     }
 134  
                 } else {
 135  0
                         context.getAttributes().remove(ProgramConstants.VARIATION_ID);
 136  0
                     showView(ProgramSections.VIEW_ALL);
 137  
                 }
 138  0
             }
 139  
         });
 140  0
     }
 141  
 
 142  
     /**
 143  
      * 
 144  
      * This method process the modify a program action that was selected. A permission
 145  
      * check is done to see if the modify program lightbox shoudl be presented to the
 146  
      * user.
 147  
      * 
 148  
      * The modify programl lightbox is only shown to the admin role.
 149  
      * 
 150  
      * @param viewContext
 151  
      */
 152  
     private void processModifyActionType(final ViewContext viewContext) {
 153  0
             SecurityContext securityContext = Application.getApplicationContext().getSecurityContext(); 
 154  
             
 155  0
             securityContext.checkPermission("useCurriculumReview", new Callback<Boolean>() {
 156  
             @Override
 157  
             public void exec(Boolean result) {
 158  0
                 final boolean isAuthorized = result;
 159  
 
 160  
                 // Show the modify program light box only for admin role.
 161  0
                 if (isAuthorized) {
 162  0
                     buildModifyDialog(viewContext, "/HOME/CURRICULUM_HOME/COURSE_PROPOSAL", programModel);
 163  
                 } else {
 164  0
                     if (isProgramStatusValidForProposal()) {
 165  0
                         showModifyProgramWithNewVersionCurriculumReviewView();
 166  
                     } else {
 167  0
                         showModifyProgramWithoutVersionView(viewContext);
 168  
                     }
 169  
                 }
 170  0
             }
 171  
         });
 172  0
     }
 173  
 
 174  
     /**
 175  
      * 
 176  
      * This method builds the light box that appears when you choose to modify a program.
 177  
      * 
 178  
      * @param viewContext
 179  
      * @param modifyPath
 180  
      * @param model
 181  
      */
 182  
     private void buildModifyDialog(final ViewContext viewContext, final String modifyPath, final DataModel model){
 183  0
         final KSLightBox modifyDialog = new KSLightBox();
 184  
         
 185  
         //Create a dialog for course selection
 186  0
         modifyDialog.setTitle((getMessage("modifyProgramSubTitle")));
 187  
 
 188  0
         final VerticalPanel layout = new VerticalPanel();
 189  0
         layout.addStyleName("ks-form-module-fields");
 190  
                 
 191  0
         final KSButton continueButton = new KSButton(getMessage("continue"));
 192  
         
 193  0
         modifyDialog.addButton(continueButton);
 194  0
         Anchor cancelLink = new Anchor("Cancel");
 195  
        
 196  
         // Cancel should just close the dialog
 197  0
         cancelLink.addClickHandler(new ClickHandler(){
 198  
             public void onClick(ClickEvent event) {
 199  0
                 modifyDialog.hide();
 200  0
             }
 201  
         });
 202  0
         modifyDialog.addButton(cancelLink);
 203  
         
 204  
         //HorizontalPanel titlePanel = new HorizontalPanel();
 205  0
         KSLabel titleLabel = new KSLabel(getMessage("modifyProgramSubTitle"));
 206  0
         titleLabel.addStyleName("bold");
 207  0
         modifyDialog.setNonCaptionHeader(titleLabel);
 208  
         //titlePanel.add(titleLabel);
 209  
         
 210  
         //layout.add(titlePanel);
 211  
         
 212  0
         final KSRadioButton radioOptionModifyNoVersion = new KSRadioButton("modifyCreditProgramButtonGroup", getMessage("modifyProgramNoVersion"));
 213  0
         final KSRadioButton radioOptionModifyWithVersion = new KSRadioButton("modifyCreditProgramButtonGroup", getMessage("modifyProgramWithVersion"));
 214  0
         final KSCheckBox curriculumReviewOption = new KSCheckBox(getMessage("useCurriculumReview"));
 215  
         
 216  
         
 217  0
         radioOptionModifyNoVersion.addValueChangeHandler(new ValueChangeHandler<Boolean>(){
 218  
             public void onValueChange(ValueChangeEvent<Boolean> event) {
 219  0
                 if(event.getValue()){
 220  0
                     curriculumReviewOption.setEnabled(false);
 221  0
                     curriculumReviewOption.setValue(false);
 222  
                 }
 223  0
             }
 224  
         });
 225  0
         radioOptionModifyNoVersion.setValue(true);
 226  
         
 227  
 
 228  0
         curriculumReviewOption.setEnabled(false);
 229  
         
 230  0
         radioOptionModifyWithVersion.addValueChangeHandler(new ValueChangeHandler<Boolean>(){
 231  
             public void onValueChange(ValueChangeEvent<Boolean> event) {
 232  0
                 if(event.getValue()){
 233  0
                     curriculumReviewOption.setEnabled(true);
 234  
                 }
 235  0
             }
 236  
         });
 237  
         
 238  
         /*
 239  
          * Continue button clicked.
 240  
          */
 241  0
         continueButton.addClickHandler(new ClickHandler(){
 242  
             @Override
 243  
             public void onClick(ClickEvent event) {
 244  0
                  if (radioOptionModifyNoVersion.getValue()){
 245  
                     // If modify w/out version radio button is chosen 
 246  
                     // we just edit the program.  We do not create a copy.
 247  
                     // We navigate to the edit program controller
 248  0
                      showModifyProgramWithoutVersionView(viewContext);
 249  0
                  } else if (radioOptionModifyWithVersion.getValue() && curriculumReviewOption.getValue()){
 250  
                     // If the curriculum review option IS checked and the modify with version radio button IS selected
 251  
                     // We need to create a copy of the program (by passing in COPY_OF_OBJECT_ID)
 252  
                     // and then transfer control to the proposal controller (the proposal controller has
 253  
                     // extra section for entering proposal related data
 254  0
                     showModifyProgramWithNewVersionCurriculumReviewView();
 255  0
                  } else if (radioOptionModifyWithVersion.getValue()){
 256  
                     // If we are just choosing to modify a program but want to create a new version
 257  
                     // AND we are not using the proposal process
 258  
                     // We make a copy of the data model and transfer control
 259  
                     // to the edit program screen
 260  
                      
 261  
                      // Pass the ID and the type to the proposal controller
 262  
                      // using the view context.  We then read it in the
 263  
                      // setViewContext method and use it to initialize the
 264  
                      // work flow utilities
 265  
     
 266  0
                      String versionIndId = getStringProperty(ProgramConstants.VERSION_IND_ID);
 267  0
                      viewContext.setId(versionIndId);
 268  0
                      viewContext.setIdType(IdType.COPY_OF_OBJECT_ID);
 269  
           
 270  
                      //ProgramRegistry.setSection(ProgramSections.getEditSection(getCurrentViewEnum()));
 271  0
                      HistoryManager.navigate(AppLocations.Locations.EDIT_PROGRAM.getLocation(), viewContext);
 272  
                 }   
 273  
                 
 274  
                 // Hide dialog after clicking
 275  0
                 modifyDialog.hide();
 276  0
             }           
 277  
         });
 278  
         
 279  
         //Check that this is the latest version with an async call and only show modify with version options if it is the latest
 280  
        
 281  0
         layout.add(radioOptionModifyNoVersion);
 282  
  
 283  
         // the curriculum review check box implements "modify by proposal"
 284  
         // a user can only check the box when the program state is active, retired, or approved (it must be the latest version when in these states)
 285  
         // See https://wiki.kuali.org/display/KULSTG/Course%2C+Proposal%2C+and+Program+Action+Dropdown+Items
 286  0
         if (isProgramStatusValidForProposal()) {
 287  0
             layout.add(radioOptionModifyWithVersion);
 288  0
             layout.add(curriculumReviewOption);
 289  
         }
 290  
         
 291  0
         modifyDialog.setWidget(layout);
 292  0
         modifyDialog.show();
 293  0
     } 
 294  
  
 295  
     /**
 296  
      * 
 297  
      * This method checks if the program state is active, retired, or approved (it must be
 298  
      * the latest version when in these states)
 299  
      * 
 300  
      * @return
 301  
      */
 302  
     private boolean isProgramStatusValidForProposal() {
 303  0
         ProgramStatus status = ProgramStatus.of(programModel);
 304  
 
 305  0
         if (isCurrentVersion
 306  
                 && (status == ProgramStatus.ACTIVE || status == ProgramStatus.APPROVED || status == ProgramStatus.ACTIVE)) {
 307  0
             return true;
 308  
         }
 309  
 
 310  0
         return false;
 311  
     }
 312  
     
 313  
     /**
 314  
      * 
 315  
      * This method will grab a message based on a key.
 316  
      * 
 317  
      * @param courseMessageKey
 318  
      * @return
 319  
      */
 320  
     public String getMessage(String programMessageKey) {
 321  0
         String msg = Application.getApplicationContext().getMessage(MSG_GROUP, programMessageKey);
 322  0
         if (msg == null) {
 323  0
             msg = programMessageKey;
 324  
         }
 325  0
         return msg;
 326  
     }   
 327  
     
 328  
     /**
 329  
      * 
 330  
      * This method will set the values in the action list drop-down.
 331  
      *
 332  
      */
 333  
     protected void resetActionList() {
 334  
             
 335  
         // Get the current state of the program (SUPERSEDED, ACTIVE, APPROVED, DRAFT)
 336  0
             ProgramStatus status = ProgramStatus.of(programModel);
 337  
             
 338  
             // Get the version independent indicator
 339  0
         String versionIndId = getStringProperty(ProgramConstants.VERSION_IND_ID);
 340  
         
 341  
         // The the version sequence number
 342  0
         Long sequenceNumber = programModel.get(ProgramConstants.VERSION_SEQUENCE_NUMBER);
 343  
                
 344  
         // Clear the drop-down list and prepare to populate it with values
 345  0
         actionBox.clear();
 346  
   
 347  
         // Call the server to see if this is the latest version of the program
 348  
         // and update the drop-down accordingly
 349  0
             programRemoteService.isLatestVersion(versionIndId, sequenceNumber, new KSAsyncCallback<Boolean>(){
 350  
                         public void onSuccess(Boolean isLatest) {
 351  
                          
 352  
                             // TODO PLEASE REVIEW.  Should we be passing values from async calls to light boxes
 353  
                             // using instance variables like this? (we are doing this in course as well)
 354  0
                             isCurrentVersion = isLatest;
 355  
                             
 356  
                             // Populate the action box drop-down with different values depending 
 357  
                             // on if we are working with the latest version of the program 
 358  
                             // or a historical version
 359  0
                 actionBox.setList(ActionType.getValuesForMajorDiscipline(isLatest));
 360  
 
 361  0
                 if (!isCurrentVersion) {
 362  0
                     Application.getApplicationContext().getSecurityContext().checkPermission("useCurriculumReview", new Callback<Boolean>() {
 363  
                         @Override
 364  
                         public void exec(Boolean result) {
 365  0
                             final boolean isAuthorized = result;
 366  
 
 367  0
                             if (!isAuthorized) {
 368  0
                                 actionBox.removeItem(ActionType.MODIFY.getValue());
 369  
                             }
 370  0
                         }
 371  
                     });
 372  
                 }
 373  
 
 374  0
                          }                
 375  
         });
 376  
             
 377  
            
 378  
             // Get the reference ID of the proposal from the XML model
 379  
             // Note: the filter puts in in the model, see ProposalWorkflowFilter.applyOutboundDataFilter
 380  0
             String referenceId = programModel.getRoot().get("id");
 381  
             
 382  
             // When the program being viewed is in DRAFT state, check to see if it exists as part of program proposal instead of admin modify. 
 383  
             // If its part of a program proposal then we don't want to display the program actions drop down since user is not allowed to take
 384  
             // any actions on a DRAFT program proposal outside of proposal process.
 385  
             // TODO PLEASE REVIEW.  If this async call runs slow, will the box remain visible? Is this an issue?
 386  
             //      Answer: Yes, it might be an issue, possible solution might to block user action w/progress bar until finished.            
 387  0
         if (status == ProgramStatus.DRAFT){
 388  0
                     programRemoteService.isProposal( "kuali.proposal.referenceType.clu", referenceId,  new KSAsyncCallback<Boolean>(){
 389  
                     public void onSuccess(Boolean isProposal) {
 390  
                      
 391  
                         // If this is a proposal then we cannot take any actions on it
 392  
                         // So hide the action box
 393  0
                         if (isProposal){
 394  0
                             actionBox.setVisible(false);
 395  
                         }
 396  
                       
 397  0
                     }           
 398  
                 });
 399  
         }
 400  0
     } 
 401  
   
 402  
     private void showVariationView() {
 403  0
         String variationId = context.getAttributes().get(ProgramConstants.VARIATION_ID);
 404  0
         if (variationId != null) {
 405  0
             final Data variationMap = getDataProperty(ProgramConstants.VARIATIONS);
 406  0
             if (variationMap != null) {
 407  0
                 int row = 0;
 408  0
                 for (Property p : variationMap) {
 409  0
                     final Data variationData = p.getValue();
 410  0
                     if (variationData != null) {
 411  0
                         if (variationData.get(ProgramConstants.ID).equals(variationId)) {
 412  
                             //FIXME: Find a better way to do this.
 413  
                             // We shouldn't be maintaining two separate datamodels for progs and variations
 414  0
                             Data credData = getDataProperty(ProgramConstants.CREDENTIAL_PROGRAM);
 415  0
                             variationData.set(ProgramConstants.CREDENTIAL_PROGRAM, credData);
 416  0
                             ProgramRegistry.setData(variationData);
 417  0
                             ProgramRegistry.setRow(row);
 418  
                         }
 419  0
                         row++;
 420  
                     }
 421  0
                 }
 422  0
                 HistoryManager.navigate(AppLocations.Locations.VIEW_VARIATION.getLocation(), context);
 423  
             }
 424  
         }
 425  0
     }
 426  
 
 427  
     @Override
 428  
     protected void configureView() {
 429  0
         super.configureView();
 430  0
         addContentWidget(actionBox);
 431  0
         initialized = true;
 432  0
     }
 433  
 
 434  
     /**
 435  
      * 
 436  
      * This method navigates to the edit program controller.
 437  
      * 
 438  
      * @param viewContext
 439  
      */
 440  
     private void showModifyProgramWithoutVersionView(final ViewContext viewContext) {
 441  0
         ProgramRegistry.setSection(ProgramSections.getEditSection(getCurrentViewEnum()));
 442  0
          HistoryManager.navigate(AppLocations.Locations.EDIT_PROGRAM.getLocation(), viewContext);
 443  0
     }
 444  
 
 445  
     /**
 446  
      * 
 447  
      * This method transfers control to the proposal controller.
 448  
      * 
 449  
      */
 450  
     private void showModifyProgramWithNewVersionCurriculumReviewView() {
 451  0
         String versionIndId = getStringProperty(ProgramConstants.VERSION_IND_ID);
 452  
  
 453  
         // Pass the ID and the type to the proposal controller
 454  
         // using the view context.  We then read it in the
 455  
         // setViewContext method and use it to initialize the
 456  
         // work flow utilities
 457  0
         final ViewContext viewContext = new ViewContext();
 458  0
         viewContext.setId(versionIndId);
 459  0
         viewContext.setIdType(IdAttributes.IdType.COPY_OF_OBJECT_ID); 
 460  0
         Application.navigate(AppLocations.Locations.PROGRAM_PROPOSAL.getLocation(), viewContext);
 461  0
     }
 462  
     
 463  
     @Override
 464  
         public boolean isAuthorizationRequired() {
 465  0
                 return true;
 466  
         }
 467  
 
 468  
         @Override
 469  
         public void setAuthorizationRequired(boolean required) {
 470  0
                 throw new UnsupportedOperationException();
 471  
         }
 472  
         
 473  
         @Override
 474  
         public void checkAuthorization(final AuthorizationCallback authCallback) {
 475  0
                 Application.getApplicationContext().getSecurityContext().checkScreenPermission(LUUIPermissions.USE_FIND_PROGRAM_SCREEN, new Callback<Boolean>() {
 476  
                         @Override
 477  
                         public void exec(Boolean result) {
 478  
 
 479  0
                                 final boolean isAuthorized = result;
 480  
                 
 481  0
                                 if(isAuthorized){
 482  0
                                         authCallback.isAuthorized();
 483  
                                 }
 484  
                                 else
 485  0
                                         authCallback.isNotAuthorized("User is not authorized: " + LUUIPermissions.USE_FIND_PROGRAM_SCREEN);
 486  0
                         }        
 487  
                 });
 488  0
         }
 489  
 }