wftk_task_new
. If an action, the action is done with wftk_action_do
. If
anything else, it's created as ad-hoc workflow with wftk_process_adhoc
. Note that we don't have a lot of
permissions here. Eventually we're going to want to funnel all that through wftk_action_do
so that
we don't have a security problem.
The request can also name a particular task in the "task" attribute; upon acceptance, that task will thus be assigned to
the requestee. There is no security on this at this point, which is (naturally) a bad idea in the long term, as it would
be simple to steal tasks by requesting them to be assigned to you, then accepting the request. Post-v1.0.
A request will be indexed with a starting "?", and so a request naming a task starting with "?" will be construed as a
sub-request; upon acceptance it will accept its parent request in the name of the requestee. So Joe has a task and sends
a reassignment request to Karen, then Karen sends a subrequest to Larry. Larry accepts, so Joe's task gets assigned to
Larry. Everybody gets notified that this has happened.
Finally, if the request has a "role" attribute, then it's a request to take over a particular role for the process and will
result in role assignment.
WFTK_EXPORT int wftk_request_new (void * session, XML * request) { XML * datasheet = NULL; XML * req; XML * requestor = NULL; XML * mark; XML * alert = NULL; const char * alertcontent; char * newalertcontent = NULL; WFTK_ADAPTORLIST * adlist; if (!request) return 0; if (*xml_attrval (request, "process")) { datasheet = wftk_process_load (session, xml_attrval (request, "dsrep"), xml_attrval (request, "process")); if (!datasheet) return 0; } if (datasheet && !*xml_attrval (request, "of") && *xml_attrval (request, "of-role")) { xml_set (request, "of", wftk_role_user (session, datasheet, xml_attrval (request, "of-role"))); } if (!*xml_attrval (request, "of")) { xml_set (request, "status", "error"); xml_set (request, "status.reason", "The requestee could not be determined."); return 0; } /* Inform task indices of new request. */ adlist = wftk_get_adaptorlist (session, TASKINDEX); wftk_call_adaptorlist (adlist, "reqnew", request); wftk_free_adaptorlist (session, adlist); if (!datasheet) return 1; /* The request was ad-hoc with no process, so there's nothing left to do. */ req = xml_create ("request"); if (datasheet) xml_setnum (req, "id", unique_id (datasheet, NULL)); xml_set (req, "of", xml_attrval (request, "of")); if (*xml_attrval (request, "by")) { requestor = wftk_user_retrieve (session, datasheet, xml_attrval (request, "by")); } else { requestor = wftk_session_getuser (session); } if (requestor) { xml_set (req, "by", xml_attrval (requestor, "id")); } if (*xml_attrval (request, "label")) { if (!datasheet) { xml_set_nodup (req, "label", wftk_value_interpreta (session, datasheet, xml_attrval (request, "label"))); } else { xml_set (req, "label", xml_attrval (request, "label")); } } else { /* TODO: default label for request depends on kind of request. */ if (requestor) { xml_setf (req, "label", "Request from %s", *xml_attrval (requestor, "name") ? xml_attrval (requestor, "name") : xml_attrval (requestor, "id")); } else { xml_set (req, "label", "Anonymous request"); } } if (*xml_attrval (request, "task") == '?') { xml_set (req, "request", xml_attrval (request, "task") + 1); } else if (*xml_attrval (request, "task")) { xml_set (req, "task", xml_attrval (request, "task")); } if (*xml_attrval (request, "role")) xml_set (req, "role", xml_attrval (request, "role")); if (*xml_attrval (request, "request")) xml_set (req, "request", xml_attrval (request, "request")); if (*xml_attrval (req, "request")) { /* TODO: some of this stuff should be done before the taskindex is updated with the request, right? */ if (xml_attrvalnum (req, "request") >= xml_attrvalnum (req, "id")) { xml_set (request, "status", "error"); xml_set (request, "status.reason", "Can't issue subrequest for nonexistent request"); return 0; } } /* Transfer the content of the request, interpreting any alert found. */ mark = xml_firstelem (request); while (mark) { if (xml_is (mark, "alert") && !alert) { alert = xml_create ("alert"); alertcontent = xml_stringcontent (mark); wftk_value_interpret (session, datasheet, alertcontent, newalertcontent, strlen (alertcontent) + 1024); xml_append (alert, xml_createtext_nodup (wftk_value_interpreta (session, datasheet, alertcontent))); free (alertcontent); xml_append (req, alert); } else { xml_append (req, xml_copy (mark)); } mark = xml_nextelem (mark); } /* If there was no custom alert, build a logical one. */ if (!alert) { alert = xml_create ("alert"); xml_append (alert, xml_createtext ("A request has been made for your action.\nPlease visit the workflow app to accept or decline.\n")); /* TODO: Boy, that is a useless alert. Write a better one. */ xml_prepend (req, alert); } xml_set (alert, "to", xml_attrval (req, "of")); xml_set (alert, "from", xml_attrval (req, "by")); xml_set (alert, "subject", xml_attrval (req, "label")); /* Do the alert -- use custom content if found above, otherwise do something logical. */ wftk_notify (session, datasheet, alert); xml_append (datasheet, req); wftk_enactment_write (session, datasheet, request, "action", "place"); wftk_process_save (session, datasheet); return 1; } |
WFTK_EXPORT XML * wftk_request_retrieve (void * session, XML * request) { XML * datasheet; WFTK_ADAPTOR * ad; XML * mark; if (!request) return 0; if (*xml_attrval (request, "process")) { datasheet = wftk_process_load (session, xml_attrval (request, "dsrep"), xml_attrval (request, "process")); } if (!datasheet) { /*ad = wftk_get_adaptor (session, TASKINDEX, NULL); wftk_call_adaptor (adlist, "reqget", xml_attrval (request, "id")); wftk_free_adaptor (session, adlist); */ /* TODO: the right thing. */ return 0; } mark = xml_firstelem (datasheet); while (mark) { if (xml_is (mark, "request") && !strcmp (xml_attrval (mark, "id"), xml_attrval (request, "id"))) { xml_copyinto (request, mark); return (request); } mark = xml_nextelem (mark); } return NULL; } WFTK_EXPORT int wftk_request_update (void * session, XML * request) { return 0; } /* TODO: figure out if this even makes sense. */ WFTK_EXPORT int wftk_request_rescind (void * session, XML * request) { XML * datasheet = NULL; XML * mark; WFTK_ADAPTORLIST * adlist; if (!request) return 0; if (*xml_attrval (request, "process")) { datasheet = wftk_process_load (session, xml_attrval (request, "dsrep"), xml_attrval (request, "process")); if (!datasheet) return 0; } /* Inform task indices of rescinded request. */ adlist = wftk_get_adaptorlist (session, TASKINDEX); wftk_call_adaptorlist (adlist, "reqdel", xml_attrval (request, "process"), xml_attrval (request, "id")); wftk_free_adaptorlist (session, adlist); if (!datasheet) return 1; /* The task was ad-hoc with no process, so there's nothing left to do. */ mark = xml_locf (datasheet, ".request[%s]", xml_attrval (request, "id")); if (mark) { xml_delete (mark); } wftk_enactment_write (session, datasheet, request, "action", "rescind"); wftk_process_save (session, datasheet); return 1; } |
WFTK_EXPORT int wftk_request_accept (void * session, XML * request) { XML * datasheet = NULL; XML * req; XML * mark; XML * task; int first = 1; WFTK_ADAPTORLIST * adlist; if (!request) return 0; if (*xml_attrval (request, "process")) { datasheet = wftk_process_load (session, xml_attrval (request, "dsrep"), xml_attrval (request, "process")); if (!datasheet) return 0; } if (datasheet) { req = xml_locf (datasheet, ".request[%s]", xml_attrval (request, "id")); if (!req) { xml_set (request, "status", "error"); xml_set (request, "status.reason", "No such request"); return 0; } if (!strcmp (xml_attrval (req, "status"), "accepted")) { xml_set (request, "status", "error"); xml_set (request, "status.reason", "Request has already been accepted."); return 0; } } /* Inform task indices of accepted request. */ adlist = wftk_get_adaptorlist (session, TASKINDEX); wftk_call_adaptorlist (adlist, "reqaccept", xml_attrval (request, "process"), xml_attrval (request, "id")); if (!datasheet) { wftk_free_adaptorlist (session, adlist); return 1; /* The task was ad-hoc with no process, so there's nothing left to do. */ } /* TODO: some of this stuff should happen before the taskindex is written. */ if (!*xml_attrval (request, "accepting")) xml_set (request, "accepting", xml_attrval (req, "of")); xml_set (req, "accepting", xml_attrval (request, "accepting")); xml_set (req, "status", "accepted"); if (*xml_attrval (req, "request")) { task = xml_locf (datasheet, ".request[%s]", xml_attrval (req, "request")); if (task) { xml_set (task, "accepting", xml_attrval (req, "accepting")); /* Not "of", because then you couldn't send subsubreqs. */ xml_set (task, "dsrep", xml_attrval (datasheet, "repository")); xml_set (task, "process", xml_attrval (datasheet, "id")); wftk_request_accept (session, task); } } if (*xml_attrval (req, "role")) { wftk_role_assign (session, datasheet, xml_attrval (req, "role"), xml_attrval (req, "accepting")); } if (*xml_attrval (req, "task")) { task = xml_locf (datasheet, ".task[%s]", xml_attrval (req, "task")); if (!task) { task = xml_locf (datasheet, ".state.queue.item[%s]", xml_attrval (req, "task")); } if (task) { xml_set (task, "user", xml_attrval (req, "accepting")); xml_set (task, "process", xml_attrval (datasheet, "id")); wftk_call_adaptorlist (adlist, "taskput", task); } } /* Now we handle the contents, if any. The first alert is the one which went to the requestee at the outset, so we skip it. */ mark = xml_firstelem (req); while (mark) { if (xml_is (mark, "alert")) { if (first) { first = 0; } else { wftk_notify (session, datasheet, mark); } } else if (xml_is (mark, "task")) { xml_set (mark, "user", xml_attrval (req, "accepting")); xml_set (mark, "dsrep", xml_attrval (datasheet, "repository")); xml_set (mark, "process", xml_attrval (datasheet, "id")); wftk_task_new (session, xml_copy (mark)); } else { wftk_process_adhoc (session, datasheet, xml_copy (mark)); } mark = xml_nextelem (mark); } wftk_enactment_write (session, datasheet, request, "action", "accepted"); /* Also saves datasheet. */ wftk_process_save (session, datasheet); wftk_free_adaptorlist (session, adlist); return 1; } WFTK_EXPORT int wftk_request_decline (void * session, XML * request) { XML * datasheet = NULL; XML * mark; WFTK_ADAPTORLIST * adlist; if (!request) return 0; if (*xml_attrval (request, "process")) { datasheet = wftk_process_load (session, xml_attrval (request, "dsrep"), xml_attrval (request, "process")); if (!datasheet) return 0; } /* Inform task indices of declined request. */ adlist = wftk_get_adaptorlist (session, TASKINDEX); wftk_call_adaptorlist (adlist, "reqdecline", xml_attrval (request, "process"), xml_attrval (request, "id")); wftk_free_adaptorlist (session, adlist); if (!datasheet) return 1; /* The task was ad-hoc with no process, so there's nothing left to do. */ mark = xml_locf (datasheet, ".request[%s]", xml_attrval (request, "id")); if (mark) { xml_set (mark, "status", "declined"); } wftk_enactment_write (session, datasheet, request, "action", "declined"); /* Also saves datasheet. */ wftk_process_save (session, datasheet); /* TODO: notify the requestor that something's amiss. */ return 1; } |
WFTK_EXPORT int wftk_request_list (void * session, XML * list) { int count = 0; const char * userid; XML * datasheet = NULL; XML * procdef = NULL; XML * mark; XML * mark2; XML * hit; WFTK_ADAPTOR * ad; if (*xml_attrval (list, "process")) { /* This is a process list. */ userid = xml_attrval (list, "user"); datasheet = wftk_process_load (session, xml_attrval (list, "dsrep"), xml_attrval (list, "process")); if (!datasheet) { return 0; } mark = xml_firstelem (datasheet); while (mark) { if (xml_is (mark, "request") && strcmp ("declined", xml_attrval (mark, "status")) && strcmp ("accepted", xml_attrval (mark, "status")) && (!*userid || !strcmp (userid, xml_attrval (mark, "of")))) { hit = xml_create ("request"); xml_set (hit, "id", xml_attrval (mark, "id")); xml_set (hit, "label", xml_attrval (mark, "label")); xml_set (hit, "of", xml_attrval (mark, "of")); xml_set (hit, "by", xml_attrval (mark, "by")); xml_set (hit, "request", xml_attrval (mark, "request")); xml_set (hit, "role", xml_attrval (mark, "role")); xml_set (hit, "task", xml_attrval (mark, "task")); xml_append (list, hit); } mark = xml_nextelem (mark); } xml_setnum (list, "count", count); /* TODO: sort the list. */ } else { /* No process means we have to ask a task index. Fortunately this is *very easy*. */ ad = wftk_get_adaptor (session, TASKINDEX, NULL); count = 0; if (ad) { wftk_call_adaptor (ad, "reqlist", list); wftk_free_adaptor (session, ad); count = xml_attrvalnum (list, "count"); } } return count; } |
This code and documentation are released under the terms of the GNU license. They are additionally copyright (c) 2000, Vivtek. All rights reserved except those explicitly granted under the terms of the GNU license. |