Check-in [5f3ddcc1b8]
Not logged in
Overview

SHA1 Hash:5f3ddcc1b80bc8e20a09be8ff131522caa5d9359
Date: 2007-11-25 21:11:33
User: drh
Comment:Add ticket configuration editing capability.
Timelines: ancestors | descendants | both | trunk
Other Links: files | ZIP archive | manifest

Tags And Properties
Changes
[hide diffs]

Modified src/setup.c from [9f3fedc058] to [ecaf658269].

@@ -38,18 +38,17 @@
 void setup_menu_entry(
   const char *zTitle,
   const char *zLink,
   const char *zDesc
 ){
-  @ <dt>
+  @ <tr><td valign="top" align="right">
   if( zLink && zLink[0] ){
     @ <a href="%s(zLink)">%h(zTitle)</a>
   }else{
     @ %h(zTitle)
   }
-  @ </dt>
-  @ <dd>%h(zDesc)</dd>
+  @ </td><td valign="top">%h(zDesc)</td></tr>
 }
 
 /*
 ** WEBPAGE: /setup
 */
@@ -58,26 +57,26 @@
   if( !g.okSetup ){
     login_needed();
   }
 
   style_header("Setup");
-  @ <dl id="setup">
+  @ <table border="0" cellspacing="20">
   setup_menu_entry("Users", "setup_ulist",
     "Grant privileges to individual users.");
   setup_menu_entry("Access", "setup_access",
     "Control access settings.");
   setup_menu_entry("Configuration", "setup_config",
     "Configure the WWW components of the repository");
-  setup_menu_entry("Tickets", "tktsetup",
+  setup_menu_entry("Tickets", "setup_ticket",
     "Configure the trouble-ticketing system for this repository");
   setup_menu_entry("CSS", "setup_editcss",
     "Edit the Cascading Style Sheet used by all pages of this repository");
   setup_menu_entry("Header", "setup_header",
     "Edit HTML text inserted at the top of every page");
   setup_menu_entry("Footer", "setup_footer",
     "Edit HTML text inserted at the bottom of every page");
-  @ </dl>
+  @ </table>
 
   style_footer();
 }
 
 /*
@@ -651,8 +650,59 @@
   @ </form>
   @ <hr>
   @ Here is the default page footer:
   @ <blockquote><pre>
   @ %h(zDefaultFooter)
+  @ </pre></blockquote>
+  db_end_transaction(0);
+}
+
+/*
+** WEBPAGE: setup_ticket
+*/
+void setup_ticket(void){
+  const char *zConfig;
+  int isSubmit;
+
+  login_check_credentials();
+  if( !g.okSetup ){
+    login_needed();
+  }
+  isSubmit = P("submit")!=0;
+  db_begin_transaction();
+  zConfig = P("cfg");
+  if( zConfig==0 ){
+    zConfig = db_text((char*)zDefaultTicketConfig,
+               "SELECT value FROM config WHERE name='ticket-configuration'");
+  }
+  style_header("Edit Ticket Configuration");
+  if( P("clear")!=0 ){
+    db_multi_exec("DELETE FROM config WHERE name='ticket-configuration'");
+    zConfig = zDefaultTicketConfig;
+  }else if( isSubmit ){
+    char *zErr = ticket_config_check(zConfig);
+    if( zErr==0 ){
+      db_multi_exec(
+         "REPLACE INTO config(name,value) VALUES('ticket-configuration',"
+         "%Q)", zConfig
+      );
+    }else{
+      @ <p><font color="red"><b>
+      @ SCRIPT ERROR: %h(zErr)
+      @ </b></font></p>
+    }
+  }
+  @ <form action="%s(g.zBaseURL)/setup_ticket" method="POST">
+  @ <p>Edit the "subscript" script that defines the ticketing
+  @ system setup for this server.</p>
+  @ <textarea name="cfg" rows="40" cols="80">%h(zConfig)</textarea>
+  @ <br />
+  @ <input type="submit" name="submit" value="Apply Changes">
+  @ <input type="submit" name="clear" value="Revert To Default">
+  @ </form>
+  @ <hr>
+  @ Here is the default page header:
+  @ <blockquote><pre>
+  @ %h(zDefaultTicketConfig)
   @ </pre></blockquote>
   db_end_transaction(0);
 }

