2 * ============LICENSE_START====================================================
4 * ===========================================================================
5 * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
6 * ===========================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END====================================================
22 package org.onap.aaf.auth.gui.pages;
24 import java.io.IOException;
25 import java.net.ConnectException;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.Comparator;
29 import java.util.List;
31 import org.onap.aaf.auth.env.AuthzEnv;
32 import org.onap.aaf.auth.env.AuthzTrans;
33 import org.onap.aaf.auth.gui.AAF_GUI;
34 import org.onap.aaf.auth.gui.BreadCrumbs;
35 import org.onap.aaf.auth.gui.Form;
36 import org.onap.aaf.auth.gui.NamedCode;
37 import org.onap.aaf.auth.gui.Page;
38 import org.onap.aaf.auth.gui.Table;
39 import org.onap.aaf.auth.gui.Table.Cells;
40 import org.onap.aaf.auth.gui.table.AbsCell;
41 import org.onap.aaf.auth.gui.table.ButtonCell;
42 import org.onap.aaf.auth.gui.table.RadioCell;
43 import org.onap.aaf.auth.gui.table.TableData;
44 import org.onap.aaf.auth.gui.table.TextCell;
45 import org.onap.aaf.auth.gui.table.TextToolTipCell;
46 import org.onap.aaf.auth.org.Organization;
47 import org.onap.aaf.auth.org.Organization.Identity;
48 import org.onap.aaf.auth.org.OrganizationFactory;
49 import org.onap.aaf.cadi.CadiException;
50 import org.onap.aaf.cadi.client.Future;
51 import org.onap.aaf.cadi.client.Rcli;
52 import org.onap.aaf.cadi.client.Retryable;
53 import org.onap.aaf.misc.env.APIException;
54 import org.onap.aaf.misc.env.Env;
55 import org.onap.aaf.misc.env.Slot;
56 import org.onap.aaf.misc.env.TimeTaken;
57 import org.onap.aaf.misc.xgen.Cache;
58 import org.onap.aaf.misc.xgen.DynamicCode;
59 import org.onap.aaf.misc.xgen.Mark;
60 import org.onap.aaf.misc.xgen.html.HTMLGen;
62 import aaf.v2_0.Approval;
63 import aaf.v2_0.Approvals;
65 public class ApprovalForm extends Page {
67 static final String NAME="Approvals";
68 static final String HREF = "/gui/approve";
69 static final String[] FIELDS = new String[] {"line[]","user","delegate_of","as_user"};
72 public ApprovalForm(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException {
73 super(gui.env,NAME,HREF, FIELDS,
75 new BreadCrumbs(breadcrumbs),
76 new NamedCode(false, "filterByUser") {
78 public void code(final Cache<HTMLGen> cache, final HTMLGen hgen) throws APIException, IOException {
79 cache.dynamic(hgen, new DynamicCode<HTMLGen, AAF_GUI, AuthzTrans>() {
81 public void code(final AAF_GUI gui, final AuthzTrans trans, final Cache<HTMLGen> cache, final HTMLGen hgen) throws APIException, IOException {
82 String user = trans.get(trans.env().slot(NAME+".user"),"");
83 hgen.incr("p", "class=userFilter")
84 .text("Filter by User:")
85 .tagOnly("input", "type=text", "value="+user, "id=userTextBox")
86 .tagOnly("input", "type=button", "onclick=userFilter('"+HREF+"');", "value=Go!")
92 new Form(true,new Table<AAF_GUI,AuthzTrans>("Approval Requests", gui.env.newTransNoAvg(),new Model(gui.env),"class=stdform"))
93 .preamble("The following requires your Approval to proceed in the AAF System.</p><p class=subtext>Hover on Name for Identity; If Deny is the only option, User is no longer valid."),
94 new NamedCode(false, "selectAlljs") {
96 public void code(final Cache<HTMLGen> cache, final HTMLGen hgen) throws APIException, IOException {
97 Mark jsStart = new Mark();
99 hgen.text("function selectAll(radioClass) {");
100 hgen.text("var radios = document.querySelectorAll(\".\"+radioClass);");
101 hgen.text("for (i = 0; i < radios.length; i++) {");
102 hgen.text("radios[i].checked = true;");
111 * Implement the Table Content for Approvals
116 private static class Model extends TableData<AAF_GUI,AuthzTrans> {
117 //TODO come up with a generic way to do ILM Info (people page)
118 // private static final String TODO_ILM_INFO = "TODO: ILM Info";
121 private static final String[] headers = new String[] {"Identity","Request","Approve","Deny"};
123 private Slot sAsDelegate;
124 private Slot sAsUser;
126 public Model(AuthzEnv env) {
127 sUser = env.slot(NAME+".user");
128 sAsDelegate = env.slot(NAME+".delegate_of");
129 sAsUser = env.slot(NAME + ".as_user");
133 public String[] headers() {
138 public Cells get(final AuthzTrans trans, final AAF_GUI gui) {
139 final String userParam = trans.get(sUser, null);
141 final String asDelegate = trans.get(sAsDelegate, null);
142 final String approver;
143 if(asDelegate==null) {
144 approver = trans.get(sAsUser,trans.user());
146 approver = asDelegate;
149 ArrayList<AbsCell[]> rv = new ArrayList<>();
151 TimeTaken tt = trans.start("AAF Get Approvals for Approver",Env.REMOTE);
153 final List<Approval> pendingApprovals = new ArrayList<>();
154 final List<Integer> beginIndicesPerApprover = new ArrayList<>();
155 int numLeft = gui.clientAsUser(trans.getUserPrincipal(), new Retryable<Integer>() {
157 public Integer code(Rcli<?> client) throws CadiException, ConnectException, APIException {
158 Future<Approvals> fa = client.read("/authz/approval/approver/"+approver,gui.getDF(Approvals.class));
160 if (fa.get(AAF_GUI.TIMEOUT)) {
162 if (fa.value!=null) {
163 for (Approval appr : fa.value.getApprovals()) {
164 if ("pending".equals(appr.getStatus())) {
165 if (userParam!=null && !appr.getUser().equalsIgnoreCase(userParam)) {
169 pendingApprovals.add(appr);
174 String prevApprover = null;
175 int overallIndex = 0;
177 for (Approval appr : pendingApprovals) {
178 String currApprover = appr.getApprover();
179 if (!currApprover.equals(prevApprover)) {
180 prevApprover = currApprover;
181 beginIndicesPerApprover.add(overallIndex);
190 if (!pendingApprovals.isEmpty()) {
191 // Only add select all links if we have approvals
192 AbsCell[] selectAllRow = new AbsCell[] {
195 new ButtonCell("all", "onclick=selectAll('approve')", "class=selectAllButton"),
196 new ButtonCell("all", "onclick=selectAll('deny')", "class=selectAllButton")
198 rv.add(selectAllRow);
203 while (!beginIndicesPerApprover.isEmpty()) {
204 int beginIndex = beginIndicesPerApprover.remove(0);
205 int endIndex = (beginIndicesPerApprover.isEmpty()?pendingApprovals.size():beginIndicesPerApprover.get(0));
206 List<Approval> currApproverList = pendingApprovals.subList(beginIndex, endIndex);
208 Identity iapprover = trans.org().getIdentity(trans,currApproverList.get(0).getApprover());
209 if(iapprover==null) {
210 rv.add(new AbsCell[] {
211 new TextCell(currApproverList.get(0).getApprover() + " is not part of Organization",
212 new String[] {"colspan=4", "class=head"})
215 if (!iapprover.fullID().equals(trans.user())) {
217 AbsCell[] approverHeader;
218 // if (domainOfUser.equals(domainOfApprover)) {
219 // approverHeader = new AbsCell[] {
220 // new TextAndRefCell("Approvals Delegated to Me by ", currApproverFull,
221 // TODO_ILM_INFO + currApproverShort,
223 // new String[] {"colspan=4", "class=head"})
226 approverHeader = new AbsCell[] {
227 new TextCell("Approvals Delegated to Me by " + iapprover.fullName()
228 + '(' + iapprover.id() + ')',
229 new String[] {"colspan=4", "class=head"})
232 rv.add(approverHeader);
235 // Sort by User Requesting
236 Collections.sort(currApproverList, new Comparator<Approval>() {
238 public int compare(Approval a1, Approval a2) {
239 return a1.getUser().compareTo(a2.getUser());
243 String prevUser = null;
245 for (Approval appr : currApproverList) {
246 if (++line<MAX_LINE) { // limit number displayed at one time.
248 String user = appr.getUser();
250 if (user.equals(prevUser)) {
251 userCell = AbsCell.Null;
252 } else if (user.endsWith(trans.org().getRealm())){
255 Organization org = OrganizationFactory.obtain(trans.env(), user);
258 userCell = new TextCell(user);
260 Identity au = org.getIdentity(trans, user);
263 userCell = new TextToolTipCell(au.fullName(),"Identity: " + au.id());
265 Identity managedBy = au.responsibleTo();
266 if (managedBy==null) {
267 title ="Identity: " + au.type();
269 title="Sponsor: " + managedBy.fullName();
271 userCell = new TextToolTipCell(au.fullID(),title);
275 title="Not a User at " + org.getName();
276 userCell = new TextToolTipCell(user,title);
279 // userCell = new RefCell(prevUser,
280 // TODO_ILM_INFO+user.substring(0, user.length()-domainOfApprover.length()),
285 userCell = new TextCell(user);
287 AbsCell[] sa = new AbsCell[] {
289 new TextCell(appr.getMemo()),
290 userOK?new RadioCell("line."+ line,"approve", "approved|"+appr.getTicket()):new TextCell(""),
291 new RadioCell("line."+ line,"deny", "denied|"+appr.getTicket())
301 msg = "After these, there will be " + numLeft + " approvals left to process";
305 msg = "No Approvals to process at this time for user " + userParam +". You have "
306 + numLeft + " other approvals to process.";
308 msg = "No Approvals to process at this time";
312 } catch (Exception e) {
313 trans.error().log(e);
317 return new Cells(rv,msg);