We would like an email to go out to people when training will run out.  When there is 2 weeks remaining, people should get a nightly email reminder.

The LMS should do this, but if people on the project team are not in the curriculum in the LMS, they fall through the cracks.  But Grouper know when people will expire.

This does not require Java, or restarting any services.  This will be a nightly GSH daemon.

Data of when people expire

First we need a query for the right population, and get the date training will query, but that in a view.

The LMS data is in another DB as the Grouper data, so we need two views and a DB link

create view AUTHZ_KL_FERPA_EXPIRE_V as
     SELECT s.penn_id,
            s.completion_date + 362 as needed_by_date -- few days less than a year so they have some notice
       FROM dwlms.LM_CURRENT_TRAINING_STATUS s, dwlms.LM_USER u
      WHERE     s.penn_id = u.penn_id
            AND s.completed = 'Y'
            and s.item_id = 'UP.87024.ITEM.FERPA001'
            and s.completion_date is not null 
            and s.completion_date < SYSDATE - (362-14) -- two weeks before you need notice
            ;

Population of people to get the email

Population of team

penn:isc:ait:apps:ngss:team:ngssTeamAllBeforeCheckingStatus

Note, lets allow them to opt out of the notifications.  Here is an opt in group.  Note, allow optin/optout for ngssTeamAllBeforeCheckingStatus

penn:isc:ait:apps:ngss:team:ngssTeamNotificationsIgnoreForStatusWarnings

Make a composite which is the policy group that identifies people eligible for status warning notifications

penn:isc:ait:apps:ngss:team:ngssTeamNotificationsEligibleForStatusWarnings

Lets not email more than once a day

Make this group: penn:isc:ait:apps:ngss:team:ngssTeamNotificationsLastSent

People here have a membership attribute with string that is yyyy/mm/dd of last time sent

Make this attribute: penn:isc:ait:apps:ngss:attributes:ngssTeamNotificationsLastSent (on memberships, string)

Test view for myself

CREATE OR REPLACE FORCE VIEW AUTHZ_NGSS_FERPA_NEEDED_V
(
   PENN_ID,
   NEEDED_BY_DATE
)
   BEQUEATH DEFINER
AS
   SELECT '10021368' AS penn_id, '2020/01/23' AS needed_by_date FROM DUAL;


Externalize some text

Externalized text: ngss.notification.ferpa.body

Dear ${yourName},$newline$Your yearly FERPA training will expire on ${theDate} at which point you will lose access to NGSS software that you need to work.  Please take the training asap.$newline$$newline$https://mylms/ngssFerpa$newline$$newline$Thanks!$newline$Chris Hyzer$newline$slack/teams/skype me if you have issues.


GSH script

    GrouperSession grouperSession = GrouperSession.startRootSession();
    
    String date = new java.text.SimpleDateFormat("yyyy/MM/dd").format(new Date());
    List pennIdsSentToday = new edu.internet2.middleware.grouperClient.jdbc.GcDbAccess().sql("select subject_id from grouper_aval_asn_efmship_v gaaev where group_name = 'penn:isc:ait:apps:ngss:team:ngssTeamNotificationsLastSent' and attribute_def_name_name = 'penn:isc:ait:apps:ngss:attributes:ngssTeamNotificationsLastSent' and value_string = ?").addBindVar(date).selectList(String.class);
        
    List results = new edu.internet2.middleware.grouperClient.jdbc.GcDbAccess().connectionName("pennCommunity").sql("select penn_id, needed_by_date from authz_ngss_ferpa_needed_v").selectList(Object[].class);

    RuntimeException re = null;
    for (Object[] result : (List<Object[]>)results) {

      edu.internet2.middleware.grouper.app.loader.OtherJobScript.retrieveFromThreadLocal().getOtherJobInput().getHib3GrouperLoaderLog().addTotalCount(1);
      
      try {

        String pennid = (String)result[0];
        if (pennIdsSentToday.contains(pennid)) {
          continue;
        }
        String neededByDate = (String)result[1];
        Subject subject = SubjectFinder.findByIdAndSource(pennid, "pennperson", true);
        if (subject == null) {
          continue;
        }
        String email = subject.getAttributeValue("email");
        if (GrouperUtil.isBlank(email)) {
          continue;
        }
        
        edu.internet2.middleware.grouper.cfg.text.GrouperTextContainer.assignThreadLocalVariable("yourName", subject.getName());
        edu.internet2.middleware.grouper.cfg.text.GrouperTextContainer.assignThreadLocalVariable("theDate", neededByDate);
        
        new GrouperEmail().setTo(email).setSubject(edu.internet2.middleware.grouper.cfg.text.GrouperTextContainer.textOrNull("ngss.notification.ferpa.subject")).setBody(edu.internet2.middleware.grouper.cfg.text.GrouperTextContainer.textOrNull("ngss.notification.ferpa.body")).send();

        edu.internet2.middleware.grouper.cfg.text.GrouperTextContainer.resetThreadLocalVariableMap();

        Group group = GroupFinder.findByName(grouperSession, "penn:isc:ait:apps:ngss:team:ngssTeamNotificationsLastSent", true);
        group.addMember(subject, false);
        Member member = MemberFinder.findBySubject(grouperSession, subject, true);
        group.getAttributeValueDelegateEffMship(member).assignValue("penn:isc:ait:apps:ngss:attributes:ngssTeamNotificationsLastSent", date);

        edu.internet2.middleware.grouper.app.loader.OtherJobScript.retrieveFromThreadLocal().getOtherJobInput().getHib3GrouperLoaderLog().addUpdateCount(1);

      } catch (RuntimeException e) {

        e.printStackTrace();
        re = e;

        edu.internet2.middleware.grouper.app.loader.OtherJobScript.retrieveFromThreadLocal().getOtherJobInput().getHib3GrouperLoaderLog().incrementUnresolvableSubjectCount();
      }
    }
    if (re != null) {
      throw re;
    }


