Diff
Not logged in

Differences From:

File src/tkt.c part of check-in [fb358ca492] - Progress toward getting ticketing working. We can enter a new ticket and display it. Cannot yet edit a ticket. by drh on 2007-11-24 19:33:46. [view]

To:

File src/tkt.c part of check-in [d913179b82] - Progress toward ticket editing. This is an incremental check-in. by drh on 2007-11-24 21:28:03. [view]

@@ -33,9 +33,11 @@
 ** The real table also contains some addition fields for internal
 ** used.  The internal-use fields begin with "tkt_".
 */
 static int nField = 0;
-static char **azField = 0;
+static char **azField = 0;    /* Names of database fields */
+static char **azValue = 0;    /* Original values */
+static char **azAppend = 0;   /* Value to be appended */
 
 /*
 ** A subscript interpreter used for processing Tickets.
 */
@@ -59,9 +61,9 @@
   while( db_step(&q)==SQLITE_ROW ){
     const char *zField = db_column_text(&q, 1);
     if( strncmp(zField,"tkt_",4)==0 ) continue;
     if( nField%10==0 ){
-      azField = realloc(azField, sizeof(azField)*(nField+10) );
+      azField = realloc(azField, sizeof(azField)*3*(nField+10) );
       if( azField==0 ){
         fossil_fatal("out of memory");
       }
     }
@@ -69,8 +71,11 @@
     nField++;
   }
   db_finalize(&q);
   qsort(azField, nField, sizeof(azField[0]), nameCmpr);
+  azAppend = &azField[nField];
+  memset(azAppend, 0, sizeof(azAppend[0])*nField*2);
+  azValue = &azAppend[nField];
 }
 
 /*
 ** Return true if zField is a field within the TICKET table.
@@ -86,29 +91,43 @@
 /*
 ** Query the database for all TICKET fields for the specific
 ** ticket whose name is given by the "name" CGI parameter.
 ** Load the values for all fields into the interpreter.
+**
+** Only load those fields which do not already exist as
+** variables.
 */
 static void initializeVariablesFromDb(void){
   const char *zName;
   Stmt q;
-  int i, n;
+  int i, n, size, j;
 
   zName = PD("name","");
   db_prepare(&q, "SELECT * FROM ticket WHERE tkt_uuid GLOB '%q*'", zName);
   if( db_step(&q)==SQLITE_ROW ){
     n = db_column_count(&q);
     for(i=0; i<n; i++){
       const char *zVal = db_column_text(&q, i);
+      const char *zName = db_column_name(&q, i);
       if( zVal==0 ) zVal = "";
-      SbS_Store(pInterp, db_column_name(&q,i), zVal, 1);
+      for(j=0; j<nField; j++){
+        if( strcmp(azField[j],zName)==0 ){
+          azValue[j] = mprintf("%s", zVal);
+          break;
+        }
+      }
+      if( SbS_Fetch(pInterp, zName, -1, &size)==0 ){
+        SbS_Store(pInterp, db_column_name(&q,i), zVal, 1);
+      }
     }
   }else{
     db_finalize(&q);
     db_prepare(&q, "PRAGMA table_info(ticket)");
     while( db_step(&q)==SQLITE_ROW ){
       const char *zField = db_column_text(&q, 1);
-      SbS_Store(pInterp, zField, "", 0);
+      if( SbS_Fetch(pInterp, zField, -1, &size)==0 ){
+        SbS_Store(pInterp, zField, "", 0);
+      }
     }
   }
   db_finalize(&q);
 }
@@ -310,9 +329,8 @@
     int i;
     int rid;
     Blob tktchng, cksum;
 
-    (*(int*)pNotify) = 1;
     blob_zero(&tktchng);
     zDate = db_text(0, "SELECT datetime('now')");
     zDate[10] = 'T';
     blob_appendf(&tktchng, "D %s\n", zDate);
