001/**
002 * Copyright 2005-2015 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.kim.web.struts.action;
017
018import org.apache.commons.lang.StringUtils;
019import org.apache.struts.action.ActionForm;
020import org.apache.struts.action.ActionForward;
021import org.apache.struts.action.ActionMapping;
022import org.kuali.rice.core.api.delegation.DelegationType;
023import org.kuali.rice.core.api.membership.MemberType;
024import org.kuali.rice.core.api.util.RiceConstants;
025import org.kuali.rice.core.api.util.RiceKeyConstants;
026import org.kuali.rice.kew.api.exception.WorkflowException;
027import org.kuali.rice.kim.api.KimConstants;
028import org.kuali.rice.kim.api.group.Group;
029import org.kuali.rice.kim.api.identity.Person;
030import org.kuali.rice.kim.api.identity.principal.Principal;
031import org.kuali.rice.kim.api.role.Role;
032import org.kuali.rice.kim.api.services.KimApiServiceLocator;
033import org.kuali.rice.kim.bo.ui.KimDocumentRoleMember;
034import org.kuali.rice.kim.bo.ui.KimDocumentRolePermission;
035import org.kuali.rice.kim.bo.ui.KimDocumentRoleQualifier;
036import org.kuali.rice.kim.bo.ui.KimDocumentRoleResponsibility;
037import org.kuali.rice.kim.bo.ui.RoleDocumentDelegationMember;
038import org.kuali.rice.kim.bo.ui.RoleDocumentDelegationMemberQualifier;
039import org.kuali.rice.kim.document.IdentityManagementRoleDocument;
040import org.kuali.rice.kim.impl.responsibility.AddResponsibilityEvent;
041import org.kuali.rice.kim.impl.responsibility.ResponsibilityBo;
042import org.kuali.rice.kim.impl.type.KimTypeLookupableHelperServiceImpl;
043import org.kuali.rice.kim.rule.event.ui.AddDelegationMemberEvent;
044import org.kuali.rice.kim.rule.event.ui.AddMemberEvent;
045import org.kuali.rice.kim.rule.event.ui.AddPermissionEvent;
046import org.kuali.rice.kim.web.struts.form.IdentityManagementRoleDocumentForm;
047import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
048import org.kuali.rice.kns.web.struts.form.KualiTableRenderFormMetadata;
049import org.kuali.rice.kns.question.ConfirmationQuestion;
050import org.kuali.rice.krad.service.KRADServiceLocator;
051import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
052import org.kuali.rice.krad.util.GlobalVariables;
053import org.kuali.rice.krad.util.KRADConstants;
054import org.kuali.rice.krad.util.ObjectUtils;
055
056import javax.servlet.http.HttpServletRequest;
057import javax.servlet.http.HttpServletResponse;
058import java.sql.Timestamp;
059import java.util.ArrayList;
060import java.util.Arrays;
061import java.util.Calendar;
062import java.util.HashMap;
063import java.util.List;
064import java.util.Map;
065
066/**
067 * @author Kuali Rice Team (rice.collab@kuali.org)
068 */
069public class IdentityManagementRoleDocumentAction extends IdentityManagementDocumentActionBase {
070
071    public static final String CHANGE_DEL_ROLE_MEMBER_METHOD_TO_CALL = "changeDelegationRoleMember";
072    public static final String SWITCH_TO_ROLE_MEMBER_METHOD_TO_CALL = "jumpToRoleMember";
073    public static final String REMOVE_AFFECTED_DELEGATES_QUESTION_ID = "RemoveAffectedDelegates";
074
075    protected List<String> methodToCallToUncheckedList = new ArrayList<String>();
076
077    /**
078     * This method doesn't actually sort the column - it's just that we need a sort method in
079     * order to exploit the existing methodToCall logic. The sorting is handled in the execute
080     * method below, and delegated to the KualiTableRenderFormMetadata object. 
081     *
082     * @param mapping
083     * @param form
084     * @param request
085     * @param response
086     * @return
087     * @throws Exception
088     */
089    {
090        methodToCallToUncheckedList.add(CHANGE_DEL_ROLE_MEMBER_METHOD_TO_CALL);
091        methodToCallToUncheckedList.add(CHANGE_MEMBER_TYPE_CODE_METHOD_TO_CALL);
092        methodToCallToUncheckedList.add(CHANGE_NAMESPACE_METHOD_TO_CALL);
093        methodToCallToUncheckedList.add(SWITCH_TO_ROLE_MEMBER_METHOD_TO_CALL);
094    }
095
096    /**
097     * This constructs a ...
098     */
099    public IdentityManagementRoleDocumentAction() {
100        super();
101        for (String methodToCallToUncheck : methodToCallToUncheckedList) {
102            addMethodToCallToUncheckedList(methodToCallToUncheck);
103        }
104    }
105
106    public ActionForward sort(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
107        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
108        KualiTableRenderFormMetadata memberTableMetadata = roleDocumentForm.getMemberTableMetadata();
109        memberTableMetadata.setSwitchToPageNumber(0);
110        return mapping.findForward(RiceConstants.MAPPING_BASIC);
111    }
112
113    @Override
114    public ActionForward execute(ActionMapping mapping, ActionForm form,
115            HttpServletRequest request, HttpServletResponse response) throws Exception {
116        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
117        if (roleDocumentForm.getRoleId() == null) {
118            String roleId = request.getParameter(KimConstants.PrimaryKeyConstants.SUB_ROLE_ID);
119            roleDocumentForm.setRoleId(roleId);
120        }
121
122        KualiTableRenderFormMetadata memberTableMetadata = roleDocumentForm.getMemberTableMetadata();
123        if (roleDocumentForm.getRoleDocument()!=null && roleDocumentForm.getMemberRows() != null) {
124            memberTableMetadata.jumpToPage(memberTableMetadata.getViewedPageNumber(), roleDocumentForm.getMemberRows().size(), roleDocumentForm.getRecordsPerPage());
125            // KULRICE-3972: need to be able to sort by column header like on lookups when editing large roles and groups
126            memberTableMetadata.sort(roleDocumentForm.getMemberRows(), roleDocumentForm.getRecordsPerPage());
127        }
128
129        // KULRICE-4762: active delegates of "inactivated" role members cause validation problems
130        ActionForward forward = promptForAffectedDelegates(mapping, form, request, response,
131                roleDocumentForm);
132        // if we need to prompt the user due to affected delegates, do so:
133        if (forward != null) { return forward; }
134
135        forward = super.execute(mapping, roleDocumentForm, request, response);
136
137        roleDocumentForm.setCanAssignRole(validAssignRole(roleDocumentForm.getRoleDocument()));
138        if (KimTypeLookupableHelperServiceImpl.hasDerivedRoleTypeService(roleDocumentForm.getRoleDocument().getKimType())) {
139            roleDocumentForm.setCanModifyAssignees(false);
140        }
141        GlobalVariables.getUserSession().addObject(KimConstants.KimUIConstants.KIM_ROLE_DOCUMENT_SHORT_KEY, roleDocumentForm.getRoleDocument());
142        return forward;
143    }
144
145    /**
146     * This overridden method ...
147     *
148     * @see org.kuali.rice.krad.web.struts.action.KualiDocumentActionBase#loadDocument(org.kuali.rice.krad.web.struts.form.KualiDocumentFormBase)
149     */
150    @Override
151    protected void loadDocument(KualiDocumentFormBase form)
152            throws WorkflowException {
153        super.loadDocument(form);
154
155        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
156        setKimType(roleDocumentForm.getRoleDocument().getRoleTypeId(), roleDocumentForm);
157
158        getUiDocumentService().setDelegationMembersInDocument(roleDocumentForm.getRoleDocument());
159        getUiDocumentService().setMembersInDocument(roleDocumentForm.getRoleDocument());
160
161        roleDocumentForm.setMember(roleDocumentForm.getRoleDocument().getBlankMember());
162        roleDocumentForm.setDelegationMember(roleDocumentForm.getRoleDocument().getBlankDelegationMember());
163
164        KualiTableRenderFormMetadata memberTableMetadata = roleDocumentForm.getMemberTableMetadata();
165        if (roleDocumentForm.getMemberRows() != null) {
166            memberTableMetadata.jumpToFirstPage(roleDocumentForm.getMemberRows().size(), roleDocumentForm.getRecordsPerPage());
167        }
168    }
169
170    /**
171     * This overridden method ...
172     *
173     * @see org.kuali.rice.krad.web.struts.action.KualiDocumentActionBase#createDocument(org.kuali.rice.krad.web.struts.form.KualiDocumentFormBase)
174     */
175    @Override
176    protected void createDocument(KualiDocumentFormBase form)
177            throws WorkflowException {
178        super.createDocument(form);
179        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
180
181        if (roleDocumentForm.getRoleId() == null) {
182            roleDocumentForm.getRoleDocument().setKimType(roleDocumentForm.getKimType());
183            roleDocumentForm.getRoleDocument().initializeDocumentForNewRole();
184            roleDocumentForm.setRoleId(roleDocumentForm.getRoleDocument().getRoleId());
185            //roleDocumentForm.setKimType(KimApiServiceLocator.getKimTypeInfoService().getKimType(roleDocumentForm.getRoleDocument().getRoleTypeId()));
186        } else {
187            loadRoleIntoDocument(roleDocumentForm.getRoleId(), roleDocumentForm);
188        }
189
190        roleDocumentForm.setMember(roleDocumentForm.getRoleDocument().getBlankMember());
191        roleDocumentForm.setDelegationMember(roleDocumentForm.getRoleDocument().getBlankDelegationMember());
192
193        KualiTableRenderFormMetadata memberTableMetadata = roleDocumentForm.getMemberTableMetadata();
194        if (roleDocumentForm.getMemberRows() != null) {
195            memberTableMetadata.jumpToFirstPage(roleDocumentForm.getMemberRows().size(), roleDocumentForm.getRecordsPerPage());
196        }
197    }
198
199    protected void setKimType(String kimTypeId, IdentityManagementRoleDocumentForm roleDocumentForm) {
200        if (StringUtils.isNotBlank(kimTypeId)) {
201            roleDocumentForm.setKimType(KimApiServiceLocator.getKimTypeInfoService().getKimType(kimTypeId));
202            if (roleDocumentForm.getRoleDocument() != null) {
203                roleDocumentForm.getRoleDocument().setKimType(roleDocumentForm.getKimType());
204            }
205        } else if (roleDocumentForm.getRoleDocument() != null && StringUtils.isNotBlank(roleDocumentForm.getRoleDocument().getRoleTypeId())) {
206            roleDocumentForm.setKimType(KimApiServiceLocator.getKimTypeInfoService().getKimType(
207                    roleDocumentForm.getRoleDocument().getRoleTypeId()));
208            roleDocumentForm.getRoleDocument().setKimType(roleDocumentForm.getKimType());
209        }
210    }
211
212    protected void loadRoleIntoDocument(String roleId, IdentityManagementRoleDocumentForm roleDocumentForm) {
213        Role role = KimApiServiceLocator.getRoleService().getRole(roleId);
214        roleDocumentForm.getRoleDocument().setMemberMetaDataTypeToSort(roleDocumentForm.getMemberTableMetadata().getColumnToSortIndex());
215        getUiDocumentService().loadRoleDoc(roleDocumentForm.getRoleDocument(), role);
216    }
217
218    /**
219     * @see org.kuali.rice.kim.web.struts.action.IdentityManagementDocumentActionBase#getActionName()
220     */
221    public String getActionName() {
222        return KimConstants.KimUIConstants.KIM_ROLE_DOCUMENT_ACTION;
223    }
224
225    protected boolean validAssignRole(IdentityManagementRoleDocument document) {
226        boolean rulePassed = true;
227        if (StringUtils.isNotEmpty(document.getRoleNamespace())) {
228            Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
229            additionalPermissionDetails.put(KimConstants.AttributeConstants.NAMESPACE_CODE, document.getRoleNamespace());
230            additionalPermissionDetails.put(KimConstants.AttributeConstants.ROLE_NAME, document.getRoleName());
231            if (!getDocumentHelperService().getDocumentAuthorizer(document).isAuthorizedByTemplate(
232                    document,
233                    KimConstants.NAMESPACE_CODE,
234                    KimConstants.PermissionTemplateNames.ASSIGN_ROLE,
235                    GlobalVariables.getUserSession().getPrincipalId(),
236                    additionalPermissionDetails, null)) {
237                rulePassed = false;
238            }
239        }
240        return rulePassed;
241    }
242
243    public ActionForward changeMemberTypeCode(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
244        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
245        roleDocumentForm.getMember().setMemberId("");
246        return refresh(mapping, roleDocumentForm, request, response);
247    }
248
249    public ActionForward changeDelegationMemberTypeCode(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
250        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
251        KimDocumentRoleMember roleMember = roleDocumentForm.getRoleDocument().getMember(roleDocumentForm.getDelegationMember().getRoleMemberId());
252        if (roleMember != null) {
253            RoleDocumentDelegationMemberQualifier delegationMemberQualifier;
254            for (KimDocumentRoleQualifier roleQualifier : roleMember.getQualifiers()) {
255                delegationMemberQualifier = roleDocumentForm.getDelegationMember().getQualifier(roleQualifier.getKimAttrDefnId());
256                delegationMemberQualifier.setAttrVal(roleQualifier.getAttrVal());
257            }
258        }
259        return refresh(mapping, roleDocumentForm, request, response);
260    }
261
262    public ActionForward addResponsibility(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
263        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
264        KimDocumentRoleResponsibility newResponsibility = roleDocumentForm.getResponsibility();
265        if (newResponsibility != null && StringUtils.isNotBlank(newResponsibility.getResponsibilityId())) {
266            Map<String, String> criteria = new HashMap<String, String>();
267            criteria.put(KimConstants.PrimaryKeyConstants.RESPONSIBILITY_ID, newResponsibility.getResponsibilityId());
268            ResponsibilityBo responsibilityImpl = KRADServiceLocator.getBusinessObjectService().findByPrimaryKey(ResponsibilityBo.class, criteria);
269            newResponsibility.setKimResponsibility(responsibilityImpl);
270        }
271
272        if (KRADServiceLocatorWeb.getKualiRuleService().applyRules(new AddResponsibilityEvent("", roleDocumentForm.getRoleDocument(), newResponsibility))) {
273            if (newResponsibility != null) {
274                newResponsibility.setDocumentNumber(roleDocumentForm.getDocument().getDocumentNumber());
275            }
276            roleDocumentForm.getRoleDocument().addResponsibility(newResponsibility);
277            roleDocumentForm.setResponsibility(new KimDocumentRoleResponsibility());
278            roleDocumentForm.getRoleDocument().updateMembers(newResponsibility);
279        }
280        return mapping.findForward(RiceConstants.MAPPING_BASIC);
281    }
282
283    public ActionForward deleteResponsibility(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
284        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
285        roleDocumentForm.getRoleDocument().getResponsibilities().remove(getLineToDelete(request));
286        roleDocumentForm.getRoleDocument().updateMembers(roleDocumentForm);
287        return mapping.findForward(RiceConstants.MAPPING_BASIC);
288    }
289
290    public ActionForward addPermission(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
291        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
292        KimDocumentRolePermission newPermission = roleDocumentForm.getPermission();
293        if (KRADServiceLocatorWeb.getKualiRuleService().applyRules(new AddPermissionEvent("", roleDocumentForm.getRoleDocument(), newPermission))) {
294            newPermission.setDocumentNumber(roleDocumentForm.getDocument().getDocumentNumber());
295            newPermission.setRoleId(roleDocumentForm.getRoleDocument().getRoleId());
296            roleDocumentForm.getRoleDocument().getPermissions().add(newPermission);
297            roleDocumentForm.setPermission(new KimDocumentRolePermission());
298        }
299        return mapping.findForward(RiceConstants.MAPPING_BASIC);
300    }
301
302    public ActionForward addMember(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
303        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
304        KimDocumentRoleMember newMember = roleDocumentForm.getMember();
305
306        //See if possible to add with just Group Details filled in (not returned from lookup)
307        if ( StringUtils.equals(newMember.getMemberTypeCode(), KimConstants.KimGroupMemberTypes.GROUP_MEMBER_TYPE.getCode())
308                && StringUtils.isEmpty(newMember.getMemberId())
309                && !newMember.isMemberNameNull()
310                && !newMember.isMemberNameSpaceCodeNull() ) {
311            Group tempGroup = KimApiServiceLocator.getGroupService().getGroupByNamespaceCodeAndName(
312                    newMember.getMemberNamespaceCode(), newMember.getMemberName());
313            if (tempGroup != null) {
314                newMember.setMemberId(tempGroup.getId());
315            }
316        }
317
318        //See if possible to grab details for Principal
319        if ( StringUtils.equals(newMember.getMemberTypeCode(), KimConstants.KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE.getCode())
320                && StringUtils.isEmpty(newMember.getMemberId())
321                && StringUtils.isNotEmpty(newMember.getMemberName())) {
322            Principal principal = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName(newMember.getMemberName());
323            if (principal != null) {
324                newMember.setMemberId(principal.getPrincipalId());
325                String fullName = checkMemberFullName(principal.getPrincipalId());
326                if (fullName != null) {
327                    newMember.setMemberFullName(fullName);
328                }
329            }
330        } else if ( StringUtils.equals(newMember.getMemberTypeCode(), KimConstants.KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE.getCode())
331                && StringUtils.isNotEmpty(newMember.getMemberId())
332                && StringUtils.isNotEmpty(newMember.getMemberName())) {
333            String fullName = checkMemberFullName(newMember.getMemberId());
334            if (fullName != null) {
335                newMember.setMemberFullName(fullName);
336            }
337        }
338
339        if (checkKimDocumentRoleMember(newMember) &&
340                KRADServiceLocatorWeb.getKualiRuleService().applyRules(new AddMemberEvent("", roleDocumentForm.getRoleDocument(), newMember))) {
341            newMember.setDocumentNumber(roleDocumentForm.getDocument().getDocumentNumber());
342            roleDocumentForm.getRoleDocument().addMember(newMember);
343            roleDocumentForm.setMember(roleDocumentForm.getRoleDocument().getBlankMember());
344        }
345        return mapping.findForward(RiceConstants.MAPPING_BASIC);
346    }
347
348    protected String checkMemberFullName(String principalId) {
349        Principal principal = getIdentityService().getPrincipal(principalId);
350        if (principal != null) {
351            Person psn = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(principal.getPrincipalName());
352            if (psn != null) {
353                return psn.getFirstName() + " " + psn.getLastName();
354            }
355        }
356        return null;
357    }
358
359    protected boolean checkKimDocumentRoleMember(KimDocumentRoleMember newMember) {
360        boolean memberExists = false;
361        String memberName = null;
362        String memberNamespace = null;
363
364        if (StringUtils.isBlank(newMember.getMemberId())) {
365            GlobalVariables.getMessageMap().putError("document.member.memberId", RiceKeyConstants.ERROR_EMPTY_ENTRY,
366                    new String[]{"Member ID"});
367            return false;
368        }
369
370        if (MemberType.PRINCIPAL.getCode().equals(newMember.getMemberTypeCode())) {
371            Principal pi = this.getIdentityService().getPrincipal(newMember.getMemberId());
372            if (pi != null) {
373                memberExists = true;
374                memberName = pi.getPrincipalName();
375                memberNamespace = "";
376            }
377        } else if (MemberType.GROUP.getCode().equals(newMember.getMemberTypeCode())) {
378            Group gi = KimApiServiceLocator.getGroupService().getGroup(newMember.getMemberId());
379            if (gi != null) {
380                memberExists = true;
381                memberName = gi.getName();
382                memberNamespace = gi.getNamespaceCode();
383            }
384        } else if (MemberType.ROLE.getCode().equals(newMember.getMemberTypeCode())) {
385            Role ri = KimApiServiceLocator.getRoleService().getRole(newMember.getMemberId());
386            if (!validateRole(newMember.getMemberId(), ri, "document.member.memberId", "Role")) {
387                return false;
388            } else {
389                memberExists = true;
390                memberName = ri.getName();
391                memberNamespace = ri.getNamespaceCode();
392            }
393        }
394
395        if (!memberExists) {
396            GlobalVariables.getMessageMap().putError("document.member.memberId", RiceKeyConstants.ERROR_MEMBERID_MEMBERTYPE_MISMATCH,
397                    new String[]{newMember.getMemberId()});
398            return false;
399        }
400        newMember.setMemberName(memberName);
401        newMember.setMemberNamespaceCode(memberNamespace);
402        return true;
403    }
404
405    public ActionForward deleteMember(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
406        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
407        KimDocumentRoleMember inactivatedRoleMember = roleDocumentForm.getRoleDocument().getModifiedMembers().get(getLineToDelete(request));
408
409        // KULRICE-4762: active delegates of "inactivated" role members cause validation problems
410        ActionForward forward = promptForAffectedDelegates(mapping, form, request, response,
411                roleDocumentForm, /* we haven't actually inactivated them yet, so specify them here */ inactivatedRoleMember);
412        // if we need to prompt the user due to affected delegates, do so:
413        if (forward != null) {
414            return forward;
415        }
416
417        Calendar cal = Calendar.getInstance();
418        inactivatedRoleMember.setActiveToDate(new Timestamp(cal.getTimeInMillis()));
419
420        roleDocumentForm.getRoleDocument().getModifiedMembers().set(getLineToDelete(request), inactivatedRoleMember);
421        return mapping.findForward(RiceConstants.MAPPING_BASIC);
422    }
423
424    public ActionForward editMember(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
425        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
426        KimDocumentRoleMember roleMemberToEdit = roleDocumentForm.getRoleDocument().getMembers().get(getLineToEdit(request));
427        KimDocumentRoleMember copiedMember = (KimDocumentRoleMember)ObjectUtils.deepCopy(roleMemberToEdit);
428        roleDocumentForm.getRoleDocument().getModifiedMembers().add(copiedMember);
429        roleDocumentForm.getRoleDocument().getMembers().remove(roleMemberToEdit);
430        return mapping.findForward(RiceConstants.MAPPING_BASIC);
431    }
432
433    public ActionForward editSearchResultsMember(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
434        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
435        KimDocumentRoleMember roleMemberToEdit = roleDocumentForm.getRoleDocument().getSearchResultMembers().get(getLineToEdit(request));
436        KimDocumentRoleMember copiedMember = (KimDocumentRoleMember)ObjectUtils.deepCopy(roleMemberToEdit);
437        roleDocumentForm.getRoleDocument().getModifiedMembers().add(copiedMember);
438        roleDocumentForm.getRoleDocument().getSearchResultMembers().remove(roleMemberToEdit);
439        roleDocumentForm.getRoleDocument().getMembers().remove(roleMemberToEdit);
440        return mapping.findForward(RiceConstants.MAPPING_BASIC);
441    }
442
443    public ActionForward search(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
444        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
445        String memberSearchValue = roleDocumentForm.getMemberSearchValue();
446        if (memberSearchValue != null && !memberSearchValue.isEmpty()) {
447            memberSearchValue = memberSearchValue.replaceAll("[%*]","");
448            getUiDocumentService().loadRoleMembersBasedOnSearch(roleDocumentForm.getRoleDocument(), memberSearchValue);
449        } else {
450            clear(mapping, form, request, response);
451        }
452        return mapping.findForward(RiceConstants.MAPPING_BASIC);
453    }
454
455    public ActionForward clear(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
456        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
457        roleDocumentForm.setMemberSearchValue("");
458        getUiDocumentService().clearRestrictedRoleMembersSearchResults(roleDocumentForm.getRoleDocument());
459
460        KualiTableRenderFormMetadata memberTableMetadata = roleDocumentForm.getMemberTableMetadata();
461        if (roleDocumentForm.getMemberRows() != null) {
462            memberTableMetadata.jumpToFirstPage(roleDocumentForm.getMemberRows().size(), roleDocumentForm.getRecordsPerPage());
463        }
464        return mapping.findForward(RiceConstants.MAPPING_BASIC);
465    }
466
467    public ActionForward deletePermission(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
468        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
469        roleDocumentForm.getRoleDocument().getPermissions().remove(getLineToDelete(request));
470        return mapping.findForward(RiceConstants.MAPPING_BASIC);
471    }
472
473    protected boolean checkDelegationMember(RoleDocumentDelegationMember newMember) {
474        if (StringUtils.isBlank(newMember.getMemberTypeCode()) || StringUtils.isBlank(newMember.getMemberId())) {
475            GlobalVariables.getMessageMap().putError("document.delegationMember.memberId", RiceKeyConstants.ERROR_EMPTY_ENTRY,
476                    new String[]{"Member Type Code and Member ID"});
477            return false;
478        }
479        if (MemberType.PRINCIPAL.getCode().equals(newMember.getMemberTypeCode())) {
480            Principal principalInfo = getIdentityService().getPrincipal(newMember.getMemberId());
481            if (principalInfo == null) {
482                GlobalVariables.getMessageMap().putError("document.delegationMember.memberId", RiceKeyConstants.ERROR_MEMBERID_MEMBERTYPE_MISMATCH,
483                        new String[]{newMember.getMemberId()});
484                return false;
485            } else {
486                newMember.setMemberName(principalInfo.getPrincipalName());
487            }
488        } else if (MemberType.GROUP.getCode().equals(newMember.getMemberTypeCode())) {
489            Group groupInfo = null;
490            groupInfo = getGroupService().getGroup(newMember.getMemberId());
491            if (groupInfo == null) {
492                GlobalVariables.getMessageMap().putError("document.delegationMember.memberId", RiceKeyConstants.ERROR_MEMBERID_MEMBERTYPE_MISMATCH,
493                        new String[]{newMember.getMemberId()});
494                return false;
495            } else {
496                newMember.setMemberName(groupInfo.getName());
497                newMember.setMemberNamespaceCode(groupInfo.getNamespaceCode());
498            }
499        } else if (MemberType.ROLE.getCode().equals(newMember.getMemberTypeCode())) {
500            Role roleInfo = KimApiServiceLocator.getRoleService().getRole(newMember.getMemberId());
501            if (roleInfo == null) {
502                GlobalVariables.getMessageMap().putError("document.delegationMember.memberId", RiceKeyConstants.ERROR_MEMBERID_MEMBERTYPE_MISMATCH,
503                        new String[]{newMember.getMemberId()});
504                return false;
505            } else {
506                newMember.setMemberName(roleInfo.getName());
507                newMember.setMemberNamespaceCode(roleInfo.getNamespaceCode());
508            }
509        }
510        return true;
511    }
512
513    public ActionForward addDelegationMember(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
514        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
515        RoleDocumentDelegationMember newDelegationMember = roleDocumentForm.getDelegationMember();
516
517        //See if possible to add with just Group Details filled in (not returned from lookup)
518        if (StringUtils.isEmpty(newDelegationMember.getMemberId())
519                && StringUtils.isNotEmpty(newDelegationMember.getMemberName())
520                && StringUtils.isNotEmpty(newDelegationMember.getMemberNamespaceCode())
521                && StringUtils.equals(newDelegationMember.getMemberTypeCode(), KimConstants.KimGroupMemberTypes.GROUP_MEMBER_TYPE.getCode())) {
522            Group tempGroup = KimApiServiceLocator.getGroupService().getGroupByNamespaceCodeAndName(
523                    newDelegationMember.getMemberNamespaceCode(), newDelegationMember.getMemberName());
524            if (tempGroup != null) {
525                newDelegationMember.setMemberId(tempGroup.getId());
526            }
527        }
528
529        //See if possible to grab details for Principal
530        if (StringUtils.isEmpty(newDelegationMember.getMemberId())
531                && StringUtils.isNotEmpty(newDelegationMember.getMemberName())
532                && StringUtils.equals(newDelegationMember.getMemberTypeCode(), KimConstants.KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE.getCode())) {
533            Principal principal = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName(newDelegationMember.getMemberName());
534            if (principal != null) {
535                newDelegationMember.setMemberId(principal.getPrincipalId());
536            }
537        }
538
539        if (checkDelegationMember(newDelegationMember) && KRADServiceLocatorWeb.getKualiRuleService().applyRules(
540                new AddDelegationMemberEvent("", roleDocumentForm.getRoleDocument(), newDelegationMember))) {
541            newDelegationMember.setDocumentNumber(roleDocumentForm.getDocument().getDocumentNumber());
542            if (StringUtils.isEmpty(newDelegationMember.getDelegationTypeCode())) {
543               newDelegationMember.setDelegationTypeCode(DelegationType.SECONDARY.getCode());
544            }
545            roleDocumentForm.getRoleDocument().addDelegationMember(newDelegationMember);
546            roleDocumentForm.setDelegationMember(roleDocumentForm.getRoleDocument().getBlankDelegationMember());
547        }
548        return mapping.findForward(RiceConstants.MAPPING_BASIC);
549    }
550
551    public ActionForward deleteDelegationMember(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
552        IdentityManagementRoleDocumentForm roleDocumentForm = (IdentityManagementRoleDocumentForm) form;
553        // Removing, not inactivating -- is this what we really want?
554        roleDocumentForm.getRoleDocument().getDelegationMembers().remove(getLineToDelete(request));
555        roleDocumentForm.setDelegationMember(roleDocumentForm.getRoleDocument().getBlankDelegationMember());
556        return mapping.findForward(RiceConstants.MAPPING_BASIC);
557    }
558
559    /**
560     * @see org.kuali.rice.kns.web.struts.action.KualiTableRenderAction#switchToPage(org.apache.struts.action.ActionMapping,
561     *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
562     */
563    public ActionForward jumpToRoleMember(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
564        IdentityManagementRoleDocumentForm idmForm = (IdentityManagementRoleDocumentForm) form;
565        String delegationRoleMemberId = getDelegationRoleMemberToJumpTo(request);
566        KualiTableRenderFormMetadata memberTableMetadata = idmForm.getMemberTableMetadata();
567        memberTableMetadata.jumpToPage(idmForm.getPageNumberOfRoleMemberId(delegationRoleMemberId),
568                idmForm.getMemberRows().size(), idmForm.getRecordsPerPage());
569        memberTableMetadata.setColumnToSortIndex(memberTableMetadata.getPreviouslySortedColumnIndex());
570        idmForm.setAnchor(delegationRoleMemberId);
571        return mapping.findForward(RiceConstants.MAPPING_BASIC);
572    }
573
574    protected String getDelegationRoleMemberToJumpTo(HttpServletRequest request) {
575        String delegationRoleMemberIdToJumpTo = "";
576        String parameterName = (String) request.getAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE);
577        if (StringUtils.isNotBlank(parameterName)) {
578            delegationRoleMemberIdToJumpTo = StringUtils.substringBetween(parameterName, ".dmrmi", ".");
579        }
580        return delegationRoleMemberIdToJumpTo;
581    }
582
583
584    /**
585     * Side-effecting method returns an ActionForward if needed for handling prompting of the user about automatically
586     * "inactivating" active delegates of inactive role members.  If the user has already responded "Yes", delegates are
587     * "inactivated" here, and a null forward is returned.  Otherwise, an appropriate forward is returned.
588     *
589     * @param roleMembersToConsiderInactive additional role members to consider inactive for the purposes of this computation
590     */
591    private ActionForward promptForAffectedDelegates(ActionMapping mapping,
592            ActionForm form, HttpServletRequest request,
593            HttpServletResponse response,
594            IdentityManagementRoleDocumentForm roleDocumentForm, KimDocumentRoleMember... roleMembersToConsiderInactive)
595            throws Exception {
596        // KULRICE-4762: Role: Removed an Assignee who has delegations associated with him and now the Role cannot be updated
597        // To solve this issue, prompt for confirmation if there are active delegates for the role member being "inactivated",
598        // and upon confirmation, "inactivate" the delegates too.
599        List<RoleDocumentDelegationMember> activeDelegatesOfInactiveRoleMembers =
600                getActiveDelegatesOfInactiveRoleMembers(roleDocumentForm, roleMembersToConsiderInactive);
601        ActionForward forward = getAffectedDelegatesQuestionActionForward(activeDelegatesOfInactiveRoleMembers, mapping, form, request,
602                response, roleDocumentForm);
603        // if the question logic gave us a forward, do it
604        if (forward != null) {
605            return forward;
606        }
607        // otherwise, inactivate affected delegates
608        if (activeDelegatesOfInactiveRoleMembers.size() > 0) {
609            Calendar cal = Calendar.getInstance();
610            // deactivate (inactivate?) delegates
611            for (RoleDocumentDelegationMember delegateToDeactivate : activeDelegatesOfInactiveRoleMembers) {
612                delegateToDeactivate.setActiveToDate(new Timestamp(cal.getTimeInMillis()));
613            }
614        }
615        return null;
616    }
617
618    /**
619     * <p>If there are active delegates of an "inactivated" role member, return an ActionForward to prompt the user
620     * letting them know that the delegates will be "inactivated" too if they proceed.
621     * <p>Also, if the user has already responded to the question and the response was (1) "Yes", then return null, signifying
622     * that we can go ahead and take the needed action to "inactivate" the delegates; or (2) "No", then return a basic forward that
623     * will cancel further action.
624     */
625    private ActionForward getAffectedDelegatesQuestionActionForward(List<RoleDocumentDelegationMember> activeDelegatesOfInactiveRoleMembers,
626            ActionMapping mapping, ActionForm form, HttpServletRequest request,
627            HttpServletResponse response,
628            IdentityManagementRoleDocumentForm roleDocumentForm)
629            throws Exception {
630
631        if (activeDelegatesOfInactiveRoleMembers.size() > 0) {
632            Object question = getQuestion(request);
633            // logic for delegates question
634            if (question == null || !REMOVE_AFFECTED_DELEGATES_QUESTION_ID.equals(question)) {
635                return performQuestionWithoutInput(mapping, form, request, response, REMOVE_AFFECTED_DELEGATES_QUESTION_ID,
636                        getKualiConfigurationService().getPropertyValueAsString(
637                                RiceKeyConstants.QUESTION_ACTIVE_DELEGATES_FOR_INACTIVE_MEMBERS),
638                        KRADConstants.CONFIRMATION_QUESTION, roleDocumentForm.getMethodToCall(), StringUtils.EMPTY);
639            }
640            Object buttonClicked = request.getParameter(KRADConstants.QUESTION_CLICKED_BUTTON);
641            if ((REMOVE_AFFECTED_DELEGATES_QUESTION_ID.equals(question)) && ConfirmationQuestion.YES.equals(buttonClicked)) {
642                // the question was answered in the affirmative.
643                // fall through, no special mapping to return
644            } else {
645                // NO was clicked ... what to do?  Return basic mapping without "inactivating" anything
646                return mapping.findForward(RiceConstants.MAPPING_BASIC);
647            }
648        }
649
650        return null;
651    }
652
653    /**
654     * This method returns a list of all active delegates for role members that are inactive
655     *
656     * @param roleDocumentForm              form bean
657     * @param roleMembersToConsiderInactive additional role members to consider inactive for the purposes of this computation
658     * @return the active delegates of inactive role members
659     */
660    private List<RoleDocumentDelegationMember> getActiveDelegatesOfInactiveRoleMembers(
661            IdentityManagementRoleDocumentForm roleDocumentForm, KimDocumentRoleMember... roleMembersToConsiderInactive) {
662        List<KimDocumentRoleMember> roleMembers = roleDocumentForm.getMemberRows();
663        List<KimDocumentRoleMember> inactiveRoleMembers = new ArrayList<KimDocumentRoleMember>();
664        List<RoleDocumentDelegationMember> activeDelegatesOfInactivatedRoleMembers = new ArrayList<RoleDocumentDelegationMember>();
665
666        inactiveRoleMembers.addAll(Arrays.asList(roleMembersToConsiderInactive));
667
668        if (roleMembers != null) {
669            for (KimDocumentRoleMember roleMember : roleMembers) {
670                if (roleMember != null) {
671                    if (!roleMember.isActive()) {
672                        inactiveRoleMembers.add(roleMember);
673                    }
674                }
675            }
676        }
677
678        for (KimDocumentRoleMember inactiveRoleMember : inactiveRoleMembers) {
679            // check if there are delegates for the member being removed
680            List<RoleDocumentDelegationMember> delegationMembers = roleDocumentForm.getRoleDocument().getDelegationMembers();
681            if (delegationMembers != null) {
682                for (RoleDocumentDelegationMember delegationMember : delegationMembers) {
683                    if (delegationMember != null && delegationMember.isActive()) {
684                        // if the roleMember for this delegation is the same as the inactivatedRoleMember
685                        if (delegationMember.getRoleMemberId().equals(inactiveRoleMember.getRoleMemberId())) {
686                            activeDelegatesOfInactivatedRoleMembers.add(delegationMember);
687                        }
688                    }
689                }
690            }
691        }
692        return activeDelegatesOfInactivatedRoleMembers;
693    }
694
695    /**
696     * This method overrides validateRole() from IdentityManagementDocumentActionBase.
697     * The difference with this method is that it allows derived roles.
698     * The base implementation returns false if the role is a derived role.
699     *
700     */
701    @Override
702    protected boolean validateRole(String roleId, Role role, String propertyName, String message) {
703        if (role == null) {
704            GlobalVariables.getMessageMap().putError(propertyName, RiceKeyConstants.ERROR_INVALID_ROLE, roleId);
705            return false;
706        }
707        return true;
708    }
709
710
711}