From ebaf170010c039f0a711aa465adfde4e7645e1de Mon Sep 17 00:00:00 2001
From: Marco Malavolti <marco.malavolti@gmail.com>
Date: Fri, 19 Jun 2020 19:21:06 +0200
Subject: [PATCH] Added checkTime, statusCode and Collapse buttons

---
 api.py        | 52 ++++++++++++++++++++--------
 eccs2.py      | 94 ++++++++++++++++++++++++++++++---------------------
 web/index.php |  5 ++-
 web/script.js | 35 ++++++++++++++++---
 web/style.css |  9 +++++
 5 files changed, 137 insertions(+), 58 deletions(-)

diff --git a/api.py b/api.py
index 1236b98..5847d48 100755
--- a/api.py
+++ b/api.py
@@ -188,9 +188,13 @@ class EccsResults(Resource):
           # IdP-supp-ctc-1,IdP-supp-ctc-2;   check[4]
           # Status;                          check[5]
           # SP-entityID-1;                   check[6]
-          # SP-status-1;                     check[7]
-          # SP-entityID-2;                   check[8]
-          # SP-status-2                      check[9]
+          # SP-check-time-1;                 check[7]
+          # SP-status-1;                     check[8]
+          # SP-status-code-1;                check[9]
+          # SP-entityID-2;                   check[10]
+          # SP-check-time-2;                 check[11]
+          # SP-status-2                      check[12]
+          # SP-status-code-2                 check[13]
           check = line.split(";")
 
           idp_displayname = check[0].rstrip("\n\r")
@@ -200,9 +204,13 @@ class EccsResults(Resource):
           idp_supp_ctcs = check[4].rstrip("\n\r")
           idp_checks_status = check[5].rstrip("\n\r")
           sp1_entity_id = check[6].rstrip("\n\r")
-          sp1_check_status = check[7].rstrip("\n\r")
-          sp2_entity_id = check[8].rstrip("\n\r")
-          sp2_check_status = check[9].rstrip("\n\r")
+          sp1_check_time = check[7].rstrip("\n\r")
+          sp1_check_status = check[8].rstrip("\n\r")
+          sp1_status_code = check[9].rstrip("\n\r")
+          sp2_entity_id = check[10].rstrip("\n\r")
+          sp2_check_time = check[11].rstrip("\n\r")
+          sp2_check_status = check[12].rstrip("\n\r")
+          sp2_status_code = check[13].rstrip("\n\r")
 
           if (idp and status):
               app.logger.info("Results for the idp '%s' with status '%s'" % (idp, status))
@@ -219,11 +227,15 @@ class EccsResults(Resource):
                         'date' : date,
                         'sp1' : {
                             'entityID' : sp1_entity_id,
-                            'status' : sp1_check_status
+                            'checkTime' : sp1_check_time,
+                            'status' : sp1_check_status,
+                            'statusCode' : sp1_status_code
                         },
                         'sp2' : {
                             'entityID' : sp2_entity_id,
-                            'status' : sp2_check_status
+                            'checkTime' : sp2_check_time,
+                            'status' : sp2_check_status,
+                            'statusCode' : sp2_status_code
                         },
                         'status' : idp_checks_status
                     } )
@@ -244,11 +256,15 @@ class EccsResults(Resource):
                         'date' : date,
                         'sp1' : {
                             'entityID' : sp1_entity_id,
-                            'status' : sp1_check_status
+                            'checkTime' : sp1_check_time,
+                            'status' : sp1_check_status,
+                            'statusCode' : sp1_status_code
                         },
                         'sp2' : {
                             'entityID' : sp2_entity_id,
-                            'status' : sp2_check_status
+                            'checkTime' : sp2_check_time,
+                            'status' : sp2_check_status,
+                            'statusCode' : sp2_status_code
                         },
                         'status' : idp_checks_status
                     } )
@@ -266,11 +282,15 @@ class EccsResults(Resource):
                         'date' : date,
                         'sp1' : {
                            'entityID' : sp1_entity_id,
-                           'status' : sp1_check_status
+                           'checkTime' : sp1_check_time,
+                           'status' : sp1_check_status,
+                           'statusCode' : sp1_status_code
                         },
                         'sp2' : {
                            'entityID' : sp2_entity_id,
-                           'status' : sp2_check_status
+                           'checkTime' : sp2_check_time,
+                           'status' : sp2_check_status,
+                           'statusCode' : sp2_status_code
                         },
                         'status' : idp_checks_status
                     } )
