Screenshots

See this page

Configuration


grouperGshTemplate.zoomDeprovisioning.displayErrorOutput = true
grouperGshTemplate.zoomDeprovisioning.folderShowOnDescendants = certainFolderAndDescendants
grouperGshTemplate.zoomDeprovisioning.folderShowType = certainFolder
grouperGshTemplate.zoomDeprovisioning.folderUuidToShow = 319a44d13d754dfea820571dd2709147
grouperGshTemplate.zoomDeprovisioning.groupUuidCanRun = b05d4ff9946c4e6aa3f33c6e71dcca48
grouperGshTemplate.zoomDeprovisioning.input.0.description = Pick what you want to do.  Manage non humans to remove false positives.  Manage email links to link non-eppn emails up with their identities.  The reports have the CSVs.  Reports are scheduled to run weekly so you should generally run them before viewing them to get most recent data.
grouperGshTemplate.zoomDeprovisioning.input.0.dropdownCsvValue = runReports, viewReports, addNonHumans, removeNonHumans, addEmailMappings, removeEmailMappings
grouperGshTemplate.zoomDeprovisioning.input.0.dropdownValueFormat = csv
grouperGshTemplate.zoomDeprovisioning.input.0.formElementType = dropdown
grouperGshTemplate.zoomDeprovisioning.input.0.label = Action
grouperGshTemplate.zoomDeprovisioning.input.0.name = gsh_input_action
grouperGshTemplate.zoomDeprovisioning.input.0.required = true
grouperGshTemplate.zoomDeprovisioning.input.1.description = Enter in emails, one on each line, no delimiters
grouperGshTemplate.zoomDeprovisioning.input.1.formElementType = textarea
grouperGshTemplate.zoomDeprovisioning.input.1.label = Emails
grouperGshTemplate.zoomDeprovisioning.input.1.maxLength = 100000
grouperGshTemplate.zoomDeprovisioning.input.1.name = gsh_input_emails
grouperGshTemplate.zoomDeprovisioning.input.1.required = true
grouperGshTemplate.zoomDeprovisioning.input.1.showEl = ${gsh_input_action == 'addNonHumans' || gsh_input_action == 'removeNonHumans' || gsh_input_action == 'removeEmailMappings' }
grouperGshTemplate.zoomDeprovisioning.input.1.validationType = none
grouperGshTemplate.zoomDeprovisioning.input.2.description = Enter in CSV with no headers.  First col is email address, second col is penn id or pennkey.
grouperGshTemplate.zoomDeprovisioning.input.2.formElementType = textarea
grouperGshTemplate.zoomDeprovisioning.input.2.label = Email link
grouperGshTemplate.zoomDeprovisioning.input.2.maxLength = 100000
grouperGshTemplate.zoomDeprovisioning.input.2.name = gsh_input_emailLink
grouperGshTemplate.zoomDeprovisioning.input.2.showEl = ${gsh_input_action == 'addEmailMappings'}
grouperGshTemplate.zoomDeprovisioning.input.2.validationType = none
grouperGshTemplate.zoomDeprovisioning.moreActionsLabel = Zoom deprovisioning
grouperGshTemplate.zoomDeprovisioning.numberOfInputs = 3
grouperGshTemplate.zoomDeprovisioning.runAsType = GrouperSystem
grouperGshTemplate.zoomDeprovisioning.securityRunType = specifiedGroup
grouperGshTemplate.zoomDeprovisioning.showInMoreActions = true
grouperGshTemplate.zoomDeprovisioning.showOnFolders = true
grouperGshTemplate.zoomDeprovisioning.templateDescription = Manage deprovisioning of zoom licensed accounts
grouperGshTemplate.zoomDeprovisioning.templateName = Zoom deprovisioning


GSH script

