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