Modified src/style.c from [ee998320c7] to [59e6a72711].

@@ -46,16 +46,20 @@
 ** Add a new element to the submenu
 */
 void style_submenu_element(
   const char *zLabel,
   const char *zTitle,
-  const char *zLink
+  const char *zLink,
+  ...
 ){
+  va_list ap;
   assert( nSubmenu < sizeof(aSubmenu)/sizeof(aSubmenu[0]) );
   aSubmenu[nSubmenu].zLabel = zLabel;
   aSubmenu[nSubmenu].zTitle = zTitle;
-  aSubmenu[nSubmenu].zLink = zLink;
+  va_start(ap, zLink);
+  aSubmenu[nSubmenu].zLink = vmprintf(zLink, ap);
+  va_end(ap);
   nSubmenu++;
 }
 
 /*
 ** Compare two submenu items for sorting purposes

Modified src/tkt.c from [73fae28608] to [1c6be6341e].

@@ -304,16 +304,22 @@
   db_end_transaction(0);
 }
 
 /*
 ** WEBPAGE: tktview
+**
+** View a ticket.
 */
 void tktview_page(void){
   char *zScript;
   int nScript;
   login_check_credentials();
   if( !g.okRdTkt ){ login_needed(); return; }
+  if( g.okWrTkt ){
+    style_submenu_element("Edit", "Edit The Ticket", "%s/tktedit?name=%T",
+        g.zTop, PD("name",""));
+  }
   style_header("View Ticket");
   ticket_init();
   initializeVariablesFromDb();
   zScript = (char*)SbS_Fetch(pInterp, "tktview_template", -1, &nScript);
   zScript = mprintf("%.*s", nScript, zScript);
@@ -421,10 +427,18 @@
 
 
 /*
 ** WEBPAGE: tktnew
 ** WEBPAGE: debug_tktnew
+**
+** Enter a new ticket.  the tktnew_template script in the ticket
+** configuration is used.  The /tktnew page is the official ticket
+** entry page.  The /debug_tktnew page is used for debugging the
+** tktnew_template in the ticket configuration.  /debug_tktnew works
+** just like /tktnew except that it does not really save the new ticket
+** when you press submit - it just prints the ticket artifact at the
+** top of the screen.
 */
 void tktnew_page(void){
   char *zScript;
   int nScript;
   char *zNewUuid = 0;
@@ -447,15 +461,20 @@
   }
   @ </form>
   style_footer();
 }
 
-
-
 /*
 ** WEBPAGE: tktedit
 ** WEBPAGE: debug_tktedit
+**
+** Edit a ticket.  The ticket is identified by the name CGI parameter.
+** /tktedit is the official page.  The /debug_tktedit page does the same
+** thing except that it does not save the ticket change record when you
+** press submit - it instead prints the ticket change record at the top
+** of the page.  The /debug_tktedit page is intended to be used when
+** debugging ticket configurations.
 */
 void tktedit_page(void){
   char *zScript;
   int nScript;
   int nName;
@@ -500,6 +519,63 @@
     cgi_redirect(mprintf("%s/tktview/%s", g.zBaseURL, zName));
     return;
   }
   @ </form>
   style_footer();