@@ -287,11 +307,15 @@ class EccsResults(Resource):
                  'date' : date,
                  'sp1' : {
                     'entityID' : sp1_entity_id,
-                    'status' : sp1_check_status
+                    'checkTime' : sp1_check_time,
+                    'status' : sp1_check_status,
+                    'statusCode' : sp1_status_code
                  },
                  'sp2' : {
                     'entityID' : sp2_entity_id,
-                    'status' : sp2_check_status
+                    'checkTime' : sp2_check_time,
+                    'status' : sp2_check_status,
+                    'statusCode' : sp2_status_code
                  },
                  'status' : idp_checks_status
              } )
diff --git a/eccs2.py b/eccs2.py
index dd2e002..2d562de 100755
--- a/eccs2.py
+++ b/eccs2.py
@@ -1,12 +1,12 @@
 #!/usr/bin/env python3.8
 
 import argparse
+import datetime
 import json
 import re
 import requests
 import time
 
-from datetime import date
 from eccs2properties import ECCS2LOGSDIR, ECCS2RESULTSLOG, ECCS2CHECKSLOG, FEDS_BLACKLIST, IDPS_BLACKLIST, ECCS2SPS, ECCS2SELENIUMDEBUG
 from selenium.webdriver.common.by import By
 from selenium.webdriver.common.keys import Keys
@@ -38,15 +38,18 @@ def checkIdP(sp,idp,logger):
    entities_blacklist = IDPS_BLACKLIST 
 
    if (idp['registrationAuthority'] in federation_blacklist):
-      logger.info("%s;%s;NULL;Federation excluded from checks" % (idp['entityID'],sp))
-      return "DISABLED"
+      check_time = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S') + 'Z'
+      logger.info("%s;%s;%s;NULL;Federation excluded from checks" % (idp['entityID'],sp,check_time))
+      return (sp,check_time,"NULL","DISABLED")
 
    if (idp['entityID'] in entities_blacklist):
-      logger.info("%s;%s;NULL;IdP excluded from checks" % (idp['entityID'],sp))
-      return "DISABLED"
+      check_time = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S') + 'Z'
+      logger.info("%s;%s;%s;NULL;IdP excluded from checks" % (idp['entityID'],sp,check_time))
+      return (sp,check_time,"NULL","DISABLED")
 
    # Open SP, select the IDP from the EDS and press 'Enter' to reach the IdP login page to check
    try:
+      check_time = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S') + 'Z'
       driver.get(sp)
       element = WebDriverWait(driver, 50).until(EC.presence_of_element_located((By.ID,"idpSelectInput"))) 
       element.send_keys(idp['entityID'] + Keys.ENTER)
@@ -54,8 +57,8 @@ def checkIdP(sp,idp,logger):
       samlrequest_url = driver.current_url
 
    except TimeoutException as e:
-     logger.info("%s;%s;999;Timeout" % (idp['entityID'],sp))
-     return "Timeout"
+     logger.info("%s;%s;%s;999;Timeout" % (idp['entityID'],sp,check_time))
+     return (sp,check_time,"999","Timeout")
 
    except NoSuchElementException as e:
      # The input of the bootstrap tables are provided by "eccs2" and "eccs2checks" log.
@@ -66,8 +69,8 @@ def checkIdP(sp,idp,logger):
      return None
 
    except UnexpectedAlertPresentException as e:
-     logger.info("%s;%s;888;UnexpectedAlertPresent" % (idp['entityID'],sp))
-     return "ERROR"
+     logger.info("%s;%s;%s;888;UnexpectedAlertPresent" % (idp['entityID'],sp,check_time))
+     return (sp,check_time,"888","ERROR")
 
    except WebDriverException as e:
      print("!!! WEB DRIVER EXCEPTION - RUN AGAIN THE COMMAND!!!")
@@ -101,42 +104,42 @@ def checkIdP(sp,idp,logger):
      #print("!!! REQUESTS STATUS CODE CONNECTION ERROR EXCEPTION !!!")
      #print (e.__str__())
      #print ("IdP: %s\nSP: %s" % (idp['entityID'],sp))
-     status_code = 000
+     status_code = "000"
 
    except requests.exceptions.Timeout as e:
      #print("!!! REQUESTS STATUS CODE TIMEOUT EXCEPTION !!!")
      #print (e.__str__())
      #print ("IdP: %s\nSP: %s" % (idp['entityID'],sp))