@@ -373,9 +391,214 @@
   zScript = mprintf("%.*s", nScript, zScript);
   SbS_AddVerb(pInterp, "submit_new_ticket", submitNewCmd, (void*)&zNewUuid);
   if( SbS_Render(pInterp, zScript)==SBS_RETURN && zNewUuid ){
     cgi_redirect(mprintf("%s/tktview/%s", g.zBaseURL, zNewUuid));
+    return;
+  }
+  @ </form>
+  style_footer();
+}
+
+
+
+/*
+** Subscript command:   STR1 STR2 USERVAR APPENDVAR FIELD append_remark
+**
+** FIELD is the name of a database column to which we might want
+** to append text.  APPENDVAR is the name of a CGI parameter which
+** (if it exists) contains the text to be appended.  The append
+** operation will only happen if APPENDVAR exists.  USERVAR is
+** a CGI parameter which contains the name that the user wants to
+** to be known by.  STR1 and STR2 are prefixes that are prepended
+** to the text in the APPENDVAR CGI parameter.  STR1 is used if
+** USERVAR is the same as g.zLogin or if USERVAR does not exist.
+** STR2 is used if USERVAR exists and is different than g.zLogin.
+** Within STR1 and STR2, the following substitutions occur:
+**
+**     %LOGIN%    The value of g.zLogin
+**     %USER%     The value of the USERVAR CGI parameter
+**     %DATE%     The current date and time
+**
+** The concatenation STR1 or STR2 with the content of APPENDVAR
+** is written into azApnd[] in the FIELD slot so that it will be
+** picked up and used by the submit_ticket_change command.
+*/
+static int appendRemarkCmd(struct Subscript *p, void *notUsed){
+  int i, j, idx;
+  const char *zField, *zAppendVar, *zUserVar, *zStr, *zValue, *zUser;
+  int nField, nAppendVar, nUserVar, nStr, nValue, nUser;
+
+  if( SbS_RequireStack(p, 5, "append_remark") ) return 1;
+  zField = SbS_StackValue(p, 0, &nField);
+  for(idx=0; idx<nField; idx++){
+    if( strncmp(azField[idx], zField, nField)==0 && azField[idx][nField]==0 ){
+      break;
+    }
+  }
+  if( idx>=nField ){
+    SbS_SetErrorMessage(p, "no such TICKET column: %.*s", nField, zField);
+    return SBS_ERROR;
+  }
+  zAppendVar = SbS_StackValue(p, 1, &nAppendVar);
+  zValue = SbS_Fetch(p, zAppendVar, nAppendVar, &nValue);
+  if( zValue ){
+    Blob out;
+    blob_zero(&out);
+    zUserVar = SbS_StackValue(p, 2, &nUserVar);
+    zUser = SbS_Fetch(p, zUserVar, nUserVar, &nUser);
+    if( zUser && (strncmp(zUser, g.zLogin, nUser) || g.zLogin[nUser]!=0) ){
+      zStr = SbS_StackValue(p, 3, &nStr);
+    }else{
+      zStr = SbS_StackValue(p, 4, &nStr);
+    }
+    for(i=j=0; i<nStr; i++){
+      if( zStr[i]!='%' ) continue;
+      if( i>j ){
+        blob_append(&out, &zStr[j], i-j);
+        j = i;
+      }
+      if( strncmp(&zStr[j], "%USER%", 6)==0 ){
+        blob_appendf(&out, "%z", htmlize(zUser, nUser));
+        i += 5;
+        j = i+1;
+      }else if( strncmp(&zStr[j], "%LOGIN%", 7)==0 ){
+        blob_appendf(&out, "%z", htmlize(g.zLogin, -1));
+        i += 6;
+        j = i+1;
+      }else if( strncmp(&zStr[j], "%DATE%", 6)==0 ){
+        blob_appendf(&out, "%z", db_text(0, "SELECT datetime('now')"));
+        i += 5;
+        j = i+1;
+      }
+    }
+    if( i>j ){
+      blob_append(&out, &zStr[j], i-j);
+    }
+    blob_append(&out, zValue, nValue);
+    azAppend[idx] = blob_str(&out);
+  }
+  SbS_Pop(p, 5);
+  return SBS_OK;
+}
+
+/*
+** Subscript command:   LABEL submit_ticket_change
+**
+** If the variable named LABEL exists, then submit a change to
+** the ticket identified by the "name" CGI parameter.
+*/
+static int submitEditCmd(struct Subscript *p, void *pNotify){
+  const char *zLabel;
+  int nLabel, size;
+
+  if( SbS_RequireStack(p, 1, "submit_ticket_change") ) return 1;
+  zLabel = SbS_StackValue(p, 0, &nLabel);
+  if( SbS_Fetch(p, zLabel, nLabel, &size)!=0 ){
+    char *zDate, *zUuid;
+    int i;
+    int rid;
+    Blob tktchng, cksum;
+
+    (*(int*)pNotify) = 1;
+    blob_zero(&tktchng);
+    zDate = db_text(0, "SELECT datetime('now')");
+    zDate[10] = 'T';
+    blob_appendf(&tktchng, "D %s\n", zDate);
+    free(zDate);
+    for(i=0; i<nField; i++){
+      const char *zValue;
+      int nValue;
+      if( azAppend[i] ){
+        blob_appendf(&tktchng, "J +%s %z\n", azField[i],
+                     fossilize(azAppend[i], -1));
+      }else{
+        zValue = SbS_Fetch(p, azField[i], -1, &nValue);
+        if( zValue ){
+          while( nValue>0 && isspace(zValue[nValue-1]) ){ nValue--; }
+          if( strncmp(zValue, azValue[i], nValue)
+                  || strlen(azValue[i])!=nValue ){
+            blob_appendf(&tktchng, "J %s %z\n",
+               azField[i], fossilize(zValue,nValue));
+          }
+        }
+      }
+    }
+    zUuid = db_text(0,
+       "SELECT tkt_uuid FROM ticket WHERE tkt_uuid GLOB '%s*'",
+       P("name")
+    );
+    blob_appendf(&tktchng, "K %s\n", zUuid);
+    (*(char**)pNotify) = zUuid;
+    blob_appendf(&tktchng, "U %F\n", g.zLogin ? g.zLogin : "");
+    md5sum_blob(&tktchng, &cksum);
+    blob_appendf(&tktchng, "Z %b\n", &cksum);
+
+#if 1
+    @ <hr><pre>
+    @ %h(blob_str(&tktchng))
+    @ </pre><hr>
+    blob_zero(&tktchng);
+    SbS_Pop(p, 1);
+    return SBS_OK;
+#endif
+
+    rid = content_put(&tktchng, 0, 0);
+    if( rid==0 ){
+      fossil_panic("trouble committing ticket: %s", g.zErrMsg);
+    }
+    manifest_crosslink(rid, &tktchng);
+    return SBS_RETURN;
+  }
+  SbS_Pop(p, 1);
+  return SBS_OK;
+}
+
+/*
+** WEBPAGE: tktedit
+*/
+void tktedit_page(void){
+  char *zScript;
+  int nScript;
+  int chnged = 0;
+  int nName;
+  const char *zName;
+  int nRec;
+
+  login_check_credentials();
+  if( !g.okApndTkt && !g.okWrTkt ){ login_needed(); return; }
+  style_header("Edit Ticket");
+  zName = P("name");
+  if( zName==0 || (nName = strlen(zName))<4 || nName>UUID_SIZE
+          || !validate16(zName,nName) ){
+    @ <font color="red"><b>Not a valid ticket id: \"%h(zName)\"</b></font>
+    style_footer();
+    return;
+  }
+  nRec = db_int(0, "SELECT count(*) FROM ticket WHERE tkt_uuid GLOB '%q*'",
+                zName);
+  if( nRec==0 ){
+    @ <font color="red"><b>No such ticket: \"%h(zName)\"</b></font>
+    style_footer();
+    return;
+  }
+  if( nRec>1 ){
+    @ <font color="red"><b>%d(nRec) tickets begin with: \"%h(zName)\"</b></font>
+    style_footer();
+    return;
+  }
+  ticket_init();
+  getAllTicketFields();
+  initializeVariablesFromCGI();
+  initializeVariablesFromDb();
+  @ <form method="POST" action="%s(g.zBaseURL)/tktedit">
+  @ <input type="hidden" name="name" value="%s(zName)">
+  zScript = (char*)SbS_Fetch(pInterp, "tktedit_template", -1, &nScript);
+  zScript = mprintf("%.*s", nScript, zScript);
+  SbS_AddVerb(pInterp, "append_remark", appendRemarkCmd, 0);
+  SbS_AddVerb(pInterp, "submit_ticket_change", submitEditCmd, (void*)&chnged);
+  if( SbS_Render(pInterp, zScript)==SBS_RETURN && chnged ){
+    cgi_redirect(mprintf("%s/tktview/%s", g.zBaseURL, zName));
     return;
   }
   @ </form>
   style_footer();
 }