+}
+
+/*
+** Check the ticket configuration in zConfig to see if it appears to
+** be well-formed.  If everything is OK, return NULL.  If something is
+** amiss, then return a pointer to a string (obtained from malloc) that
+** describes the problem.
+*/
+char *ticket_config_check(const char *zConfig){
+  struct Subscript *p;
+  char *zErr = 0;
+  const char *z;
+  int n;
+  int i;
+  int rc;
+  sqlite3 *db;
+  static const char *azRequired[] = {
+     "tktnew_template",
+     "tktview_template",
+     "tktedit_template",
+  };
+
+  p = SbS_Create();
+  rc = SbS_Eval(p, zConfig, strlen(zConfig));
+  if( rc!=SBS_OK ){
+    zErr = mprintf("%s", SbS_GetErrorMessage(p));
+    SbS_Destroy(p);
+    return zErr;
+  }
+  for(i=0; i<sizeof(azRequired)/sizeof(azRequired[0]); i++){
+    z = SbS_Fetch(p, azRequired[i], -1, &n);
+    if( z==0 ){
+      zErr = mprintf("missing definition: %s", azRequired[i]);
+      SbS_Destroy(p);
+      return zErr;
+    }
+  }
+  z = SbS_Fetch(p, "ticket_sql", -1, &n);
+  if( z==0 ){
+    zErr = mprintf("missing definition: ticket_sql");
+    SbS_Destroy(p);
+    return zErr;
+  }
+  rc = sqlite3_open(":memory:", &db);
+  if( rc==SQLITE_OK ){
+    char *zSql = mprintf("%.*s", n, z);
+    rc = sqlite3_exec(db, zSql, 0, 0, &zErr);
+    if( rc!=SQLITE_OK ){
+      sqlite3_close(db);
+      SbS_Destroy(p);
+      return zErr;
+    }
+    /* TODO: verify that the TICKET table exists and has required fields */
+    sqlite3_close(db);
+  }
+  SbS_Destroy(p);
+  return 0;
 }

Modified src/tktconfig.c from [64970a9836] to [c567cf64e8].

@@ -85,26 +85,19 @@
 ** This configuration file just sets the values of various variables.
 ** Some of the variables have special meanings.  The content of some
 ** of the variables are additional subscript scripts.
 */
 
-/* @-comment: # */
+/* @-comment: ** */
 const char zDefaultTicketConfig[] =
-@ ##########################################################################
-@ #
-@ # Every ticket configuration file should have a title.  When you
-@ # come up with a new ticket configuration, please change the title
-@ # to something descriptive.
-@ #
-@ {Default Ticket Configuration} /ticket_config_title set
-@
 @ ############################################################################
-@ # Every ticket configuration *must* define a set of columns for the
-@ # "ticket" table of the database.  These column names will also be
-@ # used as CGI parameter names, so to avoid problems it is best that
-@ # the names be all lower-case alphabetic characters.  The names must
-@ # be unique and must not begin with "tkt_".
+@ # Every ticket configuration *must* define an SQL statement that creates
+@ # the TICKET table.  This table must have three columns named
+@ # tkt_id, tkt_uuid, and tkt_mtime.  tkt_id must be the integer primary
+@ # key and tkt_uuid and tkt_mtime must be unique.  A configuration should
+@ # define addition columns as necessary.  All columns should be in all
+@ # lower-case letters and should not begin with "tkt".
 @ #
 @ {
 @    CREATE TABLE ticket(
 @      -- Do not change any column that begins with tkt_
 @      tkt_id INTEGER PRIMARY KEY,

Modified src/wiki.c from [06781e499d] to [9e63012182].

@@ -161,20 +161,20 @@
         zBody = m.zWiki;
       }
     }
   }
   if( isSandbox || (rid && g.okWrWiki) || (!rid && g.okNewWiki) ){
-    style_submenu_element("Edit", "Edit Wiki Page",
-       mprintf("%s/wikiedit?name=%T", g.zTop, zPageName));
+    style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T",
+         g.zTop, zPageName);
   }
   if( isSandbox || (rid && g.okApndWiki) ){
-    style_submenu_element("Append", "Add A Comment",
-       mprintf("%s/wikiappend?name=%T", g.zTop, zPageName));
+    style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T",
+         g.zTop, zPageName);
   }
   if( !isSandbox && g.okHistory ){
-    style_submenu_element("History", "History",
-         mprintf("%s/whistory?name=%T", g.zTop, zPageName));
+    style_submenu_element("History", "History", "%s/whistory?name=%T",
+         g.zTop, zPageName);
   }
   zHtmlPageName = mprintf("%h", zPageName);
   style_header(zHtmlPageName);
   blob_init(&wiki, zBody, -1);
   wiki_convert(&wiki, 0, 0);