Batch Test improvements 97/82197/1
authorInstrumental <jonathan.gathman@att.com>
Wed, 13 Mar 2019 22:33:51 +0000 (17:33 -0500)
committerInstrumental <jonathan.gathman@att.com>
Wed, 13 Mar 2019 22:35:55 +0000 (17:35 -0500)
Issue-ID: AAF-776
Change-Id: Ia12106331a1db608955abd353785ab2e765b3c41
Signed-off-by: Instrumental <jonathan.gathman@att.com>
26 files changed:
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/Batch.java
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/approvalsets/ApprovalSet.java
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/approvalsets/Pending.java
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/approvalsets/URApprovalSet.java
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/CQLBatch.java
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/ExpireRange.java
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/Future.java
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/LastNotified.java
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/Notification.java [deleted file]
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/UserRole.java
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/Analyze.java
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/Notify.java
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/bodies/NotifyCredBody.java
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/bodies/OneMonthNotifyCredBody.java
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/bodies/TwoMonthNotifyCredBody.java
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/bodies/TwoWeeksNotifyCredBody.java
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/update/Approvals.java
auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/update/Extend.java
auth/auth-batch/src/test/java/org/onap/aaf/auth/batch/test/JU_NotificationTest.java [deleted file]
auth/auth-cass/cass_init/init.cql
auth/auth-cass/cass_init/init2_10.cql
auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/LocalCA.java
auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApprovalForm.java
auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/TextToolTipCell.java [new file with mode: 0644]
cadi/core/src/main/java/org/onap/aaf/cadi/filter/CadiFilter.java
cadi/core/src/main/java/org/onap/aaf/cadi/util/CSV.java

index 1c65c05..a588b80 100644 (file)
@@ -149,7 +149,7 @@ public abstract class Batch {
     }
 
     protected abstract void run(AuthzTrans trans);
