Sending notifications

Previous: Working with the enactment history ] [ Top:  ] [ Next: Taking external action ]

I've put a lot of thought into how notifications (alerts) should work. I've finally come up with the following scheme. First, the alert itself is basically the message, with attributes for recipient, sender, subject, etc. The body of the alert is the body of the message. This is interpreted in the context of a datasheet if one is associated with the alert.

The datasheet is thus the primary context of an alert, but other objects also make sense. For instance, if I have a user profile, it makes sense to be able to send a message to that user directly. Similarly, tasks, requests, and procdefs all make sense as contexts if you simply send the message to the owner of the object.

If an object other than a user is given as the context, then it's searched for a user object in it with the same name as the recipient. Otherwise we treat the user given as the recipient. Either way, we look at the recipient for a preferred modality of notification (say, email), then check our configuration for the adaptor used to address that modality (say, smtp:www.vivtek.com). In addition, we collect an adaptorlist of notification adaptors which the system should always copy to; this will allow for logging of notifications, backup to database, and the like.

I'm sure that even this fairly complicated rigamarole will get even more complicated once it hits reality...

March 22, 2004: Well, it took a while for reality to catch up, but it did so with decisiveness. I've rebuilt notifications entirely in the context of the repository manager (and among other things, they use standard views and can express email in both plaintext and HTML formats, which makes things easier.) So if we're not in the wftk-bare context, we're going to do a very minimal amount of work, then ship the whole alert off to the repository manager.
 
WFTK_EXPORT int wftk_notify (XML * session, XML * context, XML * alert) {
   WFTK_ADAPTOR * ad;
   WFTK_ADAPTORLIST * adlist;
   XML * user = context;
   XML * from;
   const char * preferred_modality = "";
   const char * always_list;
   char *tovalue;
   XML * temp;

#ifdef WFTK_WITH_REPMGR
   repos_notify_direct (session, xml_attrval (context, "list"), xml_attrval (context, "key"), context, alert, NULL, NULL);
#else
   if (!xml_is (context, "user")) {
      tovalue = wftk_value_interpreta (session, context, xml_attrval (alert, "to"));
      user = xml_firstelem (user);
      while (user) {
         if (xml_is (user, "user") && !strcmp (xml_attrval (user, "id"), tovalue)) break;
         user = xml_nextelem (user);
      }
      free (tovalue);
   }

   if (*xml_attrval (alert, "from")) {
      tovalue = wftk_value_interpreta (session, context, xml_attrval (alert, "from"));
      from = wftk_user_retrieve (session, context, tovalue);
      free (tovalue);
      preferred_modality = xml_attrval (from, "notifyvia");
      if (!*preferred_modality) preferred_modality = wftk_config_get_value (session, "notify.default");
      if (*preferred_modality) {
         xml_set (alert, "from_addr", xml_attrval (from, preferred_modality));
      }
      xml_set (alert, "from_name", xml_attrval (from, "name"));
   } else {
      xml_set (alert, "from_addr", wftk_config_get_value (session, "notify.system_from"));
      xml_set_nodup (alert, "from_name", wftk_value_interpreta (session, context, wftk_config_get_value (session, "notify.system_name")));
   }

   if (user) {
      wftk_user_synch (session, user);
      preferred_modality = xml_attrval (user, "notifyvia");
      if (!*preferred_modality) preferred_modality = wftk_config_get_value (session, "notify.default");
      if (*preferred_modality) {
         xml_set (alert, "to_addr", xml_attrval (user, preferred_modality));
         xml_set (alert, "to_name", xml_attrval (user, "name"));

         temp = xml_create ("value");
         xml_setf (temp, "value", "notify.%s", preferred_modality);
         ad = wftk_get_adaptor (session, NOTIFY, wftk_config_get_value (session, xml_attrval (temp, "value")));
         xml_free (temp);
         if (ad) {
            wftk_call_adaptor (ad, "send", context, alert);
            wftk_free_adaptor (session, ad);
         }
      }
   } else {
      preferred_modality = wftk_config_get_value (session, "notify.default");
      xml_set_nodup (alert, "to_addr", wftk_value_interpreta (session, context, xml_attrval (alert, "to")));

      temp = xml_create ("value");
      xml_setf (temp, "value", "notify.%s", preferred_modality);
      ad = wftk_get_adaptor (session, NOTIFY, wftk_config_get_value (session, xml_attrval (temp, "value")));
      xml_free (temp);
      if (ad) {
         wftk_call_adaptor (ad, "send", context, alert);
         wftk_free_adaptor (session, ad);
      }
   }

   adlist = wftk_get_adaptorlist (session, NOTIFY);
   if (adlist) {
      wftk_call_adaptorlist (adlist, "send", context, alert);
      wftk_free_adaptorlist (session, adlist);
   }
#endif
   return 1;
}
Previous: Working with the enactment history ] [ Top:  ] [ Next: Taking external action ]


This code and documentation are released under the terms of the GNU license. They are copyright (c) 2000-2004, Vivtek. All rights reserved except those explicitly granted under the terms of the GNU license.