001    /*
002     * Copyright 2011 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     */
016    package org.kuali.kfs.sec.document.web;
017    
018    import java.util.ArrayList;
019    import java.util.Iterator;
020    import java.util.List;
021    import java.util.Map;
022    
023    import javax.servlet.jsp.JspException;
024    import javax.servlet.jsp.PageContext;
025    import javax.servlet.jsp.tagext.Tag;
026    
027    import org.apache.struts.Globals;
028    import org.apache.struts.action.ActionMessage;
029    import org.apache.struts.action.ActionMessages;
030    import org.kuali.kfs.sec.SecConstants;
031    import org.kuali.kfs.sec.SecKeyConstants;
032    import org.kuali.kfs.sec.service.AccessSecurityService;
033    import org.kuali.kfs.sys.context.SpringContext;
034    import org.kuali.kfs.sys.document.AccountingDocument;
035    import org.kuali.kfs.sys.document.datadictionary.AccountingLineGroupDefinition;
036    import org.kuali.kfs.sys.document.web.DefaultAccountingLineGroupImpl;
037    import org.kuali.kfs.sys.document.web.RenderableAccountingLineContainer;
038    import org.kuali.kfs.sys.document.web.renderers.GroupErrorsRenderer;
039    import org.kuali.rice.kim.bo.Person;
040    import org.kuali.rice.kns.util.GlobalVariables;
041    
042    
043    /**
044     * Integrates with access security module to check security on accounting lines before rendering
045     */
046    public class SecAccountingLineGroupImpl extends DefaultAccountingLineGroupImpl {
047        protected boolean hasEditRestrictions;
048        protected boolean hasViewRestrictions;
049    
050        /**
051         * Constructs a SecAccountingLineGroupImpl
052         */
053        public SecAccountingLineGroupImpl() {
054            hasEditRestrictions = false;
055            hasViewRestrictions = false;
056        }
057    
058        /**
059         * Performs access security edit check and sets edit flag on container line to false if access is not allowed or removes
060         * container if view is not allowed
061         * 
062         * @see org.kuali.kfs.sys.document.web.DefaultAccountingLineGroupImpl#initialize(org.kuali.kfs.sys.document.datadictionary.AccountingLineGroupDefinition,
063         *      org.kuali.kfs.sys.document.AccountingDocument, java.util.List, java.lang.String, java.lang.String, java.util.Map,
064         *      java.util.Map, java.util.Map, boolean)
065         */
066        @Override
067        public void initialize(AccountingLineGroupDefinition groupDefinition, AccountingDocument accountingDocument, List<RenderableAccountingLineContainer> containers, String collectionPropertyName, String collectionItemPropertyName, Map<String, Object> displayedErrors, Map<String, Object> displayedWarnings, Map<String, Object> displayedInfo, boolean canEdit) {
068            AccessSecurityService accessSecurityService = SpringContext.getBean(AccessSecurityService.class);
069            Person currentUser = GlobalVariables.getUserSession().getPerson();
070    
071            // check view and edit access
072            List<RenderableAccountingLineContainer> unviewableContainers = new ArrayList<RenderableAccountingLineContainer>();
073            for (RenderableAccountingLineContainer container : containers) {
074                boolean lineHasError = false;
075                for (Object errorKeyAsObject : GlobalVariables.getMessageMap().keySet()) {
076                    if (((String) errorKeyAsObject).startsWith(collectionItemPropertyName))
077                        lineHasError = true;
078                }
079    
080                if (lineHasError || container.isNewLine()) {
081                    container.setEditableLine(true);
082                    continue;
083                }
084    
085                boolean viewAllowed = accessSecurityService.canViewDocumentAccountingLine(accountingDocument, container.getAccountingLine(), currentUser);
086                if (!viewAllowed) {
087                    unviewableContainers.add(container);
088                    hasViewRestrictions = true;
089                }
090                else {
091                    boolean editAllowed = accessSecurityService.canEditDocumentAccountingLine(accountingDocument, container.getAccountingLine(), currentUser);
092    
093                    if (container.isEditableLine() && !editAllowed) {
094                        container.setEditableLine(false);
095                        hasEditRestrictions = true;
096                    }
097                }
098            }
099    
100            // remove containers that are not viewable
101            for (RenderableAccountingLineContainer container : unviewableContainers) {
102                containers.remove(container);
103            }
104    
105            super.initialize(groupDefinition, accountingDocument, containers, collectionPropertyName, collectionItemPropertyName, displayedErrors, displayedWarnings, displayedInfo, canEdit);
106        }
107    
108        /**
109         * Adds info message if we have restricted view of any accounting lines and adds an additional key to match on
110         * 
111         * @see org.kuali.kfs.sys.document.web.DefaultAccountingLineGroupImpl#renderErrors(javax.servlet.jsp.PageContext,
112         *      javax.servlet.jsp.tagext.Tag)
113         */
114        @Override
115        protected void renderErrors(PageContext pageContext, Tag parentTag) throws JspException {
116            renderSecurityMessage(pageContext, parentTag);
117    
118            renderMessages(pageContext, parentTag, groupDefinition.getErrorKey());
119        }
120    
121        /**
122         * Helper method for outputting messages
123         * 
124         * @param pageContext
125         * @param parentTag
126         * @param messageKey - key for messages to display
127         * @throws JspException
128         */
129        protected void renderMessages(PageContext pageContext, Tag parentTag, String messageKey) throws JspException {
130            GroupErrorsRenderer errorRenderer = getErrorRenderer();
131            errorRenderer.setErrorKeyMatch(messageKey);
132            errorRenderer.setColSpan(getWidthInCells());
133            errorRenderer.render(pageContext, parentTag);
134    
135            moveListToMap(errorRenderer.getErrorsRendered(), getDisplayedErrors());
136            moveListToMap(errorRenderer.getWarningsRendered(), getDisplayedWarnings());
137            moveListToMap(errorRenderer.getInfoRendered(), getDisplayedInfo());
138    
139            errorRenderer.clear();
140        }
141    
142        /**
143         * Adds info message for any security restrictions that have been applied
144         * 
145         * @param pageContext
146         * @param parentTag
147         * @throws JspException
148         */
149        protected void renderSecurityMessage(PageContext pageContext, Tag parentTag) throws JspException {
150            String secErrorKey = SecConstants.ACCOUNTING_GROUP_ERROR_KEY_PREFIX + collectionItemPropertyName + collectionPropertyName;
151    
152            // add info message if we are restricting any lines from view
153            if (hasEditRestrictions || hasViewRestrictions) {
154                List pageWarnings = (List) pageContext.getRequest().getAttribute("InfoPropertyList");
155                if (pageWarnings == null) {
156                    pageWarnings = new ArrayList();
157                }
158                pageWarnings.add(secErrorKey);
159                pageContext.getRequest().setAttribute("InfoPropertyList", pageWarnings);
160    
161                ActionMessages requestErrors = (ActionMessages) pageContext.getRequest().getAttribute("InfoActionMessages");
162                if (requestErrors == null) {
163                    requestErrors = new ActionMessages();
164                }
165    
166                if (hasViewRestrictions) {
167                    requestErrors.add(secErrorKey, new ActionMessage(SecKeyConstants.MESSAGE_ACCOUNTING_LINE_VIEW_RESTRICTED));
168                }
169                else {
170                    requestErrors.add(secErrorKey, new ActionMessage(SecKeyConstants.MESSAGE_ACCOUNTING_LINE_EDIT_RESTRICTED));
171                }
172    
173                pageContext.getRequest().setAttribute(Globals.ERROR_KEY, requestErrors);
174            }
175    
176            renderMessages(pageContext, parentTag, secErrorKey);
177        }
178    
179    }