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 (XML * 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", wftk_value_counter (session, datasheet, "idcount"));
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_pretty (alert, xml_createtext_nodup (wftk_value_interpreta (session, datasheet, alertcontent)));
free (alertcontent);
xml_append_pretty (req, alert);
} else {
xml_append_pretty (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_pretty (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_pretty (datasheet, req);
wftk_enactment_write (session, datasheet, request, "action", "place");
wftk_process_save (session, datasheet);
return 1;
}
|
WFTK_EXPORT XML * wftk_request_retrieve (XML * 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 (XML * session, XML * request) { return 0; } /* TODO: figure out if this even makes sense. */
WFTK_EXPORT int wftk_request_rescind (XML * 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 (XML * 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 (XML * 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 (XML * 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 copyright (c) 2000-2004, Vivtek. All rights reserved except those explicitly granted under the terms of the GNU license. |