001/**
002 * Copyright 2005-2018 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.krad.uif.lifecycle.model;
017
018import org.kuali.rice.kim.api.identity.Person;
019import org.kuali.rice.krad.datadictionary.AttributeSecurity;
020import org.kuali.rice.krad.uif.component.Component;
021import org.kuali.rice.krad.uif.component.DataBinding;
022import org.kuali.rice.krad.uif.container.Group;
023import org.kuali.rice.krad.uif.element.Action;
024import org.kuali.rice.krad.uif.field.ActionField;
025import org.kuali.rice.krad.uif.field.DataField;
026import org.kuali.rice.krad.uif.field.Field;
027import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
028import org.kuali.rice.krad.uif.lifecycle.ViewLifecycleTaskBase;
029import org.kuali.rice.krad.uif.view.View;
030import org.kuali.rice.krad.uif.view.ViewAuthorizer;
031import org.kuali.rice.krad.uif.view.ViewModel;
032import org.kuali.rice.krad.uif.view.ViewPresentationController;
033import org.kuali.rice.krad.uif.widget.Widget;
034import org.kuali.rice.krad.util.GlobalVariables;
035
036/**
037 * Apply authorization and presentation logic for the component.
038 * 
039 * @author Kuali Rice Team (rice.collab@kuali.org)
040 */
041public class ApplyAuthAndPresentationLogicTask extends ViewLifecycleTaskBase<Component> {
042
043    /**
044     * Default constructor.
045     */
046    public ApplyAuthAndPresentationLogicTask() {
047        super(Component.class);
048    }
049
050    /**
051     * Invokes the view's configured {@link ViewAuthorizer} and {@link ViewPresentationController}
052     * to set state of the component
053     * 
054     * <p>
055     * The following authorization is done here: Fields: edit, view, required, mask, and partial
056     * mask Groups: edit and view Actions: take action
057     * </p>
058     * 
059     * <p>
060     * Note additional checks are also done for fields that are part of a collection group. This
061     * authorization is found in {@link org.kuali.rice.krad.uif.container.CollectionGroupBuilder}
062     * </p>
063     * 
064     * @see org.kuali.rice.krad.uif.lifecycle.ViewLifecycleTaskBase#performLifecycleTask()
065     */
066    @Override
067    protected void performLifecycleTask() {
068        ViewModel model = (ViewModel) ViewLifecycle.getModel();
069        Component component = (Component) getElementState().getElement();
070        View view = ViewLifecycle.getView();
071        ViewPresentationController presentationController = view.getPresentationController();
072        ViewAuthorizer authorizer = view.getAuthorizer();
073
074        // if user session is not established cannot perform authorization
075        if (GlobalVariables.getUserSession() == null) {
076            return;
077        }
078
079        Person user = GlobalVariables.getUserSession().getPerson();
080
081        // if component not flagged for render no need to check auth and controller logic
082        if (!component.isRender()) {
083            return;
084        }
085
086        // check top level view edit authorization
087        if (component instanceof View) {
088            if (!Boolean.TRUE.equals(view.getReadOnly())) {
089                if (model.isCanEditView() == null) {
090                    boolean canEditView = authorizer.canEditView(view, model, user);
091                    if (canEditView) {
092                        canEditView = presentationController.canEditView(view, model);
093                    }
094                    view.setReadOnly(Boolean.valueOf(!canEditView));
095                    model.setCanEditView(Boolean.valueOf(canEditView));
096                } else {
097                    view.setReadOnly(!model.isCanEditView());
098                }
099            }
100        }
101
102        // perform group authorization and presentation logic
103        else if (component instanceof Group) {
104            Group group = (Group) component;
105
106            // if group is not hidden, do authorization for viewing the group
107            if (!group.isHidden()) {
108                boolean canViewGroup = authorizer.canViewGroup(view, model, group, group.getId(), user);
109                if (canViewGroup) {
110                    canViewGroup = presentationController.canViewGroup(view, model, group, group.getId());
111                }
112                group.setHidden(!canViewGroup);
113                group.setRender(canViewGroup);
114            }
115
116            // if group is editable, do authorization for editing the group
117            if (!Boolean.TRUE.equals(group.getReadOnly())) {
118                boolean canEditGroup = authorizer.canEditGroup(view, model, group, group.getId(), user);
119                if (canEditGroup) {
120                    canEditGroup = presentationController.canEditGroup(view, model, group, group.getId());
121                }
122                group.setReadOnly(!canEditGroup);
123            }
124        }
125
126        // perform field authorization and presentation logic
127        else if (component instanceof Field && !(component instanceof ActionField)) {
128            Field field = (Field) component;
129
130            String propertyName = null;
131            if (field instanceof DataBinding) {
132                propertyName = ((DataBinding) field).getPropertyName();
133            }
134
135            // if field is not hidden, do authorization for viewing the field
136            if (!field.isHidden()) {
137                boolean canViewField = authorizer.canViewField(view, model, field, propertyName, user);
138                if (canViewField) {
139                    canViewField = presentationController.canViewField(view, model, field, propertyName);
140                }
141                field.setHidden(!canViewField);
142                field.setRender(canViewField);
143            }
144
145            // if field is not readOnly, check edit authorization
146            if (!Boolean.TRUE.equals(field.getReadOnly())) {
147                // check field edit authorization
148                boolean canEditField = authorizer.canEditField(view, model, field, propertyName, user);
149                if (canEditField) {
150                    canEditField = presentationController.canEditField(view, model, field, propertyName);
151                }
152                field.setReadOnly(!canEditField);
153            }
154
155            // if field is not already required, invoke presentation logic to determine if it should be
156            if ((field.getRequired() == null) || !field.getRequired().booleanValue()) {
157                // boolean fieldIsRequired = 
158                presentationController.fieldIsRequired(view, model, field, propertyName);
159            }
160
161            if (field instanceof DataField) {
162                DataField dataField = (DataField) field;
163
164                // check for masking and mask authorization
165                boolean canUnmaskValue = authorizer.canUnmaskField(view, model, dataField, dataField.getPropertyName(),
166                        user);
167                boolean canPartiallyUnmaskValue = authorizer.canPartialUnmaskField(view, model, dataField,
168                        dataField.getPropertyName(), user);
169                boolean isMasked = isMaskField(dataField);
170                boolean isPartialMask = isPartialMaskField(dataField);
171
172                if (isMasked && !canUnmaskValue)  {
173                    dataField.setApplyMask(true);
174                    dataField.setMaskFormatter(dataField.getDataFieldSecurity().getAttributeSecurity().
175                            getMaskFormatter());
176                }
177                else if(isMasked && canUnmaskValue)  {
178                    // do not mask
179                }
180                else if (isPartialMask && !canPartiallyUnmaskValue ) {
181                    dataField.setApplyMask(true);
182                    dataField.setMaskFormatter(
183                            dataField.getDataFieldSecurity().getAttributeSecurity().getPartialMaskFormatter());
184                }
185            }
186        }
187
188        // perform action authorization and presentation logic
189        else if (component instanceof ActionField || component instanceof Action) {
190            Action action = null;
191            if (component instanceof ActionField) {
192                action = ((ActionField) component).getAction();
193            } else {
194                action = (Action) component;
195            }
196
197            boolean canTakeAction = authorizer.canPerformAction(view, model, action, action.getActionEvent(),
198                    action.getId(), user);
199            if (canTakeAction) {
200                canTakeAction = presentationController.canPerformAction(view, model, action, action.getActionEvent(),
201                        action.getId());
202            }
203            action.setRender(canTakeAction);
204        }
205
206        // perform widget authorization and presentation logic
207        else if (component instanceof Widget) {
208            Widget widget = (Widget) component;
209
210            // if widget is not hidden, do authorization for viewing the widget
211            if (!widget.isHidden()) {
212                boolean canViewWidget = authorizer.canViewWidget(view, model, widget, widget.getId(), user);
213                if (canViewWidget) {
214                    canViewWidget = presentationController.canViewWidget(view, model, widget, widget.getId());
215                }
216                widget.setHidden(!canViewWidget);
217                widget.setRender(canViewWidget);
218            }
219
220            // if widget is not readOnly, check edit authorization
221            if (!Boolean.TRUE.equals(widget.getReadOnly())) {
222                boolean canEditWidget = authorizer.canEditWidget(view, model, widget, widget.getId(), user);
223                if (canEditWidget) {
224                    canEditWidget = presentationController.canEditWidget(view, model, widget, widget.getId());
225                }
226                widget.setReadOnly(!canEditWidget);
227            }
228        }
229    }
230
231    /**
232     *
233     */
234    private boolean isMaskField(DataField field) {
235        if (field.getDataFieldSecurity() == null) {
236            return false;
237        }
238
239        // check mask authz flag is set
240        AttributeSecurity attributeSecurity = field.getDataFieldSecurity().getAttributeSecurity();
241        if (attributeSecurity == null || !attributeSecurity.isMask()) {
242            return false;
243        }
244
245        return true;
246    }
247
248    /**
249     *
250     */
251    private boolean isPartialMaskField(DataField field) {
252        if (field.getDataFieldSecurity() == null) {
253            return false;
254        }
255
256        // check partial mask authz flag is set
257        AttributeSecurity attributeSecurity = field.getDataFieldSecurity().getAttributeSecurity();
258        if (attributeSecurity == null || !attributeSecurity.isPartialMask()) {
259            return false;
260        }
261
262        return true;
263    }
264
265}