-    protected abstract void _close(AuthzTrans trans);
+    protected void _close(AuthzTrans trans) {}
     
     public String[] args() {
         return env.get(ssargs);
@@ -363,7 +363,12 @@ public abstract class Batch {
 
     public final void close(AuthzTrans trans) {
         _close(trans);
-        cluster.close();
+        if(session!=null) {
+               session.close();
+        }
+        if(cluster!=null) {
+            cluster.close();
+        }
     }
 
     public static void main(String[] args) {
index b7176c2..500906d 100644 (file)
@@ -25,7 +25,9 @@ import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
 import java.util.ArrayList;
 import java.util.GregorianCalendar;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.UUID;
 
 import org.onap.aaf.auth.dao.cass.ApprovalDAO;
@@ -93,4 +95,16 @@ public class ApprovalSet {
                }
                return errs==null?Result.ok():Result.err(Result.ERR_Backend,errs.toString());
        }
+
+       public boolean hasApprovals() {
+               return !ladd.isEmpty();
+       }
+       
+       public Set<String> approvers() {
+               Set<String> rv = new HashSet<>();
+               for(ApprovalDAO.Data app : ladd) {
+                       rv.add(app.approver);
+               }
+               return rv;
+       }
 }
\ No newline at end of file
index 3072038..5d720c2 100644 (file)
@@ -34,15 +34,6 @@ public class Pending {
        boolean hasNew;
        Date earliest;
        
-       /**
-        * Use this Constructor when there is no Last Notified Date
-        */
-       public Pending() {
-               qty = 1;
-               hasNew = true;
-               earliest = null;
-       }
-
        /**
         * Use this constructor to indicate when last Notified
         * @param last_notified
@@ -84,6 +75,11 @@ public class Pending {
        
        public void inc(Pending value) {
                qty+=value.qty;
+               if(earliest==null) {
+                       earliest = value.earliest;
+               } else if(value.earliest!=null && value.earliest.before(earliest)) {
+                       earliest = value.earliest;
+               }
        }
 
        public void earliest(Date lastnotified) {
@@ -106,4 +102,8 @@ public class Pending {
                return hasNew;
        }
 
+       public static Pending create() {
+               return new Pending((Date)null);
+       }
+
 }
\ No newline at end of file
index 2c1ffe6..7f7bff2 100644 (file)
@@ -49,8 +49,12 @@ public class URApprovalSet extends ApprovalSet {
                UserRoleDAO.Data urdd = lurdd.load();
                setConstruct(urdd.bytify());
                setMemo(getMemo(urdd));
-               setExpires(org.expiration(null, Organization.Expiration.UserInRole));
-               setTargetKey(urdd.role);
+               GregorianCalendar expires = org.expiration(null, Organization.Expiration.UserInRole);
+               if(urdd.expires.before(expires.getTime())) {
+                       expires.setTime(urdd.expires);
+               }
+               setExpires(expires);
+               setTargetKey(urdd.user+'|'+urdd.role);
                setTargetDate(urdd.expires);
                
                Result<RoleDAO.Data> r = dv.roleByName(trans, urdd.role);
index 738c534..9f685ad 100644 (file)
@@ -84,4 +84,8 @@ public class CQLBatch {
                }
                execute(dryRun);
        }
+       
+       public String toString() {
+               return sb.toString();
+       }
 }
index 73bff6e..13d74c8 100644 (file)
@@ -40,12 +40,11 @@ public class ExpireRange {
        public static final String ONE_WEEK = "OneWeek";
        private static final String AAF_BATCH_RANGE = "aaf_batch_range.";
        public Map<String,List<Range>> ranges;
-       public final Date now;
+       public static final Date now = new Date();
 
        private Range delRange;
        
        public ExpireRange(final Access access) {
-               now = new Date();
                ranges = new HashMap<>();
                int i=0;
                String prop = access.getProperty(AAF_BATCH_RANGE + i,null);
@@ -70,6 +69,10 @@ public class ExpireRange {
                        }
        }
        
+       public static Range newFutureRange() {
+               return new Range("Approval",1,1,0,0,GregorianCalendar.MONTH,1);
+       }
+       
        public Set<String> names() {
                Set<String> names = new HashSet<>();
         for(List<Range> lr : ranges.values()) {
@@ -90,7 +93,7 @@ public class ExpireRange {
                return rv;
        }
        
-       public class Range {
+       public static class Range {
                private final String name;
                private final int reportingLevel;
                private final int interval; // in Days
@@ -138,7 +141,7 @@ public class ExpireRange {
                        return end;
                }
                
-               private boolean inRange(final Date date) {
+               public boolean inRange(final Date date) {
                        if(date==null) {
                                return false;
                        } else {
index 13f8193..4f87e33 100644 (file)
@@ -23,6 +23,7 @@
 
 package org.onap.aaf.auth.batch.helpers;
 
+import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Date;
@@ -32,6 +33,7 @@ import java.util.TreeMap;
 import java.util.UUID;
 
 import org.onap.aaf.auth.dao.cass.FutureDAO;
+import org.onap.aaf.auth.dao.cass.UserRoleDAO;
 import org.onap.aaf.auth.env.AuthzTrans;
 import org.onap.aaf.auth.layer.Result;
 import org.onap.aaf.cadi.util.CSV;
@@ -90,7 +92,21 @@ public class Future implements CacheChange.Data, Comparable<Future> {
         fdd.start = start;
         fdd.expires = expires;
         fdd.construct = construct;
-        role = Approval.roleFromMemo(memo);
+        String role = null;
+        switch(target) {
+               case "user_role":
+                       UserRoleDAO.Data urdd = new UserRoleDAO.Data();
+                       try {
+                               urdd.reconstitute(construct);
+                               fdd.target_key = urdd.user + '|' + urdd.role;
+                               fdd.target_date=urdd.expires;
+                               role=urdd.role;
+                       } catch (IOException e) {
+                               e.printStackTrace(System.err);
+                       }
+                       break;
+        }
+       this.role = role;
     }
     
     public final UUID id() {
index 22231f3..0539fcd 100644 (file)
@@ -28,7 +28,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
 
-import org.onap.aaf.auth.batch.helpers.Notification.TYPE;
+import org.onap.aaf.auth.dao.cass.UserRoleDAO;
 
 import com.datastax.driver.core.ResultSet;
 import com.datastax.driver.core.Row;
@@ -37,6 +37,7 @@ import com.datastax.driver.core.Session;
 public class LastNotified {
        private Map<String,Date> lastNotified = new TreeMap<>();
        private Session session;
+       public static final Date never = new Date(0);
        
        public LastNotified(Session session) {
                this.session = session;
@@ -44,7 +45,7 @@ public class LastNotified {
        
        public void add(Set<String> users) {
                StringBuilder query = new StringBuilder();
-               startNotifyQuery(query);
+               startQuery(query);
                int cnt = 0;
        for(String user : users) {
                if(++cnt>1) {
@@ -54,37 +55,74 @@ public class LastNotified {
                query.append(user);
                query.append('\'');
                if(cnt>=30) {
-                       endNotifyQuery(query, Notification.TYPE.OA);
+                       endQuery(query);
                        add(session.execute(query.toString()),lastNotified);
                        query.setLength(0);
-                       startNotifyQuery(query);
+                       startQuery(query);
                        cnt=0;
                }
        }
        if(cnt>0) {
-               endNotifyQuery(query, Notification.TYPE.OA);
+               endQuery(query);
                        add(session.execute(query.toString()),lastNotified);
        }
        }
 
-       public Date lastNotified(String user) {
-               return lastNotified.get(user);
+       /**
+        * Note: target_key CAN also contain a Pipe.
+        * 
+        * @param user
+        * @param target
+        * @param target_key
+        * @return
+        */
+       public Date lastNotified(String user, String target, String target_key) {
+               String key = user + '|' + target + '|' + target_key;
+               return lastNotified(key);
        }
        
-       private void add(ResultSet result, Map<String, Date> lastNotified) {
+       public Date lastNotified(String key) {
+               Date rv = lastNotified.get(key);
+               if(rv==null) {
+                       rv = never;
+                       lastNotified.put(key, rv);
+               }
+               return rv;
+       }
+       
+       private Date add(ResultSet result, Map<String, Date> lastNotified) {
+               Date last = null;
        for(Iterator<Row> iter = result.iterator(); iter.hasNext();) {
                Row r = iter.next();
-               lastNotified.put(r.getString(0), r.getTimestamp(1));
+               String key = r.getString(0) + '|' +
+                                    r.getString(1) + '|' +
+                                    r.getString(2);
+               
+               lastNotified.put(key, last=r.getTimestamp(3));
        }
+       return last;
        }
 
-       private void startNotifyQuery(StringBuilder query) {
-               query.append("SELECT user,last FROM authz.notify WHERE user in (");
+       private void startQuery(StringBuilder query) {
+               query.append("SELECT user,target,key,last FROM authz.notified WHERE user in (");
        }
-    
-    private void endNotifyQuery(StringBuilder query, TYPE oa) {
-       query.append(") AND type=");
-       query.append(oa.idx());
-       query.append(';');
-    }
+
+       private void endQuery(StringBuilder query) {
+               query.append(");");
+       }
+
+       public void update(StringBuilder query,String user, String target, String key) {
+               query.append("UPDATE authz.notified SET last=dateof(now()) WHERE user='");
+               query.append(user);
+               query.append("' AND target='");
+               query.append(target);
+               query.append("' AND key='");
+               query.append(key);
+               query.append("';");
+       }
+
+       public static String newKey(UserRoleDAO.Data urdd) {
+               return urdd.user + "|ur|" + urdd.role;
+       }
+
 }
diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/Notification.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/Notification.java
deleted file mode 100644 (file)
index ae0d37b..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/**
- * ============LICENSE_START====================================================
- * org.onap.aaf
- * ===========================================================================
- * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
- * ===========================================================================
- * Modifications Copyright (C) 2018 IBM.
- * ===========================================================================
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ============LICENSE_END====================================================
- *
- */
-
-package org.onap.aaf.auth.batch.helpers;
-
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.TreeMap;
-
-import org.onap.aaf.auth.batch.actions.Message;
-import org.onap.aaf.auth.env.AuthzTrans;
-import org.onap.aaf.auth.org.Organization;
-import org.onap.aaf.misc.env.Env;
-import org.onap.aaf.misc.env.TimeTaken;
-import org.onap.aaf.misc.env.Trans;
-import org.onap.aaf.misc.env.util.Chrono;
-
-import com.datastax.driver.core.ResultSet;
-import com.datastax.driver.core.Row;
-import com.datastax.driver.core.Session;
-import com.datastax.driver.core.SimpleStatement;
-import com.datastax.driver.core.Statement;
-
-public class Notification {
-    public enum TYPE {
-        OA("Owner Approval",1),SA("Supervisor Approval",2),CN("Credential Expiration",20);
-        
-        private String desc;
-        private int type;
-    
-        private TYPE(String desc,int type) {
-            this.desc = desc;
-            this.type = type;
-        }
-        
-        public String desc() {
-            return desc;
-        }
-        
-        public int idx() {
-            return type;
-        }
-
-        public static TYPE get(int idx) {
-            for (TYPE nt : TYPE.values()) {
-                if (idx==nt.type) {
-                    return nt;
-                }
-            }
-            return null;
-        }
-    }
-
-
-    public static final TreeMap<String,List<Notification>> data = new TreeMap<>();
-    public static final Date now = new Date();
-    
-    public final String user;
-    public final TYPE type;
-    public Date last;
-    public int checkSum;
-    public Message msg;
-    private int current;
-    public Organization org;
-    public int count;
-
-    public static Creator<Notification> v2_0_18 = new Creator<Notification>() {
-        @Override
-        public Notification create(Row row) {
-            int idx =row.getInt(1);
-            TYPE typeCreator = TYPE.get(idx);
-            if (typeCreator==null) {
-                return null;
-            }
-            return new Notification(row.getString(0), typeCreator, row.getTimestamp(2), row.getInt(3));
-        }
-
-        @Override
-        public String select() {
-            return "SELECT user,type,last,checksum FROM authz.notify LIMIT 100000";
-        }
-    };
-    
-    private Notification(String user, TYPE nt, Date last, int checksum) {
-        this.user = user;
-        this.type = nt;
-        this.last = last;
-        this.checkSum = checksum;
-        current = 0;
-        count = 0;
-    }
-    
-    public static void load(Trans trans, Session session, Creator<Notification> creator ) {
-        trans.info().log( "query: " + creator.select() );
-        TimeTaken tt = trans.start("Load Notify", Env.REMOTE);
-       
-        ResultSet results;
-        try {
-            Statement stmt = new SimpleStatement(creator.select());
-            results = session.execute(stmt);
-        } finally {
-            tt.done();
-        }
-        int count = 0;
-        tt = trans.start("Process Notify", Env.SUB);
-
-        try {
-            for (Row row : results.all()) {
-                ++count;
-                try {
-                    Notification not = creator.create(row);
-                    List<Notification> ln = data.get(not.user);
-                    if (ln==null) {
-                        ln = new ArrayList<>();
-                        data.put(not.user, ln);
-                    }
-                    ln.add(not);
-                } finally {
-                    tt.done();
-                }
-            }
-        } finally {
-            tt.done();
-            trans.info().log("Found",count,"Notify Records");
-        }
-    }
-    
-    public static Notification get(String user, TYPE type) {
-        List<Notification> ln = data.get(user);
-        if (ln!=null) {
-            for (Notification n : ln) {
-                if (type.equals(n.type)) {
-                    return n;
-                }
-            }
-        }
-        return null;
-    }
-
-    public static Notification create(String user, TYPE type) {
-        return new Notification(user,type,null,0);
-    }
-
-    
-    public void set(Message msg) {
-        this.msg = msg; 
-    }
-
-    public int checksum() {
-        if (msg==null) {
-            current=0;
-        } else if (current==0) {
-            for (String l : msg.lines) {
-                for (byte b : l.getBytes()) {
-                    current+=b;
-                }
-            }
-        }
-        return current;
-    }
-    
-    public boolean update(AuthzTrans trans, Session session, boolean dryRun) {
-        checksum();
-        if (last==null || current==0 || current!=checkSum) {
-            last = now;
-            current = checksum();
-            String update = "UPDATE authz.notify SET " +
-                    "last = '" + Chrono.utcStamp(last) +
-                    "', checksum=" +
-                    current +
-                    " WHERE user='" +
-                    user + 
-                    "' AND type=" +
-                    type.idx() +
-                    ";";
-            if (dryRun) {
-                trans.info().log("Would",update);
-            } else {
-                session.execute(update);
-            }
-            return true;
-        }
-        return false;
-    }
-
-    public String toString() {
-        return "\"" + user + "\",\"" + type.name() + "\",\"" 
-                + Chrono.dateTime(last)+ "\", "  + checkSum;
-    }
-}
\ No newline at end of file
index 55dd1e7..343a0e2 100644 (file)
@@ -122,12 +122,12 @@ public class UserRole implements Cloneable, CacheChange.Data  {
     }
     
     public static void loadOneUser(Trans trans, Session session, Creator<UserRole> creator, String user, Visitor<UserRole> visitor ) {
-        load(trans,session,creator,"role='"+ user +"';",visitor);
+        load(trans,session,creator,"user='"+ user +'\'',visitor);
     }
 
     private static void load(Trans trans, Session session, Creator<UserRole> creator, String where, Visitor<UserRole> visitor) {
         String query = creator.query(where);
-        trans.info().log( "query: " + query );
+        trans.debug().log( "query: " + query );
         TimeTaken tt = trans.start("Read UserRoles", Env.REMOTE);
 
         ResultSet results;
@@ -145,7 +145,7 @@ public class UserRole implements Cloneable, CacheChange.Data  {
                 tt.done();
             }
         } finally {
-            trans.info().log("Loaded",totalLoaded,"UserRoles");
+            trans.debug().log("Loaded",totalLoaded,"UserRoles");
         }
     }
 
@@ -337,16 +337,26 @@ public class UserRole implements Cloneable, CacheChange.Data  {
        sb.append("';\n");
     }
 
-    public static void batchExtend(StringBuilder sb, List<String> row, String newDate ) {
+    public static void batchExtend(StringBuilder sb, List<String> row, Date newDate ) {
        sb.append("UPDATE authz.user_role SET expires='");
-       sb.append(newDate);
+       sb.append(Chrono.dateTime(newDate));
        sb.append("' WHERE user='");
        sb.append(row.get(1));
        sb.append("' AND role='");
        sb.append(row.get(2));
        sb.append("';\n");
     }
-    
+
+    public void batchUpdateExpires(StringBuilder sb) {
+       sb.append("UPDATE authz.user_role SET expires='");
+       sb.append(Chrono.dateTime(expires()));
+       sb.append("' WHERE user='");
+       sb.append(user());
+       sb.append("' AND role='");
+       sb.append(role());
+       sb.append("';\n");
+    }
+
        public static String histMemo(String fmt, List<String> row) {
                String reason;
                if(row.size()>7) { // Reason included
index a0dce74..70c950e 100644 (file)
@@ -38,6 +38,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.TreeMap;
+import java.util.TreeSet;
 import java.util.UUID;
 
 import org.onap.aaf.auth.batch.Batch;
@@ -49,6 +50,7 @@ import org.onap.aaf.auth.batch.helpers.Cred.Instance;
 import org.onap.aaf.auth.batch.helpers.ExpireRange;
 import org.onap.aaf.auth.batch.helpers.ExpireRange.Range;
 import org.onap.aaf.auth.batch.helpers.Future;
+import org.onap.aaf.auth.batch.helpers.LastNotified;
 import org.onap.aaf.auth.batch.helpers.Role;
 import org.onap.aaf.auth.batch.helpers.UserRole;
 import org.onap.aaf.auth.batch.helpers.X509;
@@ -87,6 +89,8 @@ public class Analyze extends Batch {
        private CSV.Writer deleteCW;
        private CSV.Writer approveCW;
        private CSV.Writer extendCW;
+       private Range futureRange;
+       private final String sdate;
        
        public Analyze(AuthzTrans trans) throws APIException, IOException, OrganizationException {
         super(trans.env());
@@ -110,14 +114,14 @@ public class Analyze extends Batch {
             writerList = new HashMap<>();
             
             expireRange = new ExpireRange(trans.env().access());
-            String sdate = Chrono.dateOnlyStamp(expireRange.now);
+            sdate = Chrono.dateOnlyStamp(ExpireRange.now);
             for( List<Range> lr : expireRange.ranges.values()) {
                for(Range r : lr ) {
                        if(writerList.get(r.name())==null) {
                        File file = new File(logDir(),r.name() + sdate +CSV);
                        CSV csv = new CSV(env.access(),file);
                        CSV.Writer cw = csv.writer(false);
-                       cw.row(INFO,r.name(),Chrono.dateOnlyStamp(expireRange.now),r.reportingLevel());
+                       cw.row(INFO,r.name(),sdate,r.reportingLevel());
                        writerList.put(r.name(),cw);
                        if("Delete".equals(r.name())) {
                                deleteDate = r.getEnd();
@@ -129,17 +133,18 @@ public class Analyze extends Batch {
             }
             
             // Setup New Approvals file
+            futureRange = ExpireRange.newFutureRange();
             File file = new File(logDir(),APPROVALS + sdate +CSV);
             CSV approveCSV = new CSV(env.access(),file);
             approveCW = approveCSV.writer();
-            approveCW.row(INFO,APPROVALS,Chrono.dateOnlyStamp(expireRange.now),1);
+            approveCW.row(INFO,APPROVALS,sdate,1);
             writerList.put(APPROVALS,approveCW);
             
             // Setup Extend Approvals file
             file = new File(logDir(),EXTEND + sdate +CSV);
             CSV extendCSV = new CSV(env.access(),file);
             extendCW = extendCSV.writer();
-            extendCW.row(INFO,EXTEND,Chrono.dateOnlyStamp(expireRange.now),1);
+            extendCW.row(INFO,EXTEND,sdate,1);
             writerList.put(EXTEND,extendCW);
             
             // Load full data of the following
@@ -160,7 +165,7 @@ public class Analyze extends Batch {
        try {
                        Future.load(noAvg, session, Future.withConstruct, fut -> {
                                List<Approval> appls = Approval.byTicket.get(fut.id());
-                               if(fut.expires().before(expireRange.now)) {
+                               if(!futureRange.inRange(fut.expires())) {
                                        deleteCW.comment("Future %s expired", fut.id());
                                        Future.row(deleteCW,fut);
                                        if(appls!=null) {
@@ -179,6 +184,7 @@ public class Analyze extends Batch {
                tt.done();
        }
                
+       Set<String> approvers = new TreeSet<>();
        tt = trans.start("Connect Approvals with Futures",Trans.SUB);
        try {
                        for(Approval appr : Approval.list) {
@@ -192,6 +198,7 @@ public class Analyze extends Batch {
                                        Approval.row(deleteCW, appr);
                                } else {
                                        ticket.approvals.add(appr); // add to found Ticket
+                                       approvers.add(appr.getApprover());
                                }
                        }
        } finally {
@@ -205,78 +212,98 @@ public class Analyze extends Batch {
                Map<String,Pending> pendingApprs = new HashMap<>();
                Map<String,Pending> pendingTemp = new HashMap<>();
 
+               // Convert Good Tickets to keyed User/Role for UserRole Step
+               Map<String,Ticket> mur = new TreeMap<>();
+               LastNotified ln = new LastNotified(session);
+               ln.add(approvers);
+               String approver;
+               
                tt = trans.start("Analyze Good Tickets",Trans.SUB);
                try {
                        for(Ticket ticket : goodTickets.values()) {
-                               pendingTemp.clear();
-                               switch(ticket.f.target()) {
-                                       case "user_role":
-                                               int state[][] = new int[3][3];
-                                               int type;
-                                                               
-                                               for(Approval appr : ticket.approvals) {
-                                                       switch(appr.getType()) {
-                                                               case "owner":
-                                                                       type=owner;
-                                                                       break;
-                                                               case "supervisor":
-                                                                       type=supervisor;
-                                                                       break;
-                                                               default:
-                                                                       type=0;
+                               try {
+                                       pendingTemp.clear();
+                                       switch(ticket.f.target()) {
+                                               case "user_role":
+                                                       int state[][] = new int[3][3];
+                                                       int type;
+                                                                       
+                                                       for(Approval appr : ticket.approvals) {
+                                                               switch(appr.getType()) {
+                                                                       case "owner":
+                                                                               type=owner;
+                                                                               break;
+                                                                       case "supervisor":
+                                                                               type=supervisor;
+                                                                               break;
+                                                                       default:
+                                                                               type=0;
+                                                               }
+                                                               ++state[type][total]; // count per type
+                                                               switch(appr.getStatus()) {
+                                                                       case "pending":
+                                                                               ++state[type][pending];
+                                                                               approver = appr.getApprover();
+                                                                               Pending n = pendingTemp.get(approver);
+                                                                               if(n==null) {
+                                                                                       Date lastNotified = ln.lastNotified(approver,"ur",ticket.f.fdd.target_key);
+                                                                                       pendingTemp.put(approver,new Pending(lastNotified));
+                                                                               } else {
+                                                                                       n.inc();
+                                                                               }
+                                                                               break;
+                                                                       case "approved":
+                                                                               ++state[type][approved];
+                                                                               break;
+                                                                       default:
+                                                                               ++state[type][unknown];
+                                                               }
                                                        }
-                                                       ++state[type][total]; // count per type
-                                                       switch(appr.getStatus()) {
-                                                               case "pending":
-                                                                       ++state[type][pending];
-                                                                       Pending n = pendingTemp.get(appr.getApprover());
-                                                                       if(n==null) {
-                                                                               pendingTemp.put(appr.getApprover(),new Pending());
-                                                                       } else {
-                                                                               n.inc();
+                                                       
+                                                       // To Approve:
+                                                       // Always must have at least 1 owner
+                                                       if((state[owner][total]>0 && state[owner][approved]>0) &&
+                                                               // If there are no Supervisors, that's ok
+                                                           (state[supervisor][total]==0 || 
+                                                           // But if there is a Supervisor, they must have approved 
+                                                           (state[supervisor][approved]>0))) {
+                                                                       UserRoleDAO.Data urdd = new UserRoleDAO.Data();
+                                                                       try {
+                                                                               urdd.reconstitute(ticket.f.fdd.construct);
+                                                                               if(urdd.expires.before(ticket.f.expires())) {
+                                                                                       extendCW.row("extend_ur",urdd.user,urdd.role,ticket.f.expires());
+                                                                               }
+                                                                       } catch (IOException e) {
+                                                                               trans.error().log("Could not reconstitute UserRole");
                                                                        }
-                                                                       break;
-                                                               case "approved":
-                                                                       ++state[type][approved];
-                                                                       break;
-                                                               default:
-                                                                       ++state[type][unknown];
-                                                       }
-                                               }
-                                               
-                                               // To Approve:
-                                               // Always must have at least 1 owner
-                                               if((state[owner][total]>0 && state[owner][approved]>0) &&
-                                                       // If there are no Supervisors, that's ok
-                                                   (state[supervisor][total]==0 || 
-                                                   // But if there is a Supervisor, they must have approved 
-                                                   (state[supervisor][approved]>0))) {
-                                                               UserRoleDAO.Data urdd = new UserRoleDAO.Data();
-                                                               try {
-                                                                       urdd.reconstitute(ticket.f.fdd.construct);
-                                                                       if(urdd.expires.before(ticket.f.expires())) {
-                                                                               extendCW.row("extend_ur",urdd.user,urdd.role,ticket.f.expires());
+                                                       } else { // Load all the Pending.
+                                                               for(Entry<String, Pending> es : pendingTemp.entrySet()) {
+                                                                       Pending p = pendingApprs.get(es.getKey());
+                                                                       if(p==null) {
+                                                                               pendingApprs.put(es.getKey(), es.getValue());
+                                                                       } else {
+                                                                               p.inc(es.getValue());
                                                                        }
-                                                               } catch (IOException e) {
-                                                                       trans.error().log("Could not reconstitute UserRole");
-                                                               }
-                                               } else { // Load all the Pending.
-                                                       for(Entry<String, Pending> es : pendingTemp.entrySet()) {
-                                                               Pending p = pendingApprs.get(es.getKey());
-                                                               if(p==null) {
-                                                                       pendingApprs.put(es.getKey(), es.getValue());
-                                                               } else {
-                                                                       p.inc(es.getValue());
                                                                }
                                                        }
+                                                       break;
+                                       }
+                               } finally {
+                                       if("user_role".equals(ticket.f.fdd.target)) {
+                                               String key = ticket.f.fdd.target_key; 
+                                               if(key!=null) {
+                                                       mur.put(key, ticket);
                                                }
-                                               break;
+                                       }
                                }
                        }
                } finally {
                        tt.done();
                }
-               
+
+               // Good Tickets no longer needed
+               goodTickets.clear();
+
                /**
                 * Decide to Notify about Approvals, based on activity/last Notified
                 */
@@ -288,7 +315,9 @@ public class Analyze extends Batch {
                        
                        for(Entry<String, Pending> es : pendingApprs.entrySet()) {
                                Pending p = es.getValue();
-                               if(p.newApprovals() || p.earliest() == null || p.earliest().after(remind)) {
+                               if(p.newApprovals() 
+                                               || p.earliest() == null 
+                                               || p.earliest().after(remind)) {
                                        p.row(approveCW,es.getKey());
                                }
                        }
@@ -297,7 +326,6 @@ public class Analyze extends Batch {
                }
                
                // clear out Approval Intermediates
-               goodTickets.clear();
                pendingTemp = null;
                pendingApprs = null;
                
@@ -309,7 +337,7 @@ public class Analyze extends Batch {
                try {
                        tt = trans.start("Analyze UserRoles, storing Owners",Trans.SUB);
                        Set<String> specialCommented = new HashSet<>();
-                       Map<String, Set<UserRole>> owners = new TreeMap<String, Set<UserRole>>();
+                       Map<String, Set<UserRole>> owners = new TreeMap<>();
                        try {
                                UserRole.load(noAvg, session, UserRole.v2_0_11, ur -> {
                                        Identity identity;
@@ -340,20 +368,25 @@ public class Analyze extends Batch {
                                                        ur.row(deleteCW, UserRole.UR,String.format("Role %s does not exist", ur.role()));
                                                        return;
                                                }
-                                               // Cannot just delete owners, unless there is at least one left. Process later
-                                               if ("owner".equals(ur.rname())) {
-                                                       Set<UserRole> urs = owners.get(ur.role());
-                                                       if (urs == null) {
-                                                               urs = new HashSet<UserRole>();
-                                                               owners.put(ur.role(), urs);
-                                                       }
-                                                       urs.add(ur);
-                                               } else {
-                                                       Range r = writeAnalysis(noAvg,ur);
-                                                       if(r!=null) {
-                                                               Approval existing = findApproval(ur);
-                                                               if(existing==null) {
-                                                                       ur.row(approveCW,UserRole.APPROVE_UR);
+                                               // Just let expired UserRoles sit until deleted
+                                               if(futureRange.inRange(ur.expires())) {
+                                                       if(!mur.containsKey(ur.user() + '|' + ur.role())) {
+                                                               // Cannot just delete owners, unless there is at least one left. Process later
+                                                               if ("owner".equals(ur.rname())) {
+                                                                       Set<UserRole> urs = owners.get(ur.role());
+                                                                       if (urs == null) {
+                                                                               urs = new HashSet<UserRole>();
+                                                                               owners.put(ur.role(), urs);
+                                                                       }
+                                                                       urs.add(ur);
+                                                               } else {
+                                                                       Range r = writeAnalysis(noAvg,ur);
+                                                                       if(r!=null) {
+                                                                               Approval existing = findApproval(ur);
+                                                                               if(existing==null) {
+                                                                                       ur.row(approveCW,UserRole.APPROVE_UR);
+                                                                               }
+                                                                       }
                                                                }
                                                        }
                                                }
@@ -374,16 +407,16 @@ public class Analyze extends Batch {
                        tt = trans.start("Analyze Owners Separately",Trans.SUB);
                        try {
                                if (!owners.values().isEmpty()) {
-                                       File file = new File(logDir(), EXPIRED_OWNERS + Chrono.dateOnlyStamp(expireRange.now) + CSV);
+                                       File file = new File(logDir(), EXPIRED_OWNERS + sdate + CSV);
                                        final CSV ownerCSV = new CSV(env.access(),file);
                                        CSV.Writer expOwner = ownerCSV.writer();
-                                       expOwner.row(INFO,EXPIRED_OWNERS,Chrono.dateOnlyStamp(expireRange.now),2);
+                                       expOwner.row(INFO,EXPIRED_OWNERS,sdate,2);
 
                                        try {
                                                for (Set<UserRole> sur : owners.values()) {
                                                        int goodOwners = 0;
                                                        for (UserRole ur : sur) {
-                                                               if (ur.expires().after(expireRange.now)) {
+                                                               if (ur.expires().after(ExpireRange.now)) {
                                                                        ++goodOwners;
                                                                }
                                                        }
@@ -462,7 +495,6 @@ public class Analyze extends Batch {
                                        } catch (CertificateException | IOException e) {
                                                noAvg.error().log(e, "Error Decrypting X509");
                                        }
-       
                                });
                        } finally {
                                tt.done();
index 1c1f660..7cddea2 100644 (file)
@@ -25,22 +25,36 @@ import java.io.FileReader;
 import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
+import java.text.ParseException;
 import java.util.ArrayList;
+import java.util.Date;
+import java.util.GregorianCalendar;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
+import java.util.TreeMap;
 
 import org.onap.aaf.auth.batch.Batch;
+import org.onap.aaf.auth.batch.approvalsets.Pending;
+import org.onap.aaf.auth.batch.helpers.CQLBatch;
+import org.onap.aaf.auth.batch.helpers.CQLBatchLoop;
+import org.onap.aaf.auth.batch.helpers.LastNotified;
 import org.onap.aaf.auth.batch.reports.bodies.NotifyBody;
+import org.onap.aaf.auth.batch.reports.bodies.NotifyPendingApprBody;
 import org.onap.aaf.auth.env.AuthzTrans;
 import org.onap.aaf.auth.org.Mailer;
 import org.onap.aaf.auth.org.Organization.Identity;
 import org.onap.aaf.auth.org.OrganizationException;
 import org.onap.aaf.cadi.Access;
 import org.onap.aaf.cadi.CadiException;
+import org.onap.aaf.cadi.PropAccess;
 import org.onap.aaf.cadi.client.Holder;
 import org.onap.aaf.cadi.util.CSV;
 import org.onap.aaf.misc.env.APIException;
+import org.onap.aaf.misc.env.TimeTaken;
+import org.onap.aaf.misc.env.Trans;
 import org.onap.aaf.misc.env.util.Chrono;
 
  public class Notify extends Batch {
@@ -52,9 +66,15 @@ import org.onap.aaf.misc.env.util.Chrono;
         private final int indent;
         private final boolean urgent;
         public final String guiURL;
+        private PropAccess access;
+        private AuthzTrans noAvg;
+        private CQLBatch cqlBatch;
 
         public Notify(AuthzTrans trans) throws APIException, IOException, OrganizationException {
                 super(trans.env());
+                access = env.access();
+                session = super.cluster.connect();
+
                 String mailerCls = env.getProperty("MAILER");
                 String mailFrom = env.getProperty("MAIL_FROM");
                 String header_html = env.getProperty("HEADER_HTML");
@@ -82,12 +102,14 @@ import org.onap.aaf.misc.env.util.Chrono;
                                 sb.append('\n');
                         }
                         String html_css = env.getProperty(HTML_CSS);
+                        String temp;
                         int hc = sb.indexOf(HTML_CSS);
                         if(hc!=0 && html_css!=null) {
-                                header = sb.replace(hc,hc+HTML_CSS.length(), html_css).toString();
+                                temp = sb.replace(hc,hc+HTML_CSS.length(), html_css).toString();
                         } else {
-                                header = sb.toString();
+                                temp = sb.toString();
                         }
+                        header = temp.replace("AAF:ENV", batchEnv);
                 } finally {
                         br.close();
                 }
@@ -119,6 +141,8 @@ import org.onap.aaf.misc.env.util.Chrono;
                         br.close();
                 }
 
+                noAvg = trans.env().newTransNoAvg();
+                cqlBatch = new CQLBatch(noAvg.info(),session); 
         }
 
         /*
@@ -127,10 +151,10 @@ import org.onap.aaf.misc.env.util.Chrono;
          */
         @Override
         protected void run(AuthzTrans trans) {
-                AuthzTrans noAvg = trans.env().newTransNoAvg();
 
                 final Holder<List<String>> info = new Holder<>(null);
                 final Set<String> errorSet = new HashSet<>();
+                String fmt = "%s"+Chrono.dateOnlyStamp()+".csv";
 
                 try {
                         // Class Load possible data
@@ -145,7 +169,6 @@ import org.onap.aaf.misc.env.util.Chrono;
                                         notifyFile.add(new File(logDir, args()[i]));
                                 }
                         } else {
-                                String fmt = "%s"+Chrono.dateOnlyStamp()+".csv";
                                 File file;
                                 for(NotifyBody nb : NotifyBody.getAll()) {
                                         file = new File(logDir,String.format(fmt, nb.name()));
@@ -188,6 +211,100 @@ import org.onap.aaf.misc.env.util.Chrono;
                         for(NotifyBody nb : NotifyBody.getAll()) {
                                 notify(noAvg, nb);
                         }
+                        
+                        //
+                        // Do Pending Approval Notifies. We do this separately, because we are consolidating
+                        // all the new entries, etc.
+                        //
+                        List<CSV> csvList = new ArrayList<>();
+                        for(String s : new String[] {"Approvals","ApprovalsNew"}) {
+                                File f = new File(logDir(),String.format(fmt, s));
+                                if(f.exists()) {
+                                        csvList.add(new CSV(access,f));
+                                }
+                        }
+                        
+                        Map<String,Pending> mpending = new TreeMap<>();
+                        Holder<Integer> count = new Holder<>(0);
+                        for(CSV approveCSV : csvList) {
+                       TimeTaken tt = trans.start("Load Analyzed Reminders",Trans.SUB,approveCSV.name());
+                       try {
+                                       approveCSV.visit(row -> {
+                                               switch(row.get(0)) {
+//                                                     case "info":
+//                                                             break;
+                                                       case Pending.REMIND:
+                                                               try {
+                                                                       String user = row.get(1);
+                                                                       Pending p = new Pending(row);
+                                                                       Pending mp = mpending.get(user);
+                                                                       if(mp==null) {
+                                                                               mpending.put(user, p);
+                                                                       } else {
+                                                                               mp.inc(p); // FYI, unlikely
+                                                                       }
+                                                                       count.set(count.get()+1);
+                                                               } catch (ParseException e) {
+                                                                       trans.error().log(e);
+                                                               } 
+                                                       break;
+                                               }
+                                       });
+                               } catch (IOException | CadiException e) {
+                                       e.printStackTrace();
+                                       // .... but continue with next row
+                       } finally {
+                               tt.done();
+                       }
+               }
+               trans.info().printf("Read %d Reminder Rows", count.get());
+               
+               NotifyPendingApprBody npab = new NotifyPendingApprBody(access);
+
+               GregorianCalendar gc = new GregorianCalendar();
+               gc.add(GregorianCalendar.DAY_OF_MONTH, 7); // Get from INFO?
+               Date oneWeek = gc.getTime();
+               CSV.Saver rs = new CSV.Saver();
+               
+               TimeTaken tt = trans.start("Obtain Last Notifications for Approvers", Trans.SUB);
+               LastNotified lastN;
+               try {
+                       lastN = new LastNotified(session);
+                       lastN.add(mpending.keySet());
+               } finally {
+                       tt.done();
+               }
+               
+               Pending p;
+               final CQLBatchLoop cbl = new CQLBatchLoop(cqlBatch,50,dryRun);
+               tt = trans.start("Notify for Pending", Trans.SUB);
+               try {
+                       for(Entry<String, Pending> es : mpending.entrySet()) {
+                               p = es.getValue();
+                               boolean nap = p.newApprovals();
+                               if(!nap) {
+                               Date dateLastNotified = lastN.lastNotified(es.getKey(),"pending","");
+                               if(dateLastNotified==null || dateLastNotified.after(oneWeek) ) {
+                                       nap=true;
+                               }
+                               }
+                               if(nap) {
+                                       rs.row("appr", es.getKey(),p.qty(),batchEnv);
+                                       npab.store(rs.asList());
+                                       if(notify(noAvg, npab)>0) {
+                                               // Update
+                                               cbl.preLoop();
+                                               lastN.update(cbl.inc(),es.getKey(),"pending","");
+                                       }
+                               }
+                       }
+               } finally {
+                       cbl.flush();
+                       tt.done();
+               }
+            trans.info().printf("Created %d Notifications", count.get());
+
+
 
                } catch (APIException | IOException e1) {
                        trans.error().log(e1);
@@ -272,8 +389,4 @@ import org.onap.aaf.misc.env.util.Chrono;
                 return nb.count();
         }
 
-       @Override
-        protected void _close(AuthzTrans trans) {
-        }
-
  }
index 94502d9..15a104d 100644 (file)
@@ -32,15 +32,17 @@ import org.onap.aaf.misc.env.util.Chrono;
 public abstract class NotifyCredBody extends NotifyBody {
 
        private final String explanation;
+       private final String instruction;
+        
        public NotifyCredBody(Access access, String name) throws IOException {
                super(access,"cred",name);
                
                // Default
                explanation = "The following Credentials that you are responsible for "
-                               + "are expiring on the dates shown. "
-                               + "Failure to act before the expiration date will cause your App's "
-                               + "Authentications to fail."
-                               + "<h3>Instructions for 'Password':</h3><ul>" 
+                               + "are expiring on the dates shown. <br><br>"
+                               ;
+                               
+        instruction = "<br><h3>Instructions for 'Password':</h3><ul>" 
                                + "<li><b><i>Click</i></b> on the Fully Qualified ID to ADD a new Password</li>"
                                + "<li><b>REMEMBER!</b> You are not finished until you <ol>"
                                + "<li><b>CHANGE <i>ALL</i></b> the configurations on <b><i>ALL</i></b> your processes!!</li>"
@@ -48,10 +50,20 @@ public abstract class NotifyCredBody extends NotifyBody {
                                + "<li>IF there is a WARNING, click the link for more information</li>"
                                + "</ul>";
        }
+       
+       /**
+        * Default Dynamic Text.  Override is expected
+        * @return
+        */
+       protected String dynamic() {
+               return "Failure to act before the expiration date will cause your App's Authentications to fail.";
+       }
 
        @Override
        public boolean body(AuthzTrans trans, StringBuilder sb, int indent, Notify n, String id) {
-               println(sb,indent,explanation);
+               print(sb,indent,explanation);
+               print(sb,indent,dynamic());
+               println(sb,indent,instruction);
                println(sb,indent,"<table>");
                indent+=2;
                println(sb,indent,"<tr>");
index a288f49..866dc23 100644 (file)
@@ -34,4 +34,12 @@ public class OneMonthNotifyCredBody extends NotifyCredBody {
        public String subject() {
                return String.format("AAF One Month Credential Notification (ENV: %s)",env);
        }
+       
+       /* (non-Javadoc)
+        * @see org.onap.aaf.auth.batch.reports.bodies.NotifyCredBody#dynamic()
+        */
+       @Override
+       protected String dynamic() {
+               return "This is your <b>one month</b> notification. " + super.dynamic();
+       }
 }
index eb52c6d..98ee47d 100644 (file)
@@ -34,4 +34,14 @@ public class TwoMonthNotifyCredBody extends NotifyCredBody {
        public String subject() {
                return String.format("AAF Two Month Credential Notification (ENV: %s)",env);
        }
+
+       /* (non-Javadoc)
+        * @see org.onap.aaf.auth.batch.reports.bodies.NotifyCredBody#dynamic()
+        */
+       @Override
+       protected String dynamic() {
+               return "This is a friendly, <b>2 month reminder</b> to schedule appropriate creation and deployment "
+                               + "of your credentials, and modification of your configurations on a per instance basis. "
+                               + " Use the following text to help create your Ticket.";
+       }
 }
index 818556c..4618856 100644 (file)
@@ -34,4 +34,12 @@ public class TwoWeeksNotifyCredBody extends NotifyCredBody {
        public String subject() {
                return String.format("AAF Two Week Credential Notification (ENV: %s)",env);
        }
+       
+       /* (non-Javadoc)
+        * @see org.onap.aaf.auth.batch.reports.bodies.NotifyCredBody#dynamic()
+        */
+       @Override
+       protected String dynamic() {
+               return "You have now reached critical stage. This email is escalated to your superiors. " + super.dynamic();
+       }
 }
index 03c812a..0df4934 100644 (file)
@@ -23,13 +23,12 @@ package org.onap.aaf.auth.batch.update;
 
 import java.io.File;
 import java.io.IOException;
-import java.text.ParseException;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.GregorianCalendar;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 import java.util.TreeMap;
 
 import org.onap.aaf.auth.batch.Batch;
@@ -38,42 +37,34 @@ import org.onap.aaf.auth.batch.approvalsets.ApprovalSet;
 import org.onap.aaf.auth.batch.approvalsets.Pending;
 import org.onap.aaf.auth.batch.approvalsets.URApprovalSet;
 import org.onap.aaf.auth.batch.helpers.BatchDataView;
-import org.onap.aaf.auth.batch.helpers.CQLBatch;
-import org.onap.aaf.auth.batch.helpers.CQLBatchLoop;
-import org.onap.aaf.auth.batch.helpers.LastNotified;
 import org.onap.aaf.auth.batch.helpers.NS;
-import org.onap.aaf.auth.batch.helpers.Notification;
-import org.onap.aaf.auth.batch.helpers.Notification.TYPE;
 import org.onap.aaf.auth.batch.helpers.Role;
 import org.onap.aaf.auth.batch.helpers.UserRole;
-import org.onap.aaf.auth.batch.reports.Notify;
-import org.onap.aaf.auth.batch.reports.bodies.NotifyPendingApprBody;
 import org.onap.aaf.auth.dao.cass.UserRoleDAO;
 import org.onap.aaf.auth.env.AuthzTrans;
 import org.onap.aaf.auth.layer.Result;
 import org.onap.aaf.auth.org.OrganizationException;
-import org.onap.aaf.cadi.Access;
 import org.onap.aaf.cadi.CadiException;
 import org.onap.aaf.cadi.client.Holder;
 import org.onap.aaf.cadi.util.CSV;
+import org.onap.aaf.cadi.util.CSV.Writer;
 import org.onap.aaf.misc.env.APIException;
 import org.onap.aaf.misc.env.TimeTaken;
 import org.onap.aaf.misc.env.Trans;
 import org.onap.aaf.misc.env.util.Chrono;
 
 public class Approvals extends Batch {
-    private final Access access;
        private final AuthzTrans noAvg;
        private BatchDataView dataview;
        private List<CSV> csvList;
-       private GregorianCalendar now;
-       private final Notify notify;
+       private Writer napproveCW;
+       private static final GregorianCalendar now = new GregorianCalendar();
+       private static final String sdate = Chrono.dateOnlyStamp(now);
+       private static final String CSV = ".csv";
+       private static final String APPROVALS_NEW = "ApprovalsNew";
        
-
     public Approvals(AuthzTrans trans) throws APIException, IOException, OrganizationException {
         super(trans.env());
-        notify = new Notify(trans);
-        access = env.access();
         noAvg = env.newTransNoAvg();
         noAvg.setUser(new BatchPrincipal("batch:Approvals"));
         session = cluster.connect();
@@ -82,8 +73,6 @@ public class Approvals extends Batch {
         Role.load(trans, session);
         UserRole.load(trans, session, UserRole.v2_0_11);
 
-        now = new GregorianCalendar();
-        
         csvList = new ArrayList<>();
         File f;
         if(args().length>0) {
@@ -103,45 +92,21 @@ public class Approvals extends Batch {
                        trans.error().printf("CSV File %s does not exist",f.getAbsolutePath());
                        }
         }
+        
+
+        File file = new File(logDir(),APPROVALS_NEW + sdate +CSV);
+        CSV approveCSV = new CSV(env.access(),file);
+        napproveCW = approveCSV.writer();
+        napproveCW.row("info",APPROVALS_NEW,sdate,1);
+        
     }
 
     @Override
     protected void run(AuthzTrans trans) {
        Map<String,Pending> mpending = new TreeMap<>();
-               Holder<Integer> count = new Holder<>(0);
-               final CQLBatchLoop cbl = new CQLBatchLoop(new CQLBatch(noAvg.info(),session),100,dryRun);
-        for(CSV approveCSV : csvList) {
-               TimeTaken tt = trans.start("Load Analyzed Reminders",Trans.SUB,approveCSV.name());
-               try {
-                               approveCSV.visit(row -> {
-                                       switch(row.get(0)) {
-                                               case Pending.REMIND:
-                                                       try {
-                                                               String user = row.get(1);
-                                                               Pending p = new Pending(row);
-                                                               Pending mp = mpending.get(user);
-                                                               if(mp==null) {
-                                                                       mpending.put(user, p);
-                                                               } else {
-                                                                       mp.inc(p); // FYI, unlikely
-                                                               }
-                                                               count.set(count.get()+1);
-                                                       } catch (ParseException e) {
-                                                               trans.error().log(e);
-                                                       } 
-                                               break;
-                                       }
-                               });
-                       } catch (IOException | CadiException e) {
-                               e.printStackTrace();
-                               // .... but continue with next row
-               } finally {
-                       tt.done();
-               }
-        }
-        trans.info().printf("Processed %d Reminder Rows", count.get());
+               Pending p = Pending.create();
 
-        count.set(0);
+               Holder<Integer> count = new Holder<>(0);
         for(CSV approveCSV : csvList) {
                TimeTaken tt = trans.start("Processing %s's UserRoles",Trans.SUB,approveCSV.name());
                try {
@@ -155,14 +120,20 @@ public class Approvals extends Batch {
                                                        });
                                                        Result<Void> rw = uras.write(noAvg);
                                                        if(rw.isOK()) {
-                                                               Pending p = new Pending();
-                                                               Pending mp = mpending.get(urdd.user);
-                                                               if(mp==null) {
-                                                                       mpending.put(urdd.user, p);
+                                                               Set<String> approvers = uras.approvers();
+                                                               if(approvers.isEmpty()) {
+                                                                       trans.error().printf("No Approvers found for %s-%s (probably no owner)",urdd.user,urdd.role);
                                                                } else {
-                                                                       mp.inc(p);
+                                                                       for(String approver : approvers) {
+                                                                               Pending mp = mpending.get(approver);
+                                                                               if(mp==null) {
+                                                                                       mpending.put(approver, Pending.create());
+                                                                               } else {
+                                                                                       mp.inc(p); // FYI, unlikely
+                                                                               }
+                                                                       }
+                                                                       count.set(count.get()+1);
                                                                }
-                                                               count.set(count.get()+1);
                                                        } else {
                                                                trans.error().log(rw.errorString());
                                                        }
@@ -178,60 +149,25 @@ public class Approvals extends Batch {
                }
             trans.info().printf("Processed %d UserRoles", count.get());
 
-            count.set(0);
-               NotifyPendingApprBody npab = new NotifyPendingApprBody(access);
-
-               GregorianCalendar gc = new GregorianCalendar();
-               gc.add(GregorianCalendar.DAY_OF_MONTH, 7);
-               Date oneWeek = gc.getTime();
-               CSV.Saver rs = new CSV.Saver();
-               
-               tt = trans.start("Obtain Last Notifications", Trans.SUB);
-               LastNotified lastN;
-               try {
-                       lastN = new LastNotified(session);
-                       lastN.add(mpending.keySet());
-               } finally {
-                       tt.done();
-               }
-               
-               Pending p;
-               tt = trans.start("Notify for Pending", Trans.SUB);
+               tt = trans.start("Processing %s's UserRoles",Trans.SUB,approveCSV.name());
+               int cnt = 0;
                try {
-                       for(Entry<String, Pending> es : mpending.entrySet()) {
-                               p = es.getValue();
-                               Date dateLastNotified = lastN.lastNotified(es.getKey());
-                               if(p.newApprovals() || dateLastNotified==null || dateLastNotified.after(oneWeek) ) {
-                                       rs.row("appr", es.getKey(),p.qty(),batchEnv);
-                                       npab.store(rs.asList());
-                                       if(notify.notify(noAvg, npab)>0) {
-                                               // Update
-                                               cbl.preLoop();
-                                               update(cbl.inc(),es.getKey(),Notification.TYPE.OA);
-                                       }
-                               }
-                       }
-               } finally {
-                       tt.done();
-               }
-            trans.info().printf("Created %d Notifications", count.get());
-           }
+                   for(Entry<String, Pending> es : mpending.entrySet()) {
+                       p.row(napproveCW,es.getKey());
+                       ++cnt;
+                   }
+            } finally {
+               tt.done();
+               trans.info().printf("Processed %d Reminders", cnt);
+            }
+           }
     }
-    
-    private void update(StringBuilder sb, String user, TYPE oa) {
-       sb.append("UPDATE authz.notify SET last=dateof(now()) WHERE user='");
-       sb.append(user);
-       sb.append("' AND type=");
-       sb.append(oa.idx());
-       sb.append(';');
-               
-       }
 
        @Override
     protected void _close(AuthzTrans trans) {
-       if(session!=null) {
-               session.close();
-               session = null;
-       }
+               if(napproveCW!=null) {
+                       napproveCW.flush();
+                       napproveCW.close();
+               }
     }
 }
index 870dc1e..3a0f7b9 100644 (file)
@@ -151,7 +151,7 @@ public class Extend extends Batch {
                                                                        gc.setTime(now.getTime());
                                                                }
                                                                gc.add(gcType, extendBy);
-                                                               UserRole.batchExtend(sb,row,Chrono.dateTime(gc));
+                                                               UserRole.batchExtend(sb,row,gc.getTime());
                                                                break;
                                                        case "cred":
                                                                int ctype = Integer.parseInt(row.get(3));
diff --git a/auth/auth-batch/src/test/java/org/onap/aaf/auth/batch/test/JU_NotificationTest.java b/auth/auth-batch/src/test/java/org/onap/aaf/auth/batch/test/JU_NotificationTest.java
deleted file mode 100644 (file)
index f1cba0b..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * ============LICENSE_START====================================================
- * org.onap.aaf
- * ===========================================================================
- * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
- * ===========================================================================
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ============LICENSE_END====================================================
- *
- */
-package org.onap.aaf.auth.batch.test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.when;
-import static org.mockito.MockitoAnnotations.initMocks;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.onap.aaf.auth.batch.actions.Message;
-import org.onap.aaf.auth.batch.helpers.Creator;
-import org.onap.aaf.auth.batch.helpers.Notification;
-import org.onap.aaf.auth.batch.helpers.Notification.TYPE;
-import org.onap.aaf.auth.env.AuthzTrans;
-import org.onap.aaf.misc.env.Env;
-import org.onap.aaf.misc.env.LogTarget;
-import org.onap.aaf.misc.env.TimeTaken;
-
-public class JU_NotificationTest {
-
-       @Mock
-       private AuthzTrans trans;
-       @Mock
-       private Creator<Notification> creator;
-       @Mock
-       private TimeTaken tt;
-
-       @Mock
-       private LogTarget logTarget;
-       private Message msg;
-
-       @Before
-       public void setUp() throws Exception {
-               initMocks(this);
-
-               msg = new Message();
-               msg.line("%n", "Message");
-
-               when(trans.info()).thenReturn(logTarget);
-               when(trans.start("Load Notify", Env.REMOTE)).thenReturn(tt);
-       }
-
-       @Test
-       public void test() {
-               Notification notification = Notification.create("user", TYPE.CN);
-               assertEquals(notification.checksum(), 0);
-               notification.set(msg);
-               assertEquals(notification.checksum(), 10);
-               assertNull(Notification.get("user", TYPE.CN));
-               assertTrue(notification.update(trans, null, true));
-               assertTrue(notification.toString().contains("\"user\",\"CN\","));
-
-
-       }
-}
\ No newline at end of file
index 75b02c5..f280de0 100644 (file)
@@ -90,12 +90,12 @@ CREATE TABLE cert (
 CREATE INDEX cert_id ON cert(id);
 CREATE INDEX cert_x500 ON cert(x500);
 
-CREATE TABLE notify (
+CREATE TABLE notified (
   user                 text,
-  type                 int,
+  target        text,
+  key          text,
   last                 timestamp,
-  checksum     int,
-  PRIMARY KEY (user,type)
+  PRIMARY KEY (user,target,key)
 );
 
 CREATE TABLE x509 (
@@ -175,6 +175,7 @@ CREATE TABLE future (
 );
 CREATE INDEX future_idx ON future(target);
 CREATE INDEX future_start_idx ON future(start);
+CREATE INDEX future_target_key ON authz.future (target_key);
 
 
 CREATE TABLE approval (
index b719507..21bd4b6 100644 (file)
@@ -2,3 +2,13 @@ use authz;
 alter TABLE cred ADD tag varchar;
 alter TABLE future ADD target_key varchar;
 alter TABLE future ADD target_date timestamp;
+CREATE INDEX future_target_key ON authz.future (target_key);
+
+CREATE TABLE notified (
+  user          text,
+  target        text,
+  key           text,
+  last          timestamp,
+  PRIMARY KEY (user,target,key)
+);
+
index 08c9685..c51ddbd 100644 (file)
@@ -203,7 +203,7 @@ public class LocalCA extends CA {
     public X509andChain sign(Trans trans, CSRMeta csrmeta) throws IOException, CertException {
         GregorianCalendar gc = new GregorianCalendar();
         Date start = gc.getTime();
-        gc.add(GregorianCalendar.MONTH, 6);
+        gc.add(GregorianCalendar.MONTH, 12);
         Date end = gc.getTime();
         X509Certificate x509;
         TimeTaken tt = trans.start("Create/Sign Cert",Env.SUB);
index f173038..0c984e4 100644 (file)
@@ -40,13 +40,12 @@ import org.onap.aaf.auth.gui.Table.Cells;
 import org.onap.aaf.auth.gui.table.AbsCell;
 import org.onap.aaf.auth.gui.table.ButtonCell;
 import org.onap.aaf.auth.gui.table.RadioCell;
-import org.onap.aaf.auth.gui.table.RefCell;
 import org.onap.aaf.auth.gui.table.TableData;
-import org.onap.aaf.auth.gui.table.TextAndRefCell;
 import org.onap.aaf.auth.gui.table.TextCell;
+import org.onap.aaf.auth.gui.table.TextToolTipCell;
 import org.onap.aaf.auth.org.Organization;
-import org.onap.aaf.auth.org.OrganizationFactory;
 import org.onap.aaf.auth.org.Organization.Identity;
+import org.onap.aaf.auth.org.OrganizationFactory;
 import org.onap.aaf.cadi.CadiException;
 import org.onap.aaf.cadi.client.Future;
 import org.onap.aaf.cadi.client.Rcli;
@@ -91,7 +90,7 @@ public class ApprovalForm extends Page {
                 }
             },
             new Form(true,new Table<AAF_GUI,AuthzTrans>("Approval Requests", gui.env.newTransNoAvg(),new Model(gui.env),"class=stdform"))
-                .preamble("The following requires your Approval to proceed in the AAF System.</p><p class=subtext>Hover on Identity for Name; click for WebPhone; If Deny is the only option, User is no longer valid."),
+                .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."),
             new NamedCode(false, "selectAlljs") {
                 @Override
                 public void code(final Cache<HTMLGen> cache, final HTMLGen hgen) throws APIException, IOException {
@@ -116,7 +115,7 @@ public class ApprovalForm extends Page {
      */
     private static class Model extends TableData<AAF_GUI,AuthzTrans> {
         //TODO come up with a generic way to do ILM Info (people page)
-        private static final String TODO_ILM_INFO = "TODO: ILM Info";
+//        private static final String TODO_ILM_INFO = "TODO: ILM Info";
         
         
         private static final String[] headers = new String[] {"Identity","Request","Approve","Deny"};
@@ -216,7 +215,7 @@ public class ApprovalForm extends Page {
        //                        } else {
                                    approverHeader = new AbsCell[] { 
                                            new TextCell("Approvals Delegated to Me by " + iapprover.fullName() 
-                                              + '(' + iapprover.id() +')',
+                                               + '(' + iapprover.id() + ')',
                                                    new String[] {"colspan=4", "class=head"})
                                    };
        //                        }
@@ -242,34 +241,29 @@ public class ApprovalForm extends Page {
                                        userCell = AbsCell.Null; 
                                    } else if (user.endsWith(trans.org().getRealm())){
                                        userOK=true;
-//                                     String title;
+                                       String title;
                                        Organization org = OrganizationFactory.obtain(trans.env(), user);
                                        if (org==null) {
-//                                         title="";
+                                           title="";
                                                userCell = new TextCell(user);
                                        } else {
                                            Identity au = org.getIdentity(trans, user);
                                            if (au!=null) {
                                                if(au.isPerson()) {
-                                                       userCell = new TextCell(au.fullName() + "\n(" + au.id() + ')');
+                                                       userCell = new TextToolTipCell(au.fullName(),"Identity: " + au.id());
                                                } else {
-                                                       userCell = new TextCell(au.fullID());
+                                                   Identity managedBy = au.responsibleTo();
+                                                   if (managedBy==null) {
+                                                       title ="Identity: " + au.type();
+                                                   } else {
+                                                       title="Sponsor: " + managedBy.fullName();                                                
+                                                   }
+                                                       userCell = new TextToolTipCell(au.fullID(),title);
                                                }
-//                                             
-//                                             if ("MECHID".equals(au.type())) {
-//                                                 Identity managedBy = au.responsibleTo();
-//                                                 if (managedBy==null) {
-//                                                     title ="title=" + au.type();
-//                                                 } else {
-//                                                     title="title=Sponsor is " + managedBy.fullName();                                                
-//                                                 }
-//                                             } else {
-//                                                 title="title=" + au.fullName();
-//                                             }
                                            } else {
                                                userOK=false;
-//                                             title="title=Not a User at " + org.getName();
-                                                       userCell = new TextCell(user);
+                                               title="Not a User at " + org.getName();
+                                                       userCell = new TextToolTipCell(user,title);
                                            }
                                        }
                                        prevUser=user;
diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/TextToolTipCell.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/TextToolTipCell.java
new file mode 100644 (file)
index 0000000..986b824
--- /dev/null
@@ -0,0 +1,51 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ * ===========================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.auth.gui.table;
+
+import org.onap.aaf.misc.xgen.html.HTMLGen;
+
+/**
+ * Write Simple Text into a Cell
+ * @author Jonathan
+ *
+ */
+public class TextToolTipCell extends AbsCell {
+    public final String name;
+    private final String[] attrs;
+       private final String tooltip;
+    
+    public TextToolTipCell(String name, String tooltip, String... attributes) {
+        attrs = attributes;
+        this.name = name;
+        this.tooltip = "<abbr title=\"" + tooltip + "\">";
+    }
+    
+    @Override
+    public void write(HTMLGen hgen) {
+        hgen.text(tooltip + name + "</abbr>");
+    }
+    
+    @Override
+    public String[] attrs() {
+        return attrs;
+    }
+}
index cd8eff4..01bf6f2 100644 (file)
@@ -303,7 +303,14 @@ public class CadiFilter implements Filter {
     private boolean noAuthn(HttpServletRequest hreq) {
         if (pathExceptions!=null) {
             String pi = hreq.getPathInfo();
-            if (pi==null) return false; // JBoss sometimes leaves null
+            if (pi==null) {
+               // Attempt to get from URI only  (Daniel Rose)
+                pi = hreq.getRequestURI().substring(hreq.getContextPath().length());
+                if(pi==null) {
+                       // Nothing works.
+                       return false; // JBoss sometimes leaves null
+                }
+            }
             for (String pe : pathExceptions) {
                 if (pi.startsWith(pe))return true;
             }
index 1d60ae5..47de84e 100644 (file)
@@ -44,6 +44,7 @@ public class CSV {
        private File csv;
        private Access access;
        private boolean processAll;
+       private char delimiter = ',';
        
        public CSV(Access access, File file) {
                this.access = access;
@@ -57,6 +58,11 @@ public class CSV {
                processAll = false;
        }
        
+       public CSV setDelimiter(char delimiter) {
+               this.delimiter = delimiter;
+               return this;
+       }
+       
        public String name() {
                return csv.getName();
        }
@@ -116,16 +122,17 @@ public class CSV {
                                                                        escape = true;
                                                                }
                                                                break;
-                                                       case ',':
-                                                               if(quotes) {
-                                                                       sb.append(c);
+                                                       default:
+                                                               if(delimiter==c) {
+                                                                       if(quotes) {
+                                                                               sb.append(c);
+                                                                       } else {
+                                                                               row.add(sb.toString());
+                                                                               sb.setLength(0);
+                                                                       }
                                                                } else {
-                                                                       row.add(sb.toString());
-                                                                       sb.setLength(0);
+                                                                       sb.append(c);
                                                                }
-                                                               break;
-                                                       default:
-                                                               sb.append(c);
                                                }
                                        }
                                        if(sb.length()>0 || c==',') {