001    /**
002     * Copyright 2004-2013 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.hr.time.roles;
017    
018    import java.util.HashMap;
019    import java.util.HashSet;
020    import java.util.List;
021    import java.util.Map;
022    import java.util.Set;
023    
024    import org.apache.commons.collections.CollectionUtils;
025    import org.apache.commons.collections.MapUtils;
026    import org.apache.commons.lang.StringUtils;
027    import org.kuali.hr.core.document.calendar.CalendarDocumentContract;
028    import org.kuali.hr.job.Job;
029    import org.kuali.hr.time.assignment.Assignment;
030    import org.kuali.hr.time.department.Department;
031    import org.kuali.hr.time.service.base.TkServiceLocator;
032    import org.kuali.hr.time.timesheet.TimesheetDocument;
033    import org.kuali.hr.time.util.TKContext;
034    import org.kuali.hr.time.util.TKUtils;
035    import org.kuali.hr.time.util.TkConstants;
036    import org.kuali.rice.krad.util.GlobalVariables;
037    
038    /**
039     * TkUserRoles encapsulates the concept of roles for a single user and provides
040     * lookup methods for quick Role checking. This object will be stored in TkUser.
041     */
042    public class TkUserRoles implements UserRoles {
043        private boolean synchronousAssignments = false;
044        private TkRole globalViewOnly;
045        private TkRole systemAdmin;
046        private String principalId;
047    
048        private Map<String, TkRole> orgAdminRolesDept = new HashMap<String, TkRole>();
049        private Map<String, TkRole> orgAdminRolesChart = new HashMap<String, TkRole>();
050        private Map<Long, TkRole> approverRoles = new HashMap<Long, TkRole>();
051        private Map<Long, TkRole> approverDelegateRoles = new HashMap<Long, TkRole>();
052        private Map<Long, TkRole> reviewerRoles = new HashMap<Long, TkRole>();
053    
054        private Map<String, TkRole> deptViewOnlyRoles = new HashMap<String, TkRole>();
055        private Set<String> activeAssignmentIds = new HashSet<String>();
056        
057        public static TkUserRoles getUserRoles(String principalId) {
058            List<TkRole> roles = TkServiceLocator.getTkRoleService().getRoles(principalId, TKUtils.getCurrentDate());
059                    List<Assignment> assignments = TkServiceLocator.getAssignmentService().getAssignments(principalId, TKUtils.getCurrentDate());
060                    
061                    return new TkUserRoles(principalId, roles, assignments);
062        }
063    
064        /**
065         * Does not keep reference to the assignment objects.  We just need the IDs,
066         * so in future refactoring, if we have a lighter weight call to obtain
067         * assignments, we could use that and modify this code.
068         *
069         * @param roles
070         * @param assignments
071         */
072        private TkUserRoles(String principalId, List<TkRole> roles, List<Assignment> assignments) {
073            this.principalId = principalId;
074            setRoles(roles);
075            setAssignments(assignments);
076        }
077    
078        @Override
079        public boolean isLocationAdmin() {
080            return CollectionUtils.isNotEmpty(getOrgAdminCharts());
081        }
082    
083        @Override
084        public boolean isDepartmentAdmin() {
085            return CollectionUtils.isNotEmpty(getOrgAdminDepartments());
086        }
087    
088        public String getPrincipalId() {
089            return principalId;
090        }
091    
092        public void setPrincipalId(String principalId) {
093            this.principalId = principalId;
094        }
095    
096        @Override
097        public Set<Long> getApproverWorkAreas() {
098            Set<Long> workAreas = new HashSet<Long>();
099            workAreas.addAll(approverRoles.keySet());
100            workAreas.addAll(approverDelegateRoles.keySet());
101            return workAreas;
102        }
103    
104        @Override
105        public Set<Long> getReviewerWorkAreas() {
106            return reviewerRoles.keySet();
107        }
108    
109        @Override
110        public Set<String> getOrgAdminDepartments() {
111            return orgAdminRolesDept.keySet();
112        }
113    
114        @Override
115        public Set<String> getOrgAdminCharts() {
116            return orgAdminRolesChart.keySet();
117        }
118    
119        @Override
120        public Set<String> getDepartmentViewOnlyDepartments() {
121            return deptViewOnlyRoles.keySet();
122        }
123    
124        /**
125         * Accessor method to obtain the Set of active Assignment ids for the
126         * current employee.
127         *
128         * @return a Set of active assignment IDs
129         */
130        @Override
131        public Set<String> getActiveAssignmentIds() {
132            return activeAssignmentIds;
133        }
134    
135        @Override
136        public boolean isSystemAdmin() {
137            return systemAdmin != null;
138        }
139    
140        @Override
141        public boolean isGlobalViewOnly() {
142            return globalViewOnly != null;
143        }
144    
145        public boolean isDeptViewOnly() {
146            return MapUtils.isNotEmpty(deptViewOnlyRoles);
147        }
148    
149        @Override
150        public boolean isSynchronous() {
151            return synchronousAssignments;
152        }
153        
154            public boolean isReviewer() {
155                    return CollectionUtils.isNotEmpty(TkUserRoles.getUserRoles(GlobalVariables.getUserSession().getPrincipalId()).getReviewerWorkAreas());
156            }
157    
158            public boolean isApprover() {
159                    return CollectionUtils.isNotEmpty(TkUserRoles.getUserRoles(GlobalVariables.getUserSession().getPrincipalId()).getApproverWorkAreas());
160            }
161    
162        /**
163         * Place the TkRole objects in the provided List into their appropriate
164         * buckets for fast lookup.
165         *
166         * @param roles A List of TkRole objects for the current user.
167         */
168        public void setRoles(List<TkRole> roles) {
169            for (TkRole role : roles) {
170                if (role.getRoleName().equals(TkConstants.ROLE_TK_APPROVER)) {
171                    approverRoles.put(role.getWorkArea(), role);
172                } else if (role.getRoleName().equals(TkConstants.ROLE_TK_APPROVER_DELEGATE)) {
173                    approverDelegateRoles.put(role.getWorkArea(), role);
174                } else if (role.getRoleName().equals(TkConstants.ROLE_TK_LOCATION_ADMIN) ||
175                                    role.getRoleName().equals(TkConstants.ROLE_LV_DEPT_ADMIN)) {
176                    if (!StringUtils.isEmpty(role.getChart())) {
177                        orgAdminRolesChart.put(role.getChart(), role);
178                        List<Department> ds = TkServiceLocator.getDepartmentService().getDepartments(role.getChart(), TKUtils.getCurrentDate());
179                        for (Department d : ds) {
180                            orgAdminRolesDept.put(d.getDept(), role);
181                        }
182                    }
183                } else if (StringUtils.equals(role.getRoleName(), TkConstants.ROLE_TK_LOCATION_VO)) {
184                    if (!StringUtils.isEmpty(role.getChart())) {
185                        List<Department> ds = TkServiceLocator.getDepartmentService().getDepartments(role.getChart(), TKUtils.getCurrentDate());
186                        for (Department dept : ds) {
187                            deptViewOnlyRoles.put(dept.getDept(), role);
188                        }
189    
190                    }
191                } else if (role.getRoleName().equals(TkConstants.ROLE_TK_SYS_ADMIN)) {
192                    systemAdmin = role;
193                } else if (role.getRoleName().equals(TkConstants.ROLE_TK_DEPT_VO)) {
194                    deptViewOnlyRoles.put(role.getDepartment(), role);
195                } else if (role.getRoleName().equals(TkConstants.ROLE_TK_DEPT_ADMIN)) {
196                    orgAdminRolesDept.put(role.getDepartment(), role);
197                } else if (role.getRoleName().equals(TkConstants.ROLE_TK_GLOBAL_VO)) {
198                    globalViewOnly = role;
199                } else if (role.getRoleName().equals(TkConstants.ROLE_TK_REVIEWER)) {
200                    reviewerRoles.put(role.getWorkArea(), role);
201                }
202            }
203        }
204    
205        public void setAssignments(List<Assignment> assignments) {
206            for (Assignment a : assignments) {
207                activeAssignmentIds.add(a.getTkAssignmentId());
208                if (a.isSynchronous())
209                    synchronousAssignments = true;
210            }
211        }
212    
213        @Override
214        public boolean isActiveEmployee() {
215            return CollectionUtils.isNotEmpty(this.activeAssignmentIds);
216        }
217    
218        @Override
219        public boolean isTimesheetApprover() {
220            return MapUtils.isNotEmpty(this.approverRoles) || MapUtils.isNotEmpty(this.approverDelegateRoles);
221        }
222    
223        public boolean isTimesheetReviewer() {
224            return CollectionUtils.isNotEmpty(this.getReviewerWorkAreas());
225        }
226    
227        @Override
228        public boolean isAnyApproverActive() {
229            return MapUtils.isNotEmpty(this.approverRoles) || MapUtils.isNotEmpty(this.approverDelegateRoles);
230        }
231    
232        //Todo: rename method.  this is also used for leave calendar
233        @Override
234        public boolean isApproverForTimesheet(CalendarDocumentContract doc) {
235            boolean approver = false;
236    
237            if (this.isSystemAdmin()) {
238                return true;
239            }
240    
241            List<Assignment> assignments = doc.getAssignments();
242            for (Assignment assignment : assignments) {
243                if (this.approverRoles.containsKey(assignment.getWorkArea()) || this.approverDelegateRoles.containsKey(assignment.getWorkArea())) {
244                    return true;
245                }
246            }
247    
248            return approver;
249        }
250    
251        //Todo: rename method.  this is also used for leave calendar
252        @Override
253        public boolean isApproverForTimesheet(String docId) {
254            boolean approver = false;
255    
256            TimesheetDocument doc = TkServiceLocator.getTimesheetService().getTimesheetDocument(docId);
257            if (doc != null)
258                approver = isApproverForTimesheet(doc);
259    
260            return approver;
261        }
262    
263        @Override
264        public boolean isDocumentWritable(CalendarDocumentContract document) {
265            boolean writable = false;
266    
267            // Quick escape.
268            if (document == null)
269                return writable;
270    
271            // Sysadmin
272            writable = this.isSystemAdmin();
273            // Owner (and not enroute/final)
274            writable |= (StringUtils.equals(this.principalId, document.getDocumentHeader().getPrincipalId())
275                    && (StringUtils.equals(TkConstants.ROUTE_STATUS.INITIATED, document.getDocumentHeader().getDocumentStatus()) ||
276                    StringUtils.equals(TkConstants.ROUTE_STATUS.SAVED, document.getDocumentHeader().getDocumentStatus()) ||
277                    (StringUtils.equals(TkConstants.ROUTE_STATUS.ENROUTE, document.getDocumentHeader().getDocumentStatus()))));
278    
279    
280            if (!writable) {
281                // Departmental View Only? || Reviewer || Org Admin || Approver
282                // (document object iteration)
283                List<Assignment> assignments = document.getAssignments();
284                for (Assignment assignment : assignments) {
285                    String dept = assignment.getDept();
286                    Long wa = assignment.getWorkArea();
287                    // Dept admins should not have write access
288                    //writable |= this.orgAdminRolesDept.containsKey(dept);
289                    writable |= this.approverRoles.containsKey(wa);
290                    writable |= this.approverDelegateRoles.containsKey(wa);
291                    writable |= this.reviewerRoles.containsKey(wa);
292                }
293            }
294    
295            return writable;
296        }
297    
298        @Override
299        public boolean isDocumentWritable(String documentId) {
300            return isDocumentWritable(TkServiceLocator.getTimesheetService().getTimesheetDocument(documentId));
301        }
302    
303        @Override
304        public boolean isDocumentReadable(String documentId) {
305            boolean readable = false;
306    
307            if (documentId != null) {
308                return isDocumentReadable(TkServiceLocator.getTimesheetService().getTimesheetDocument(documentId));
309            }
310    
311            return readable;
312        }
313    
314        @Override
315        public boolean isDocumentReadable(CalendarDocumentContract document) {
316            boolean readable = false;
317    
318            // Quick escape.
319            if (document == null)
320                return readable;
321    
322            // Sysadmin
323            readable = this.isSystemAdmin();
324            // Owner
325            readable |= StringUtils.equals(this.principalId, document.getDocumentHeader().getPrincipalId());
326            // Global VO
327            readable |= this.isGlobalViewOnly();
328    
329            if (!readable) {
330                // Departmental View Only? || Reviewer || Org Admin || Approver
331                // (document object iteration)
332                List<Assignment> assignments = document.getAssignments();
333                for (Assignment assignment : assignments) {
334                    String dept = assignment.getDept();
335                    Long wa = assignment.getWorkArea();
336    
337                    readable |= this.orgAdminRolesDept.containsKey(dept);
338                    readable |= this.approverRoles.containsKey(wa);
339                    readable |= this.approverDelegateRoles.containsKey(wa);
340                    readable |= this.reviewerRoles.containsKey(wa);
341                    readable |= this.deptViewOnlyRoles.containsKey(dept);
342                    readable |= this.reviewerRoles.containsKey(wa);
343                }
344            }
345    
346            return readable;
347        }
348    
349        private boolean isLocationAdmin(CalendarDocumentContract doc) {
350            for (Assignment assign : doc.getAssignments()) {
351                String location = assign.getJob().getLocation();
352                return this.orgAdminRolesChart.containsKey(location);
353            }
354            return false;
355        }
356    
357        private boolean isDepartmentAdmin(CalendarDocumentContract doc) {
358            for (Assignment assign : doc.getAssignments()) {
359                String dept = assign.getDept();
360                return this.orgAdminRolesDept.containsKey(dept);
361            }
362            return false;
363        }
364    
365        @Override
366        public boolean canSubmitTimesheet(CalendarDocumentContract doc) {
367            if (StringUtils.equals(TKContext.getPrincipalId(), doc.getDocumentHeader().getPrincipalId())) {
368                return true;
369            }
370    
371            if (this.isApproverForTimesheet(doc)) {
372                return true;
373            }
374    
375            //System admins can route the document as well as the employee
376            if (this.isSystemAdmin()) {
377                return true;
378            }
379            return false;
380        }
381    
382        @Override
383        public boolean canSubmitTimesheet(String docId) {
384            TimesheetDocument doc = TkServiceLocator.getTimesheetService().getTimesheetDocument(docId);
385            return canSubmitTimesheet(doc);
386        }
387    
388        @Override
389        public boolean isApproverForPerson(String principalId) {
390            List<Assignment> lstAssignment = TkServiceLocator.getAssignmentService().getAssignments(principalId, TKUtils.getCurrentDate());
391    
392            Set<Long> workAreas = getUserRoles(GlobalVariables.getUserSession().getPrincipalId()).getApproverWorkAreas();
393            for (Assignment assignment : lstAssignment) {
394                if (workAreas.contains(assignment.getWorkArea())) {
395                    return true;
396                }
397            }
398    
399            return false;
400    
401        }
402    
403        @Override
404        public boolean isDepartmentAdminForPerson(String principalId) {
405            List<Job> jobs = TkServiceLocator.getJobService().getJobs(principalId,TKUtils.getCurrentDate());
406            for (Job job : jobs) {
407                if (getOrgAdminDepartments().contains(job.getDept())) {
408                    return true;
409                }
410            }
411            return false;
412        }
413    
414        @Override
415        public boolean isDeptViewOnlyForPerson(String principalId) {
416            List<Job> jobs = TkServiceLocator.getJobService().getJobs(principalId,TKUtils.getCurrentDate());
417            for (Job job : jobs) {
418                if (getDepartmentViewOnlyDepartments().contains(job.getDept())) {
419                    return true;
420                }
421            }
422            return false;
423        }
424    
425        @Override
426        public boolean isLocationAdminForPerson(String principalId) {
427            List<TkRole> roles = TkServiceLocator.getTkRoleService().getRoles(principalId, TKUtils.getCurrentDate());
428    
429            if (CollectionUtils.isNotEmpty(roles)) {
430                for (TkRole role : roles) {
431                    if (this.getOrgAdminCharts().contains(role.getChart())) {
432                        return true;
433                    }
434                }
435            }
436    
437            return false;
438        }
439    
440        @Override
441        public boolean isTimesheetReviewerForPerson(String principalId) {
442            List<Assignment> lstAssignment = TkServiceLocator.getAssignmentService().getAssignments(principalId, TKUtils.getCurrentDate());
443    
444            for (Assignment assignment : lstAssignment) {
445                if (getReviewerWorkAreas().contains(assignment.getWorkArea())) {
446                    return true;
447                }
448            }
449            return false;
450        }
451    }