We will search and replace the newlines to be $newline$

otherJob.ngssNotificationFerpaExpire.class = edu.internet2.middleware.grouper.app.loader.OtherJobScript
otherJob.ngssNotificationFerpaExpire.quartzCron = 0 0 6 * * ?
otherJob.ngssNotificationFerpaExpire.scriptType = gsh
otherJob.ngssNotificationFerpaExpire.scriptSource = GrouperSession grouperSession = GrouperSession.startRootSession();$newline$    String date = new java.text.SimpleDateFormat("yyyy/MM/dd").format(new Date());$newline$    List pennIdsSentToday = new edu.internet2.middleware.grouperClient.jdbc.GcDbAccess().sql("select subject_id from grouper_aval_asn_efmship_v gaaev where group_name = 'penn:isc:ait:apps:ngss:team:ngssTeamNotificationsLastSent' and attribute_def_name_name = 'penn:isc:ait:apps:ngss:attributes:ngssTeamNotificationsLastSent' and value_string = ?").addBindVar(date).selectList(String.class);$newline$    List results = new edu.internet2.middleware.grouperClient.jdbc.GcDbAccess().connectionName("pennCommunity").sql("select penn_id, needed_by_date from authz_ngss_ferpa_needed_v").selectList(Object[].class);$newline$    RuntimeException re = null;$newline$    for (Object[] result : (List<Object[]>)results) {$newline$      edu.internet2.middleware.grouper.app.loader.OtherJobScript.retrieveFromThreadLocal().getOtherJobInput().getHib3GrouperLoaderLog().addTotalCount(1);$newline$      try {$newline$        String pennid = (String)result[0];$newline$        if (pennIdsSentToday.contains(pennid)) {$newline$          continue;$newline$        }$newline$        String neededByDate = (String)result[1];$newline$        Subject subject = SubjectFinder.findByIdAndSource(pennid, "pennperson", true);$newline$        if (subject == null) {$newline$          continue;$newline$        }$newline$        String email = subject.getAttributeValue("email");$newline$        if (GrouperUtil.isBlank(email)) {$newline$          continue;$newline$        }        $newline$        edu.internet2.middleware.grouper.cfg.text.GrouperTextContainer.assignThreadLocalVariable("yourName", subject.getName());$newline$        edu.internet2.middleware.grouper.cfg.text.GrouperTextContainer.assignThreadLocalVariable("theDate", neededByDate);        $newline$        new GrouperEmail().setTo(email).setFrom("noreply@isc.upenn.edu").setSubject(edu.internet2.middleware.grouper.cfg.text.GrouperTextContainer.textOrNull("ngss.notification.ferpa.subject")).setBody(edu.internet2.middleware.grouper.cfg.text.GrouperTextContainer.textOrNull("ngss.notification.ferpa.body")).send();$newline$        edu.internet2.middleware.grouper.cfg.text.GrouperTextContainer.resetThreadLocalVariableMap();$newline$        Group group = GroupFinder.findByName(grouperSession, "penn:isc:ait:apps:ngss:team:ngssTeamNotificationsLastSent", true);$newline$        group.addMember(subject, false);$newline$        Member member = MemberFinder.findBySubject(grouperSession, subject, true);$newline$        group.getAttributeValueDelegateEffMship(member).assignValue("penn:isc:ait:apps:ngss:attributes:ngssTeamNotificationsLastSent", date);$newline$        edu.internet2.middleware.grouper.app.loader.OtherJobScript.retrieveFromThreadLocal().getOtherJobInput().getHib3GrouperLoaderLog().addUpdateCount(1);$newline$      } catch (RuntimeException e) {$newline$        e.printStackTrace();$newline$        re = e;$newline$        edu.internet2.middleware.grouper.app.loader.OtherJobScript.retrieveFromThreadLocal().getOtherJobInput().getHib3GrouperLoaderLog().incrementUnresolvableSubjectCount();$newline$      }$newline$    }$newline$    if (re != null) {$newline$  throw re; $newline$   }
  • No labels