Overview
SHA1 Hash: | d913179b825b18633bd2dedede45c958e322f455 |
---|---|
Date: | 2007-11-24 21:28:03 |
User: | drh |
Comment: | Progress toward ticket editing. This is an incremental check-in. |
Timelines: | ancestors | descendants | both | trunk |
Other Links: | files | ZIP archive | manifest |
Tags And Properties
- branch=trunk inherited from [a28c83647d]
- sym-trunk inherited from [a28c83647d]
Changes
[hide diffs]Modified src/subscript.c from [d503240921] to [64131ef2ea].
@@ -808,15 +808,16 @@ height = SbS_StackValueInt(p, 0); zList = (char*)SbS_StackValue(p, 1, &nList); blob_init(&list, zList, nList); zName = (char*)SbS_StackValue(p, 2, &nName); zValue = SbS_Fetch(p, zName, nName, &nValue); - z = mprintf("<select name=\"%.*h\" size=\"%d\">", nName, zName, height); + z = mprintf("<select name=\"%z\" size=\"%d\">", + htmlize(zName, nName), height); sendText(z, -1); free(z); while( blob_token(&list, &elem) ){ - zH = mprintf("%.*h", blob_size(&elem), blob_buffer(&elem)); + zH = htmlize(blob_buffer(&elem), blob_size(&elem)); if( zValue && blob_size(&elem)==nValue && memcmp(zValue, blob_buffer(&elem), nValue)==0 ){ z = mprintf("<option value=\"%s\" selected>%s</option>", zH, zH); }else{ z = mprintf("<option value=\"%s\">%s</option>", zH, zH);
Modified src/tkt.c from [7e0e9ce39d] to [c07694441f].
@@ -32,11 +32,13 @@ ** The list of database user-defined fields in the TICKET table. ** 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. */ static struct Subscript *pInterp = 0; @@ -58,20 +60,23 @@ db_prepare(&q, "PRAGMA table_info(ticket)"); 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"); } } azField[nField] = mprintf("%s", zField); 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. */ @@ -85,31 +90,45 @@ /* ** 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); } @@ -309,11 +328,10 @@ 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); @@ -372,10 +390,215 @@ zScript = (char*)SbS_Fetch(pInterp, "tktnew_template", -1, &nScript); 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(); }
Modified src/tktconfig.c from [9a0ee09a71] to [dabb2f23c9].
@@ -158,11 +158,11 @@ @ Deferred @ Fixed @ Tested @ Closed @ } /status_choices set -@ {} /subsystem_choices set +@ {one two three} /subsystem_choices set @ @ ########################################################################## @ # The "tktnew_template" variable is set to text which is a template for @ # the HTML of the "New Ticket" page. Within this template, text contained @ # within [...] is subscript. That subscript runs when the page is @@ -216,11 +216,11 @@ @ For code defects, be sure to provide details on exactly how @ the problem can be reproduced. Provide as much detail as @ possible. @ <br> @ <textarea name="comment" cols="80" -@ rows="[{} /comment linecount 50 max 10 min]" +@ rows="[{} /comment get linecount 50 max 10 min html]" @ wrap="virtual" class="wikiedit">[{} /comment get html]</textarea><br> @ <input type="submit" name="preview" value="Preview"> @ </tr> @ @ [/preview exists enable_output] @@ -246,16 +246,19 @@ @ # The template for the "edit ticket" page @ { @ <!-- database field names not found as CGI parameters are loaded @ from the database automatically --> @ <!-- start a form --> -@ [{<hr><i>%USER% added on %DATE%:</i><br>} -@ /cmappnd /comment append_remark] -@ [/submit submit_ticket_change] +@ [{ +@ <hr><i>%LOGIN% added on %DATE%:</i><br> +@ } { +@ <hr><i>%LOGIN% claiming to be %USER% added on %DATE%:</i><br> +@ } /username /cmappnd /comment append_remark +@ /submit submit_ticket_change] @ <table cellpadding="5"> @ <tr><td align="right">Title:</td><td> -@ <input type="text" name="title" value="[title html] size=60"> +@ <input type="text" name="title" value="[title html]" size="60"> @ </td></tr> @ <tr><td align="right">Status:</td><td> @ [/status status_choices 1 combobox] @ </td></tr> @ <tr><td align="right">Type:</td><td> @@ -286,19 +289,20 @@ @ [/aonlybtn exists not /eall set] @ [/eallbtn exists /eall set] @ [/w hascap eall and /eall set] @ [eall enable_output] @ Description And Comments:<br> -@ <textarea name="comment" cols="80" rows="[comment linecount 15 max 10 min]" +@ <textarea name="comment" cols="80" +@ rows="[{} /comment get linecount 15 max 10 min html]" @ wrap="virtual" class="wikiedit">[comment html]</textarea><br> @ <input type="hidden" name="eall" value="1"> @ <input type="submit" name="aonlybtn" value="Append Remark"> @ [eall not enable_output] @ Append Remark:<br> @ <textarea name="cmappnd" cols="80" rows="15" -@ wrap="virtual" class="wikiedit">[cmappnd html]</textarea><br> -@ [ok_wrtkt enable_output] +@ wrap="virtual" class="wikiedit">[{} /cmappnd get html]</textarea><br> +@ [/w hascap eall not and enable_output] @ <input type="submit" name="eallbtn" value="Edit All"> @ [1 enable_output] @ </td></tr> @ <tr><td align="right"></td><td> @ <input type="submit" name="submit" value="Submit Changes">