View Javadoc

1   package org.kuali.student.enrollment.main.view;
2   
3   import org.apache.commons.lang.StringUtils;
4   import org.kuali.rice.kim.api.KimConstants;
5   import org.kuali.rice.kim.api.identity.Person;
6   import org.kuali.rice.krad.messages.MessageService;
7   import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
8   import org.kuali.rice.krad.uif.UifParameters;
9   import org.kuali.rice.krad.uif.component.Component;
10  import org.kuali.rice.krad.uif.component.ComponentSecurity;
11  import org.kuali.rice.krad.uif.container.Group;
12  import org.kuali.rice.krad.uif.element.Action;
13  import org.kuali.rice.krad.uif.field.Field;
14  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
15  import org.kuali.rice.krad.uif.view.View;
16  import org.kuali.rice.krad.uif.view.ViewAuthorizerBase;
17  import org.kuali.rice.krad.uif.view.ViewModel;
18  import org.kuali.rice.krad.uif.widget.Widget;
19  import org.kuali.rice.krad.util.GlobalVariables;
20  import org.kuali.student.enrollment.class2.autogen.form.ARGCourseOfferingManagementForm;
21  import org.kuali.student.enrollment.class2.courseoffering.dto.ActivityOfferingWrapper;
22  import org.kuali.student.enrollment.class2.courseoffering.dto.CourseOfferingListSectionWrapper;
23  import org.kuali.student.enrollment.class2.courseoffering.form.CourseOfferingManagementForm;
24  import org.kuali.student.enrollment.class2.courseoffering.form.RegistrationGroupManagementForm;
25  
26  import java.util.Collection;
27  import java.util.Date;
28  import java.util.HashMap;
29  import java.util.List;
30  import java.util.Map;
31  
32  /**
33   * Custom Authorizer that resolves qualifiers from the model. This will need to be refactored and made more generic in
34   * the future (configuration of mapping from model object graph to role qualifiers, maybe using beanutils
35   * (object.field1[3].field2->qualifierId)
36   */
37  public class KsViewAuthorizerBase extends ViewAuthorizerBase {
38      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KsViewAuthorizerBase.class);
39  
40      protected MessageService messageService = null;
41  
42      @Override
43      protected void addRoleQualification(Object primaryDataObjectOrDocument, Map<String, String> attributes) {
44          if (primaryDataObjectOrDocument !=null && primaryDataObjectOrDocument instanceof ARGCourseOfferingManagementForm) {
45              ARGCourseOfferingManagementForm theForm = (ARGCourseOfferingManagementForm) primaryDataObjectOrDocument;
46              if(theForm.getAdminOrg() != null){
47                  attributes.put("offeringAdminOrgId", theForm.getAdminOrg());
48              }
49              if(theForm.getSubjectCode() != null){
50                  attributes.put("subjectArea", theForm.getSubjectCode());
51              }
52          }
53          if (primaryDataObjectOrDocument !=null && primaryDataObjectOrDocument instanceof RegistrationGroupManagementForm) {
54              RegistrationGroupManagementForm theForm = (RegistrationGroupManagementForm) primaryDataObjectOrDocument;
55              if(theForm.getTheCourseOffering() != null){
56                  //Pull out the org ids and pass in the first one as a role qualifier
57                  List<String> orgIds = theForm.getTheCourseOffering().getUnitsDeploymentOrgIds();
58                  if(orgIds != null && !orgIds.isEmpty()){
59                      String orgIDs = "";
60                      for (String orgId : orgIds) {
61                          orgIDs = orgIDs + orgId + ",";
62                      }
63                      if (orgIDs.length() > 0) {
64                          attributes.put("offeringAdminOrgId", orgIDs.substring(0, orgIDs.length()-1));
65                      }
66                  }
67                  if(theForm.getTheCourseOffering().getSubjectArea() != null){
68                      attributes.put("subjectArea", theForm.getTheCourseOffering().getSubjectArea());
69                  }
70              }
71          }
72          super.addRoleQualification(primaryDataObjectOrDocument, attributes);
73      }
74  
75      @Override
76      protected void addPermissionDetails(Object primaryDataObjectOrDocument, Map<String, String> attributes) {
77          if (primaryDataObjectOrDocument !=null && primaryDataObjectOrDocument instanceof ARGCourseOfferingManagementForm) {
78              ARGCourseOfferingManagementForm theForm = (ARGCourseOfferingManagementForm) primaryDataObjectOrDocument;
79              // permission based on socState
80              String socState = theForm.getSocStateKey();
81              socState = socState==null?null:socState.substring(socState.lastIndexOf('.')+1);
82              attributes.put("socState", socState);
83  
84              // permission based on term class start date
85              Date termClassStartDate = theForm.getTermClassStartDate();
86              Date now = new Date();
87              if (termClassStartDate == null || now.before(termClassStartDate)) {
88                  attributes.put("termClassStartDateLater", "true");
89              }
90          }
91          super.addPermissionDetails(primaryDataObjectOrDocument, attributes);    //To change body of overridden methods use File | Settings | File Templates.
92      }
93  
94      /**
95       * This method resolves the unitsDeploymentOrgId from the CourseOffering Model and passes it in as
96       * a role qualifier
97       */
98      /**
99       * Performs a permission check for the given template name in the context of the given view and component
100      *
101      * <p>
102      * First standard permission details are added based on the type of component the permission check is being
103      * done for.
104      * Then the {@link org.kuali.rice.krad.uif.component.ComponentSecurity} of the given component is used to pick up additional permission details and
105      * role qualifiers.
106      * </p>
107      *
108      * @param view - view instance the component belongs to
109      * @param component - component instance the permission check is being done for
110      * @param model - object containing the views data
111      * @param permissionTemplateName - template name for the permission to check
112      * @param user - user to perform the authorization for
113      * @param additionalPermissionDetails - additional key/value pairs to pass with the permission details
114      * @param additionalRoleQualifications - additional key/value paris to pass with the role qualifiers
115      * @param checkPermissionExistence - boolean indicating whether the existence of the permission should be checked
116      * before performing the authorization
117      * @return boolean indicating whether the user has authorization, this will be the case if the user has been
118      * granted the permission or checkPermissionExistence is true and the permission does not exist
119      */
120     @Override
121     protected boolean isAuthorizedByTemplate(View view, Component component, ViewModel model,
122                                              String permissionTemplateName, Person user, Map<String, String> additionalPermissionDetails,
123                                              Map<String, String> additionalRoleQualifications, boolean checkPermissionExistence) {
124         if(additionalRoleQualifications == null){
125             //Instantiate if null was passed in
126             additionalRoleQualifications = new HashMap<String, String>();
127         }
128         addRoleQualification(model, additionalRoleQualifications);
129 
130         Map<String, String> permissionDetails = new HashMap<String, String>();
131         Map<String, String> roleQualifications = new HashMap<String, String>();
132 
133         if (additionalPermissionDetails != null) {
134             permissionDetails.putAll(additionalPermissionDetails);
135         }
136 
137         if (additionalRoleQualifications != null) {
138             roleQualifications.putAll(additionalRoleQualifications);
139         }
140 
141         Object dataObjectForContext = getDataObjectContext(view, model);
142 
143         // add permission details depending on the type of component
144         if (component instanceof Field) {
145             permissionDetails.putAll(getFieldPermissionDetails(view, dataObjectForContext, (Field) component));
146         } else if (component instanceof Group) {
147             permissionDetails.putAll(getGroupPermissionDetails(view, dataObjectForContext, (Group) component));
148         } else if (component instanceof Widget) {
149             permissionDetails.putAll(getWidgetPermissionDetails(view, dataObjectForContext, (Widget) component));
150         } else if (component instanceof Action) {
151             permissionDetails.putAll(getActionPermissionDetails(view, dataObjectForContext, (Action) component));
152         }
153 
154         // pick up additional attributes and overrides from component security
155         ComponentSecurity componentSecurity = component.getComponentSecurity();
156 
157         // add configured overrides
158         if (StringUtils.isNotBlank(componentSecurity.getNamespaceAttribute())) {
159             permissionDetails.put(KimConstants.AttributeConstants.NAMESPACE_CODE,
160                     componentSecurity.getNamespaceAttribute());
161         }
162         if (StringUtils.isNotBlank(componentSecurity.getComponentAttribute())) {
163             permissionDetails.put(KimConstants.AttributeConstants.COMPONENT_NAME,
164                     componentSecurity.getComponentAttribute());
165         }
166         if (StringUtils.isNotBlank(componentSecurity.getIdAttribute())) {
167             if (component instanceof Field) {
168                 permissionDetails.put(KimConstants.AttributeConstants.FIELD_ID, componentSecurity.getIdAttribute());
169             } else if (component instanceof Group) {
170                 permissionDetails.put(KimConstants.AttributeConstants.GROUP_ID, componentSecurity.getIdAttribute());
171             } else if (component instanceof Widget) {
172                 permissionDetails.put(KimConstants.AttributeConstants.WIDGET_ID, componentSecurity.getIdAttribute());
173             }
174         }
175 
176         // Add attribute depending on CO state for 'permissionExpression'
177         if (component instanceof Action) {
178             if (!((Action) component).getActionParameters().isEmpty() &&
179                     (((Action) component).getActionParameters().get(UifParameters.SELECTED_LINE_INDEX) != null) && !((Action) component).getActionParameters().get(UifParameters.SELECTED_LINE_INDEX).equals("") &&
180                     (((Action) component).getActionParameters().get(UifParameters.SELLECTED_COLLECTION_PATH) != null && !((Action) component).getActionParameters().get(UifParameters.SELLECTED_COLLECTION_PATH).equals("")) ) {
181                 String selectedCollectionPath = ((Action) component).getActionParameters().get(UifParameters.SELLECTED_COLLECTION_PATH);
182 
183                 int selectedLineIndex = -1;
184                 String selectedLine = ((Action) component).getActionParameters().get(UifParameters.SELECTED_LINE_INDEX);
185                 if (StringUtils.isNotBlank(selectedLine)) {
186                     selectedLineIndex = Integer.parseInt(selectedLine);
187                 }
188 
189                 if (model != null && model instanceof ARGCourseOfferingManagementForm) {
190                     ARGCourseOfferingManagementForm theForm = (ARGCourseOfferingManagementForm) model;
191                     Collection<Object> collection = ObjectPropertyUtils.getPropertyValue(theForm, selectedCollectionPath);
192                     Object selectedObject = ((List<Object>) collection).get(selectedLineIndex);
193                     if(selectedObject instanceof CourseOfferingListSectionWrapper){
194                         CourseOfferingListSectionWrapper theCourseOfferingWrapper =  (CourseOfferingListSectionWrapper)selectedObject;
195                         String courseOfferingStateDisplay = theCourseOfferingWrapper.getCourseOfferingStateDisplay();
196                         if (courseOfferingStateDisplay != null) {
197                             permissionDetails.put("coState", courseOfferingStateDisplay);
198                         }
199                     } else if(selectedObject instanceof ActivityOfferingWrapper){
200                         ActivityOfferingWrapper theActivityOfferingWrapper =  (ActivityOfferingWrapper)selectedObject;
201                         String activityOfferingStateName = theActivityOfferingWrapper.getStateName();
202                         if (activityOfferingStateName != null) {
203                             permissionDetails.put("aoState", activityOfferingStateName);
204                         }
205                     }
206                 }
207             } else if (model != null && model instanceof ARGCourseOfferingManagementForm) {
208                 if (((ARGCourseOfferingManagementForm) model).getCurrentCourseOfferingWrapper() != null &&
209                       ((ARGCourseOfferingManagementForm) model).getCurrentCourseOfferingWrapper().getStateKey() != null) {
210                     String coState = ((ARGCourseOfferingManagementForm) model).getCurrentCourseOfferingWrapper().getStateKey();
211                     coState = coState==null?null:coState.substring(coState.lastIndexOf('.')+1);
212                     permissionDetails.put("coState", coState);
213                 }
214             }
215         }
216 
217         if (componentSecurity.getAdditionalPermissionDetails() != null) {
218             permissionDetails.putAll(componentSecurity.getAdditionalPermissionDetails());
219         }
220 
221         if (componentSecurity.getAdditionalRoleQualifiers() != null) {
222             roleQualifications.putAll(componentSecurity.getAdditionalRoleQualifiers());
223         }
224 
225         boolean result = true;
226         if (!checkPermissionExistence || (checkPermissionExistence && permissionExistsByTemplate(dataObjectForContext,
227                 "KS-ENR", permissionTemplateName, permissionDetails))) {
228             result = isAuthorizedByTemplate(dataObjectForContext, "KS-ENR", permissionTemplateName,
229                     user.getPrincipalId(), permissionDetails, roleQualifications);
230 
231             if (LOG.isDebugEnabled()) {
232                 LOG.debug("Performed permission check for: " + permissionTemplateName + " and got result: " + result);
233             }
234         }
235 
236         return result;
237     }
238 
239     /**
240      * Override the method to change the KRAD namespace to KS Enroll
241      * @param view
242      * @param model
243      * @param user
244      * @return
245      */
246     @Override
247     public boolean canOpenView(View view, ViewModel model, Person user) {
248         Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
249         additionalPermissionDetails.put(KimConstants.AttributeConstants.NAMESPACE_CODE, view.getNamespaceCode());
250         additionalPermissionDetails.put(KimConstants.AttributeConstants.VIEW_ID, model.getViewId());
251 
252         if (permissionExistsByTemplate(model, "KS-ENR",
253                 KimConstants.PermissionTemplateNames.OPEN_VIEW, additionalPermissionDetails)) {
254             return isAuthorizedByTemplate(model, "KS-ENR",
255                     KimConstants.PermissionTemplateNames.OPEN_VIEW, user.getPrincipalId(), additionalPermissionDetails,
256                     null);
257         }
258 
259         return true;
260     }
261 
262     /**
263      * Checks for an edit view permission for the view id, and if found verifies the user has that permission
264      *
265      * @see org.kuali.rice.krad.uif.view.ViewAuthorizer#canEditView(org.kuali.rice.krad.uif.view.View, org.kuali.rice.krad.uif.view.ViewModel,
266      *      org.kuali.rice.kim.api.identity.Person)
267      */
268     @Override
269     public boolean canEditView(View view, ViewModel model, Person user) {
270         Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
271         additionalPermissionDetails.put(KimConstants.AttributeConstants.NAMESPACE_CODE, view.getNamespaceCode());
272         additionalPermissionDetails.put(KimConstants.AttributeConstants.VIEW_ID, model.getViewId());
273 
274         if (permissionExistsByTemplate(model, "KS-ENR",
275                 KimConstants.PermissionTemplateNames.EDIT_VIEW, additionalPermissionDetails)) {
276             return isAuthorizedByTemplate(model, "KS-ENR",
277                     KimConstants.PermissionTemplateNames.EDIT_VIEW, user.getPrincipalId(), additionalPermissionDetails,
278                     null);
279         }
280 
281         return true;
282     }
283 
284     /**
285      * @see org.kuali.rice.krad.uif.view.ViewAuthorizer#canViewGroup(org.kuali.rice.krad.uif.view.View, org.kuali.rice.krad.uif.view.ViewModel,
286      *      org.kuali.rice.krad.uif.container.Group, String, org.kuali.rice.kim.api.identity.Person)
287      *
288      *      In this override we want to be able to display a custom message that nofies the user that they are not authorized.
289      */
290     @Override
291     public boolean canViewGroup(View view, ViewModel model, Group group, String groupId, Person user) {
292          boolean bRet = super.canViewGroup(view, model, group, groupId, user);    //To change body of overridden methods use File | Settings | File Templates.
293 
294         if(!bRet){
295             String messageKey = "error." + view.getId() + "." + groupId;
296 
297             if(getMessageService().getMessageText(messageKey) != null){ // if the message isn't configured, then don't display any error
298                 GlobalVariables.getMessageMap().putError(view.getId(), messageKey);
299             }
300         }
301 
302         return bRet;
303 
304     }
305 
306     public MessageService getMessageService() {
307         if(messageService == null){
308             messageService = KRADServiceLocatorWeb.getMessageService();
309         }
310 
311         return messageService;
312     }
313 
314     public void setMessageService(MessageService messageService) {
315         this.messageService = messageService;
316     }
317 }