Definition of todomgr_create

Previous: Permissions schema ] [ Top: To-do manager ] [ Next: Definition of todomgr_start ]

The /create URL is used both to present a form for task creation, and actual creation of the task. It also handles the same thing for processes.

Before we do anything else, we need to get a database handle and check the authorized user. This is pretty straightforward. Note that in AOLserver/Tcl the ns_db command connects us with the excellent DB interface. The DB interface opens and manages a pool of connections, and we simply select one (or more) when needed. When the HTTP transaction terminates, the connections are returned to the pool.
 
global todomgr_pool
set db [ns_db gethandle $todomgr_pool]
See Checking authuser
The next thing to do is to check the form input. In AOLserver/Tcl, this is done for you before your proc is ever called (contrast with the irritation of having to do it yourself in CGI. Yes, I know there are libraries.) All kinds of information is available with the ns_conn command. The form in question is query string information (preparsed) for GETs, and content body information (also preparsed) for POSTs. It's returned as an ns_set datastructure which does pretty much what Perl hashes do.

If the form is blank, we know we're not actually creating anything, so we present the creation form.
 
set form [ns_conn form $conn]
if {$form == ""} {
  See Show process/task creation form
  return
}
If the form isn't blank, then we have to create either a process or a task. Which? (If neither, let's return a nasty error message for the script kiddy trying to crack into the system.)
 
if {[ns_set get $form what] == "task"} {
  if ![string compare [ns_set get $form description] ""] {
    See Requesting a task for a process
  } else {
    See Create task
  }
} elseif {[ns_set get $form what] == "process"} {
  if ![string compare [ns_set get $form title] ""] {
    See Requesting a new process
  } else {
    See Create process
  }
} else {
  set tags(title) "Invalid create request"
  set tags(body) "
To create a task, use <code>what=task</code>; for a process use <code>what=process</code>.
You entered <code>what=[ns_set get $form what]</code>."

  todomgr_pageout $conn message.html
}

And that's it. Oh. Still haven't covered any details.

Show process/task creation form
The display of a form is pretty straightforward. AOLserver/Tcl provides the ns_return function (among a couple of others) to perform this task. While we can obviously use a string and embed all the HTML right in the code here, I don't like that style. I nearly always use a template HTML file which I can then modify appropriately with code. Using that mechanism here means essentially copying the HTML file and writing it out, so this begs the question of why we put it into this code in the first place instead of simply directing the user to the HTML page directly. Simple: we want a list of existing projects to show up in the task creation form, and that happens in this code and is made ready in the tag [##projectlist##].