-     status_code = 111
+     status_code = "111"
 
    except requests.exceptions.TooManyRedirects as e:
      #print("!!! REQUESTS TOO MANY REDIRECTS EXCEPTION !!!")
      #print (e.__str__())
      #print ("IdP: %s\nSP: %s" % (idp['entityID'],sp))
-     status_code = 222
+     status_code = "222"
 
    except requests.exceptions.RequestException as e:
      print ("!!! REQUESTS EXCEPTION !!!")
      print (e.__str__())
      print ("IdP: %s\nSP: %s" % (idp['entityID'],sp))
-     status_code = 333
+     status_code = "333"
 
    except Exception as e:
      print ("!!! EXCEPTION !!!")
      print (e.__str__())
      print ("IdP: %s\nSP: %s" % (idp['entityID'],sp))
-     status_code = 555
+     status_code = "555"
 
 
    if(metadata_not_found):
-      logger.info("%s;%s;%s;No-eduGAIN-Metadata" % (idp['entityID'],sp,status_code))
-      return "No-eduGAIN-Metadata"
+      logger.info("%s;%s;%s;%s;No-eduGAIN-Metadata" % (idp['entityID'],sp,status_code,check_time))
+      return (sp,check_time,status_code,"No-eduGAIN-Metadata")
    elif not username_found or not password_found:
-      logger.info("%s;%s;%s;Invalid-Form" % (idp['entityID'],sp,status_code))
-      return "Invalid-Form"
+      logger.info("%s;%s;%s;%s;Invalid-Form" % (idp['entityID'],sp,status_code,check_time))
+      return (sp,check_time,status_code,"Invalid-Form")
    else:
-      logger.info("%s;%s;%s;OK" % (idp['entityID'],sp,status_code))
-      return "OK"
+      logger.info("%s;%s;%s;%s;OK" % (idp['entityID'],sp,status_code,check_time))
+      return (sp,check_time,status_code,"OK")
 
 
 def check(idp,sps,eccs2log,eccs2checksLog):
@@ -152,46 +155,59 @@ def check(idp,sps,eccs2log,eccs2checksLog):
       strSuppContacts = ','.join(listSuppContacts)
 
       # If all checks are 'OK', than the IdP consuming correctly eduGAIN Metadata.
-      if (result[0] == result[1] == "OK"):
-         # IdP-DisplayName;IdP-entityID;IdP-RegAuth;IdP-tech-ctc-1,IdP-tech-ctc-2;IdP-supp-ctc-1,IdP-supp-ctc-2;Status;SP-entityID-1;SP-status-1;SP-entityID-2;SP-status-2
-         eccs2log.info("%s;%s;%s;%s;%s;%s;%s;%s;%s;%s" % (
+      if (result[0][3] == result[1][3] == "OK"):
+         # IdP-DisplayName;IdP-entityID;IdP-RegAuth;IdP-tech-ctc-1,IdP-tech-ctc-2;IdP-supp-ctc-1,IdP-supp-ctc-2;Status;SP-entityID-1;SP-check-time-1;SP-status-code-1;SP-result-1;SP-entityID-2;SP-check-time-2;SP-status-code-2;SP-result-2
+         eccs2log.info("%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s" % (
              idp['displayname'].replace("&apos;","'").split(';')[1].split('==')[0],
              idp['entityID'],
              idp['registrationAuthority'],
              strTechContacts,
              strSuppContacts,
              'OK',
-             sps[0],
-             result[0],
-             sps[1],
-             result[1]))
-      elif (result[0] == result[1] == "DISABLED"):
-         eccs2log.info("%s;%s;%s;%s;%s;%s;%s;%s;%s;%s" % (
+             result[0][0],
+             result[0][1],
+             result[0][2],
+             result[0][3],
+             result[1][0],
+             result[1][1],
+             result[1][2],
+             result[1][3]))
+      elif (result[0][3] == result[1][3] == "DISABLED"):
+         eccs2log.info("%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s" % (
              idp['displayname'].replace("&apos;","'").split(';')[1].split('==')[0],
              idp['entityID'],
              idp['registrationAuthority'],
              strTechContacts,
              strSuppContacts,
              'DISABLE',
-             sps[0],
-             result[0],
-             sps[1],
-             result[1]))
-      elif (result[0] == None or result[1] == None):
+             result[0][0],
+             result[0][1],
+             result[0][2],
+             result[0][3],
+             result[1][0],
+             result[1][1],
+             result[1][2],
+             result[1][3]))
+      elif (result[0][3] == None or result[1][3] == None):
           # Do nothing
           return
       else:
-         eccs2log.info("%s;%s;%s;%s;%s;%s;%s;%s;%s;%s" % (
+         eccs2log.info("%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s" % (
              idp['displayname'].replace("&apos;","'").split(';')[1].split('==')[0],
              idp['entityID'],
              idp['registrationAuthority'],
              strTechContacts,
              strSuppContacts,
              'ERROR',
-             sps[0],
-             result[0],
-             sps[1],
-             result[1]))
+             result[0][0],
+             result[0][1],
+             result[0][2],
+             result[0][3],
+             result[1][0],
+             result[1][1],
+             result[1][2],
+             result[1][3]))
+
 
 # MAIN
 if __name__=="__main__":
diff --git a/web/index.php b/web/index.php
index b19d92a..c5d243a 100644
--- a/web/index.php
+++ b/web/index.php
@@ -20,8 +20,11 @@
       <input type="checkbox" name="status" value="DISABLE">DISABLE
     </div>
     <hr>
+    <button id="btn-show-all-children" type="button">Expand All</button>
+    <button id="btn-hide-all-children" type="button">Collapse All</button>
+    <hr>
     <div class="container">
-      <table id="eccstable" class="display compact" style="width:100%">
+      <table id="eccstable" class="cell-border" style="width:100%">
         <thead>
             <tr>
                 <th></th>
diff --git a/web/script.js b/web/script.js
index 2227645..bbf8672 100644
--- a/web/script.js
+++ b/web/script.js
@@ -1,31 +1,32 @@
 /* Formatting function for row details - modify as you need */
 function format ( d ) {
     // `d` is the original data object for the row
-    return '<table cellpadding="5" cellspacing="0" border="0" style="padding-left:50px;">'+
+    return '<table id="inner-table">'+
         '<tr>'+
             '<td>IdP DisplayName:</td>'+
             '<td>'+d.displayName+'</td>'+
-            '<td></td>'+
         '</tr>'+
         '<tr>'+
             '<td>Technical Contacts:</td>'+
             '<td>'+d.contacts.technical+'</td>'+
-            '<td></td>'+
         '</tr>'+
         '<tr>'+
             '<td>Support Contacts:</td>'+
             '<td>'+d.contacts.support+'</td>'+
-            '<td></td>'+
         '</tr>'+
         '<tr>'+
             '<td>SP1:</td>'+
             '<td>'+d.sp1.entityID+'</td>'+
+            '<td>'+d.sp1.checkTime+'</td>'+
             '<td>'+d.sp1.status+'</td>'+
+            '<td>'+d.sp1.statusCode+'</td>'+
         '</tr>'+
         '<tr>'+
             '<td>SP2:</td>'+
             '<td>'+d.sp2.entityID+'</td>'+
+            '<td>'+d.sp2.checkTime+'</td>'+
             '<td>'+d.sp2.status+'</td>'+
+            '<td>'+d.sp2.statusCode+'</td>'+
         '</tr>'+
     '</table>';
 }
@@ -102,4 +103,30 @@ $(document).ready(function() {
        table.column(5).search(sts, true, false, false).draw(false);
     });
 
+    // Handle click on "Expand All" button
+    $('#btn-show-all-children').on('click', function(){
+        // Enumerate all rows
+        table.rows().every(function(){
+            // If row has details collapsed
+            if(!this.child.isShown()){
+                // Open this row
+                this.child(format(this.data())).show();
+                $(this.node()).addClass('shown');
+            }
+        });
+    });
+
+    // Handle click on "Collapse All" button
+    $('#btn-hide-all-children').on('click', function(){
+        // Enumerate all rows
+        table.rows().every(function(){
+            // If row has details expanded
+            if(this.child.isShown()){
+                // Collapse row details
+                this.child.hide();
+                $(this.node()).removeClass('shown');
+            }
+        });
+    });   
+
 } );
diff --git a/web/style.css b/web/style.css
index 1b5faa4..0c3b61f 100644
--- a/web/style.css
+++ b/web/style.css
@@ -6,3 +6,12 @@ td.details-control {
 tr.shown td.details-control {
   background: url('./details_close.png') no-repeat center center;
 }
+
+#inner-table {
+ padding-left:40px; 
+ background-color:white;
+}
+
+#inner-table tr td{
+   border: 0;
+}
-- 
GitLab