//import java.util.ArrayList;
//import java.util.HashMap;
//import java.util.HashSet;
//import java.util.List;
//import java.util.Map;
//import java.util.Set;
//
//import org.apache.commons.lang.StringUtils;
//
//import edu.internet2.middleware.grouper.GrouperSession;
//import edu.internet2.middleware.grouper.Member;
//import edu.internet2.middleware.grouper.MemberFinder;
//import edu.internet2.middleware.grouper.Stem;
//import edu.internet2.middleware.grouper.StemFinder;
//import edu.internet2.middleware.grouper.SubjectFinder;
//import edu.internet2.middleware.grouper.app.gsh.template.GshTemplateOutput;
//import edu.internet2.middleware.grouper.app.loader.GrouperLoader;
//import edu.internet2.middleware.grouper.misc.GrouperStartup;
//import edu.internet2.middleware.grouper.util.GrouperUtil;
//import edu.internet2.middleware.grouperClient.jdbc.GcDbAccess;
//import edu.internet2.middleware.subject.Subject;
//
////uncomment to compile in eclipse (and last line)
//public class Test11 {
//
//  public Test11() {
//  }
//
//  public static void main(String[] args) {
//    
//    GrouperStartup.startup();
//        
//    GrouperSession gsh_builtin_grouperSession = GrouperSession.startRootSession();
//    Subject gsh_builtin_subject = SubjectFinder.findByIdentifierAndSource("mchyzer", "pennperson", true);
//    GshTemplateOutput gsh_builtin_gshTemplateOutput = new GshTemplateOutput();
//    String gsh_builtin_ownerStemName = "penn:isc:ait:apps:zoom:service:ref:zoomDeprovisioning";
//    
//    String gsh_input_action = "removeEmailMappings"; //  runReports, viewReports, addNonHumans, removeNonHumans, addEmailMappings, removeEmailMappings
//    String gsh_input_emails = "brymes@gse.upenn.edu"; //     gsh_input_emails += "0095a7722511b8e55f72e557efbf3c4a1dccf7ae@upenn.edu\n";
//    String gsh_input_emailLink = ""; //     gsh_input_emailLink += "brymes@gse.upenn.edu, brymes\n";

    // check valid action (should never be invalid since drop down)
    
    boolean actionRunReports = StringUtils.equals(gsh_input_action, "runReports");
    boolean actionViewReports = StringUtils.equals(gsh_input_action, "viewReports");
    boolean actionAddNonHumans = StringUtils.equals(gsh_input_action, "addNonHumans");
    boolean actionRemoveNonHumans = StringUtils.equals(gsh_input_action, "removeNonHumans");
    boolean actionAddEmailMappings = StringUtils.equals(gsh_input_action, "addEmailMappings");
    boolean actionRemoveEmailMappings = StringUtils.equals(gsh_input_action, "removeEmailMappings");
    if (!actionRunReports && !actionViewReports && !actionAddNonHumans && !actionViewReports && !actionRemoveNonHumans && !actionAddEmailMappings && !actionRemoveEmailMappings) {

      gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_action",
          "Error: Action cannot be found '" + gsh_input_action + "'!");

    }

    // stay on screen
    if (!actionViewReports) {
      gsh_builtin_gshTemplateOutput.assignRedirectToGrouperOperation("NONE");
    }

    
    // make sure emails are valid
    Set<String> emails = null;
    if (actionAddNonHumans || actionRemoveNonHumans || actionRemoveEmailMappings) {
      gsh_input_emails = StringUtils.replace(gsh_input_emails, "\r\n", "\n");
      gsh_input_emails = StringUtils.replace(gsh_input_emails, "\r", "\n");
      emails = GrouperUtil.splitTrimToSet(gsh_input_emails, "\n");
      emails.remove("");
      if (emails.size() == 0) {
        gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_emails", 
            "Error: Enter some emails");
      }
      for (String email : emails) {
        if (email.contains(" ") || email.contains(",")) {
          gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_emails", 
              "Error: Invalid email '" + email + "'");
        }
        if (!email.contains("@")) {
          gsh_builtin_gshTemplateOutput.addOutputLine("Note this email '" + email + "' does not contain an @ sign");
        }
      }
    }

    Map<String, String> emailLinks = null; // email, charPennId
    if (actionAddEmailMappings) {
      emailLinks = new HashMap<String, String>();
      gsh_input_emailLink = StringUtils.replace(gsh_input_emailLink, "\r\n", "\n");
      gsh_input_emailLink = StringUtils.replace(gsh_input_emailLink, "\r", "\n");
      Set<String> emailLinkLines = GrouperUtil.splitTrimToSet(gsh_input_emailLink, "\n");
      emailLinkLines.remove("");
      if (emailLinkLines.size() == 0) {
        gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_emailLink", 
            "Error: Enter some comma separated emails and (pennkeys or pennids), e.g. jsmith@gmail.com, jsmith -or- jsmith@gmail.com, 12345678");
      }
      for (String emailLinkLine : emailLinkLines) {
        if (!emailLinkLine.contains(",")) {
          gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_emailLink", 
              "Error: Invalid email link '" + emailLinkLine + "', should be: email@address comma pennkeyOrPennid");
          continue;
        }
        
        String email = StringUtils.trim(GrouperUtil.prefixOrSuffix(emailLinkLine, ",", true));
        String pennkeyOrPennid = StringUtils.trim(GrouperUtil.prefixOrSuffix(emailLinkLine, ",", false));
        
        if (email.contains(" ") || email.contains(",")) {
          gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_emailLink", 
              "Error: Invalid email '" + email + "'");
        } else if (!email.contains("@")) {
          gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_emailLink", "Note this email '" + email + "' does not contain an @ sign");
        } else {
          
          Subject subject = SubjectFinder.findByIdOrIdentifierAndSource(pennkeyOrPennid, "pennperson", false);
          if (subject == null) {
            gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_emailLink", "Person not found: '" + pennkeyOrPennid + "'");
            continue;
          }
          emailLinks.put(email, subject.getId());
        }
      }
      if (emailLinks.size() == 0) {
        gsh_builtin_gshTemplateOutput.addValidationLine("gsh_input_emailLink", 
            "Error: No email links found");
      }

    }
    
    
    
    // if anything not valid, stop
    if (GrouperUtil.length(gsh_builtin_gshTemplateOutput.getValidationLines()) > 0) {
      gsh_builtin_gshTemplateOutput.assignIsError(true);
      GrouperUtil.gshReturn();
    }

    java.sql.Timestamp now = new java.sql.Timestamp(System.currentTimeMillis());
    
    GrouperUtil.sleep(3000);


    if (actionAddNonHumans || actionRemoveNonHumans) {

      // get emails from database
      Set<String> emailsLowerInDatabase = new HashSet<String>(new GcDbAccess().sql("select lower(email) from penn_zoom_non_human").selectList(String.class));
      
      GcDbAccess gcDbAccess = new GcDbAccess().batchSize(200);
      List<List<Object>> batchBindVars = new ArrayList<List<Object>>();
      gcDbAccess.batchBindVars(batchBindVars);
      
      Member builtInMember = MemberFinder.findBySubject(gsh_builtin_grouperSession, gsh_builtin_subject, true);
      
      if (actionAddNonHumans) {
        gcDbAccess.sql("insert into penn_zoom_non_human (email, modifier_id, modify_time) values (?, ?, ?)");
      } else if (actionRemoveNonHumans) {
        gcDbAccess.sql("delete from penn_zoom_non_human where lower(email) = ?");
      }
      
      long modifyTime = System.currentTimeMillis();
      
      int countChanged = 0;
      int countUnchanged = 0;
      
      for (String email : emails) {
        
        boolean emailInDatabase = emailsLowerInDatabase.contains(email.toLowerCase());

        if (actionAddNonHumans) {
          
          if (emailInDatabase) {
            countUnchanged++;
          } else {
            countChanged++;
            batchBindVars.add(GrouperUtil.toListObject(email, builtInMember.getId(), modifyTime));
          }
        } else if (actionRemoveNonHumans) {
          if (emailInDatabase) {
            countChanged++;
            batchBindVars.add(GrouperUtil.toListObject(email));
          } else {
            countUnchanged++;
          }
          
        }
        
      }

      if (countChanged > 0) {
        gcDbAccess.executeBatchSql();
        gsh_builtin_gshTemplateOutput.addOutputLine("Made " + countChanged + " changes");
      }
      if (countUnchanged > 0) {
        gsh_builtin_gshTemplateOutput.addOutputLine(countUnchanged + " records did not need changes");
      }
      
    }
    
    if (actionAddEmailMappings || actionRemoveEmailMappings) {

      // get emails from database
      List<Object[]> emailsLowerInDatabase = new GcDbAccess().connectionName("pennCommunity").sql("select lower(lower_email_address), char_penn_id from person_source_email_adhoc").selectList(Object[].class);
      
      Map<String, String> emailLowerToPennIdInDatabase = new HashMap<String, String>();
      
      for (Object[] row : GrouperUtil.nonNull(emailsLowerInDatabase)) {
        emailLowerToPennIdInDatabase.put((String)row[0], (String)row[1]);
      }
      
      GcDbAccess gcDbAccessAdd = new GcDbAccess().connectionName("pennCommunity").batchSize(200);
      List<List<Object>> batchBindVarsAdd = new ArrayList<List<Object>>();
      gcDbAccessAdd.batchBindVars(batchBindVarsAdd);
      gcDbAccessAdd.sql("insert into person_source_email_adhoc (lower_email_address, char_penn_id) values (?, ?)");
      
      GcDbAccess gcDbAccessDelete = new GcDbAccess().connectionName("pennCommunity").batchSize(200);
      List<List<Object>> batchBindVarsDelete = new ArrayList<List<Object>>();
      gcDbAccessDelete.batchBindVars(batchBindVarsDelete);
      gcDbAccessDelete.sql("delete from person_source_email_adhoc where lower(lower_email_address) = ?");
      
      int countChanged = 0;
      int countUnchanged = 0;
      
      if (actionAddEmailMappings) {
        for (String email : emailLinks.keySet()) {

          String pennId = emailLinks.get(email);

          boolean emailInDatabase = emailLowerToPennIdInDatabase.containsKey(email.toLowerCase());

          if (emailInDatabase) {
            
            String pennIdInDatabase = emailLowerToPennIdInDatabase.get(email.toLowerCase());
            if (StringUtils.equals(pennIdInDatabase, pennId)) {
              countUnchanged++;
              continue;
            } else {
              batchBindVarsDelete.add(GrouperUtil.toListObject(email.toLowerCase()));
            }
          }
          batchBindVarsAdd.add(GrouperUtil.toListObject(email.toLowerCase(), pennId));
          countChanged++;
        }
      }
      if (actionRemoveEmailMappings) {
        for (String email: emails) {
          boolean emailInDatabase = emailLowerToPennIdInDatabase.containsKey(email.toLowerCase());
          if (emailInDatabase) {
            countChanged++;
            batchBindVarsDelete.add(GrouperUtil.toListObject(email));
          } else {
            countUnchanged++;
          }
        }
      }

      if (countChanged > 0) {
        if (batchBindVarsDelete.size() > 0) {
          gcDbAccessDelete.executeBatchSql();
        }
        if (batchBindVarsAdd.size() > 0) {
          gcDbAccessAdd.executeBatchSql();
        }
        gsh_builtin_gshTemplateOutput.addOutputLine("Made " + countChanged + " changes");
      }
      if (countUnchanged > 0) {
        gsh_builtin_gshTemplateOutput.addOutputLine(countUnchanged + " records did not need changes");
      }
      gsh_builtin_gshTemplateOutput.addOutputLine("Running daemons...");
      List<String> jobNames = GrouperUtil.toList("OTHER_JOB_personSourceEmailLookup", "OTHER_JOB_personSourceEmailLookup2", "OTHER_JOB_personSourceEmailCopyFull");
      for (String jobName : jobNames) {
        GrouperLoader.runOnceByJobName(gsh_builtin_grouperSession, jobName, true);
      }
      boolean[] successes = new boolean[jobNames.size()];
      boolean overallSuccess = false;
      OUTER: for (int i=0;i<12;i++) {
        GrouperUtil.sleep(5000);
        for (int j=0;j<jobNames.size();j++) {
          if (!successes[j]) {
            successes[j] = 1 <= new GcDbAccess().sql("select count(1) from grouper_loader_log where job_name = '" + jobNames.get(j) + "' and status = 'SUCCESS' and started_time > ?").addBindVar(now).select(int.class);
          }
        }
        for (boolean success : successes) {
          if (!success) {
            continue OUTER;
          }
        }
        overallSuccess = true;
      }
      if (!overallSuccess) {
        gsh_builtin_gshTemplateOutput.addOutputLine("error", "Could not successfully run daemons...");
      }
    }
    if (actionRunReports) {
      
      
      gsh_builtin_gshTemplateOutput.addOutputLine("Running loader daemon which takes a few minutes...");
      
      GrouperLoader.runOnceByJobName(gsh_builtin_grouperSession, "OTHER_JOB_pennZoomLoader", true);
      
      for (int i=0;i<40;i++) {
        GrouperUtil.sleep(10000);
        if (1 <= new GcDbAccess().sql("select count(1) from grouper_loader_log where job_name = 'OTHER_JOB_pennZoomLoader' and status = 'SUCCESS' and started_time > ?").addBindVar(now).select(int.class)) {
          break;
        }
      }
      
      List<String> jobNames = GrouperUtil.toList("grouper_report_319a44d13d754dfea820571dd2709147_4659596c6b804041bb2b86a9aa2ecfb8",
          "grouper_report_319a44d13d754dfea820571dd2709147_6f406147cca7464d9dc75805c8d9b3bf",
          "grouper_report_319a44d13d754dfea820571dd2709147_8bca4a2525d4403baede757b10db2f5a", 
          "grouper_report_319a44d13d754dfea820571dd2709147_9ba8ca3a5f2b490088b2b008a4ed2bcd");
      for (String jobName : jobNames) {
        GrouperLoader.runOnceByJobName(gsh_builtin_grouperSession, jobName, true);
      }
      boolean[] successes = new boolean[jobNames.size()];

      boolean overallSuccess = false;
      OUTER: for (int i=0;i<12;i++) {
        GrouperUtil.sleep(5000);
        for (int j=0;j<jobNames.size();j++) {
          if (!successes[j]) {
            successes[j] = 1 <= new GcDbAccess().sql("select count(1) from grouper_loader_log where job_name = '" + jobNames.get(j) + "' and status = 'SUCCESS' and started_time > ?").addBindVar(now).select(int.class);
          }
        }
        for (boolean success : successes) {
          if (!success) {
            continue OUTER;
          }
        }
        overallSuccess = true;
      }
      if (!overallSuccess) {
        gsh_builtin_gshTemplateOutput.addOutputLine("error", "Could not successfully run daemons...");
      }

    }
    if (actionViewReports) {
      Stem stem = StemFinder.findByName(gsh_builtin_grouperSession, gsh_builtin_ownerStemName, true);
      gsh_builtin_gshTemplateOutput.addOutputLine("success", "Please wait while reports are retrieved");
      gsh_builtin_gshTemplateOutput.assignRedirectToGrouperOperation("operation=UiV2GrouperReport.viewReportConfigsOnFolder&stemId=" + stem.getId());
    }
    // done!
    gsh_builtin_gshTemplateOutput.addOutputLine("Finished running zoom deprovisioning template!");

//    }
//  
//  }


  • No labels