This all makes use of the function todomgr_pageout, which will be defined later. (If I were using a more mature literate programming tool, a link could automagically be inserted. Unfortunately that's not the case.) The query I'm using to grab processes is overly simplistic. I'm not using user information yet. I'll revisit this piece later so that the system will be multiuser.
 
set row [ns_db select $db "select * from process"]
set tags(processlist) "<option value=\"\">Select a process if applicable\n"
while {[ns_db getrow $db $row]} {
   append tags(processlist) "<option value=\"[ns_set get $row id]\">[ns_set get $row title]\n"
}
todomgr_pageout $conn fresh_task.html



Requesting a task for a process
If we know the process we're attaching a task to, then we have another form to use. We have to get some information about the project (basically its title) and we provide a list of users to make the request of. (The current user is the default.) We also need to check the user's permission level to make sure he/she may add tasks to the process.

First, if no process is involved (i.e. this is a standalone task) then we'll just present the form and go on.
 
set process [ns_set get $form process]
if ![string compare "" $process] {
   return [todomgr_pageout $conn newtasknoproc.html]
} 
Now let's get info about the process and make sure it exists.
 
set tags(process) $process
set prow [ns_db select $db "select * from process where id='[sql_safe_string $process]'"]
if ![ns_db getrow $db $prow] {
   set tags(title) "Can't create task for nonexistent process"
   set tags(body) "The process code you entered ($process) can't be found in the database."
   return [todomgr_pageout $conn message.html]
}
set tags(title) [ns_set get $prow title]
Next, let's check the user's permission level and ensure that it's sufficient. Since the permission may come through any keyword, we have to check all the keywords for the process.
 
if [string compare $user [ns_set get $prow owner]] {
   set perm 0
   set row [ns_db select $db "select * from keyword, permission where keyword.process='[sql_safe_string $process]' and keyword.keyword=permission.keyword and permission.userid='[sql_safe_string $user]'"]
   while {[ns_db getrow $db $row]} {
      if [string match *t* [ns_set get $row flags]] { set perm 1 }
   }
   if !$perm {
      set tags(body) "You don't have sufficient privileges to request tasks for <i>$tags(title)</i>"
      set tags(title) "Insufficent privilege"
      return [todomgr_pageout $conn message.html]
   }
}
OK, let's build our list of users of which we can make requests, and put up the form.
 
set    query "select * from keyword, permission, users "
append query   "where keyword.process='[sql_safe_string $process]' "
append query     "and keyword.keyword=permission.keyword and permission.userid=users.userid "
append query     "and users.permlevel > 1"
append query " order by name"

set row [ns_db select $db $query]
set tags(userlist) "<option value=\"$user\">Select a requestee here\n"
while {[ns_db getrow $db $row]} {
   append tags(userlist) "<option value=\"[ns_set get $row userid]\">"
   append tags(userlist) "[ns_set get $row name] ([ns_set get $row userid])\n"
}
 
todomgr_pageout $conn newtask.html


Create task
Once we've presented the form and the user has filled it in, we come to the task creation routine. The first thing is to build a task ID. We want to make sure it's unique; in AOLserver/Tcl a useful way of doing that is to use the connection handle (which is a string, this is Tcl after all) and the current time. The now function is one I use a lot; its definition is in the utility section.
 
set task $conn[now tag]
Next, we build our SQL statement to create the task requested and execute that statement.
 
set fields [list id status created]
set values [list '$task' 'active' '[now]']
foreach field {process description priority sched_date sched_time} {
   if {[ns_set find $form $field] == -1} { continue }
   if {[ns_set get $form $field] == ""} { continue }

   lappend fields $field
   if {$field == "priority"} {
      lappend values [ns_set get $form $field]
   } else {
      lappend values "'[sql_safe_string [ns_set get $form $field]]'"
   }
}

if {[lsearch $fields owner] == -1} {
   lappend fields owner
   lappend values "'[sql_safe_string $user]'"
}

set query "insert into task ("
append query [join $fields ", "]
append query ") values ("
append query [join $values ", "]
append query ")"

ns_db dml $db $query

ns_returnredirect $conn show?task=$task
And that's it. Our task is created. Notice that instead of doing any display here, I'm just returning a redirect so that all task display is concentrated into one area.

Requesting a new process
This is no more than presenting the form.
 
return [todomgr_pageout $conn newprocess.html]


Create process
Creating a process is almost identical to creation of a task. The fields are different, that's all. And since we have no numeric fields in the process record, we don't need that special logic to avoid putting quotes around the priority field that we needed in the task record.
 
set process $conn[now tag]
set fields [list id status started]
set values [list '$process' 'pending' '[now]']
foreach field {title description} {
   if {[ns_set find $form $field] == -1} { continue }
   if {[ns_set get $form $field] == ""} { continue }

   lappend fields $field
   lappend values "'[sql_safe_string [ns_set get $form $field]]'"
}

if {[lsearch $fields owner] == -1} {
   lappend fields owner
   lappend values "'[sql_safe_string $user]'"
}

set query "insert into process ("
append query [join $fields ", "]
append query ") values ("
append query [join $values ", "]
append query ")"

ns_db dml $db $query

ns_returnredirect $conn show?process=$process

Previous: Permissions schema ] [ Top: To-do manager ] [ Next: Definition of todomgr_start ]


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.