Overview
SHA1 Hash: | a5e4e1ba961dc03d988e07400fb3c79b9cc0e2db |
---|---|
Date: | 2007-11-24 23:59:47 |
User: | drh |
Comment: | More work on ticketing. This is a non-working 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 [64131ef2ea] to [b76caa035f].
@@ -68,24 +68,25 @@ /* ** Configuration constants */ #define SBSCONFIG_NHASH 41 /* Size of the hash table */ -#define SBSCONFIG_NSTACK 10 /* Maximum stack depth */ +#define SBSCONFIG_NSTACK 20 /* Maximum stack depth */ #define SBSCONFIG_ERRSIZE 100 /* Maximum size of an error message */ /* ** Available token types: */ #define SBSTT_WHITESPACE 1 /* ex: \040 */ #define SBSTT_NAME 2 /* ex: /abcde */ #define SBSTT_VERB 3 /* ex: abcde */ #define SBSTT_STRING 4 /* ex: {...} */ -#define SBSTT_INTEGER 5 /* Integer including option sign */ -#define SBSTT_INCOMPLETE 6 /* Unterminated string token */ -#define SBSTT_UNKNOWN 7 /* Unknown token */ -#define SBSTT_EOF 8 /* End of input */ +#define SBSTT_QUOTED 5 /* ex: "...\n..." */ +#define SBSTT_INTEGER 6 /* Integer including option sign */ +#define SBSTT_INCOMPLETE 7 /* Unterminated string token */ +#define SBSTT_UNKNOWN 8 /* Unknown token */ +#define SBSTT_EOF 9 /* End of input */ /* ** Values are stored in the hash table as instances of the following ** structure. */ @@ -159,10 +160,23 @@ if( c=='#' ){ int i; for(i=1; i<n && z[i] && z[i-1]!='\n'; i++){} *pTokenType = SBSTT_WHITESPACE; return i; + } + if( c=='"' ){ + int i; + for(i=1; i<n && z[i] && z[i]!='"'; i++){ + if( z[i]=='\\' && i<n-1 ){ i++; } + } + if( z[i]=='"' ){ + *pTokenType = SBSTT_QUOTED; + return i+1; + }else{ + *pTokenType = SBSTT_INCOMPLETE; + return i; + } } if( c=='{' ){ int depth = 1; int i; for(i=1; i<n && z[i]; i++){ @@ -602,29 +616,57 @@ #define SBSOP_DIV 4 #define SBSOP_AND 5 #define SBSOP_OR 6 #define SBSOP_MIN 7 #define SBSOP_MAX 8 +#define SBSOP_EQ 9 +#define SBSOP_NE 10 +#define SBSOP_LT 11 +#define SBSOP_GT 12 +#define SBSOP_LE 13 +#define SBSOP_GE 14 /* ** Subscript command: INTEGER INTEGER <binary-op> INTEGER */ static int bopCmd(struct Subscript *p, void *pOp){ int a, b, c; if( SbS_RequireStack(p, 2, "BINARY-OP") ) return 1; - a = SbS_StackValueInt(p, 0); - b = SbS_StackValueInt(p, 1); + a = SbS_StackValueInt(p, 1); + b = SbS_StackValueInt(p, 0); switch( (int)pOp ){ + case SBSOP_EQ: c = a==b; break; + case SBSOP_NE: c = a!=b; break; + case SBSOP_LT: c = a<b; break; + case SBSOP_LE: c = a<=b; break; + case SBSOP_GT: c = a>b; break; + case SBSOP_GE: c = a>=b; break; case SBSOP_ADD: c = a+b; break; case SBSOP_SUB: c = a-b; break; case SBSOP_MUL: c = a*b; break; case SBSOP_DIV: c = b!=0 ? a/b : 0; break; case SBSOP_AND: c = a && b; break; case SBSOP_OR: c = a || b; break; case SBSOP_MIN: c = a<b ? a : b; break; case SBSOP_MAX: c = a<b ? b : a; break; } + SbS_Pop(p, 2); + SbS_PushInt(p, c); + return 0; +} + +/* +** Subscript command: STRING STRING streq INTEGER +*/ +static int streqCmd(struct Subscript *p, void *pOp){ + int c, nA, nB; + const char *A, *B; + + if( SbS_RequireStack(p, 2, "BINARY-OP") ) return 1; + A = SbS_StackValue(p, 1, &nA); + B = SbS_StackValue(p, 0, &nB); + c = nA==nB && memcmp(A,B,nA)==0; SbS_Pop(p, 2); SbS_PushInt(p, c); return 0; } @@ -657,10 +699,24 @@ for(n=1, i=0; i<size; i++){ if( z[i]=='\n' ) n++; } SbS_Pop(p, 1); SbS_PushInt(p, n); + return 0; +} + +/* +** Subscript command: STRING length INTEGER +** +** Return one more than the number characters in STRING. +*/ +static int lengthCmd(struct Subscript *p, void *pNotUsed){ + int size; + if( SbS_RequireStack(p, 1, "length") ) return 1; + SbS_StackValue(p, 0, &size); + SbS_Pop(p, 1); + SbS_PushInt(p, size); return 0; } /* ** Subscript command: NAME exists INTEGER @@ -831,10 +887,66 @@ } SbS_Pop(p, 3); return 0; } +/* +** Subscript command: STRING BOOLEAN if +** +** Evaluate STRING as a script if BOOLEAN is true. +*/ +static int ifCmd(struct Subscript *p, void *pNotUsed){ + int cond; + int rc = SBS_OK; + + if( SbS_RequireStack(p, 2, "if") ) return 1; + cond = SbS_StackValueInt(p, 0); + if( cond ){ + SbSValue script = p->aStack[p->nStack-2]; + p->aStack[p->nStack-2].flags = 0; + SbS_Pop(p, 2); + rc = SbS_Eval(p, script.u.str.z, script.u.str.size); + sbs_value_reset(&script); + }else{ + SbS_Pop(p, 2); + } + return rc; +} + +/* +** Subscript command: ... STRING COUNT concat STRING +** +** Concatenate COUNT strings into a single string and leave +** the concatenation on the stack. +*/ +static int concatCmd(struct Subscript *p, void *pNotUsed){ + int count; + int nByte; + char *z; + int i, j; + + if( SbS_RequireStack(p, 1, "concat") ) return SBS_ERROR; + count = SbS_StackValueInt(p, 0); + if( SbS_RequireStack(p, count+1, "concat") ) return SBS_ERROR; + SbS_Pop(p, 1); + nByte = 1; + for(i=p->nStack-count; i<p->nStack; i++){ + nByte += p->aStack[i].u.str.size; + } + z = malloc(nByte); + if( z==0 ){ fossil_panic("out of memory"); } + for(j=0, i=p->nStack-count; i<p->nStack; i++){ + nByte = p->aStack[i].u.str.size; + memcpy(&z[j], p->aStack[i].u.str.z, nByte); + j += nByte; + } + z[j] = 0; + SbS_Pop(p, count); + SbS_Push(p, z, j, 1); + return SBS_OK; +} + /* ** A table of built-in commands */ static const struct { @@ -843,24 +955,31 @@ void *pArg; } aBuiltin[] = { { "add", bopCmd, (void*)SBSOP_AND }, { "and", bopCmd, (void*)SBSOP_AND }, { "combobox", comboboxCmd, 0, }, + { "concat", concatCmd, 0, }, { "div", bopCmd, (void*)SBSOP_DIV }, { "enable_output", enableOutputCmd, 0 }, + { "eq", bopCmd, (void*)SBSOP_EQ }, { "exists", existsCmd, 0, }, { "get", getCmd, 0, }, { "hascap", hascapCmd, 0 }, { "html", putsCmd, (void*)1 }, + { "if", ifCmd, 0, }, + { "le", bopCmd, (void*)SBSOP_LE }, + { "length", lengthCmd, 0 }, { "linecount", linecntCmd, 0 }, + { "lt", bopCmd, (void*)SBSOP_LT }, { "max", bopCmd, (void*)SBSOP_MAX }, { "min", bopCmd, (void*)SBSOP_MIN }, { "mul", bopCmd, (void*)SBSOP_MUL }, { "not", notCmd, 0 }, { "or", bopCmd, (void*)SBSOP_OR }, { "puts", putsCmd, 0 }, { "set", setCmd, 0 }, + { "streq", streqCmd, 0 }, { "sub", bopCmd, (void*)SBSOP_SUB }, { "wiki", wikiCmd, 0, }, }; @@ -929,10 +1048,34 @@ rc = SbS_Push(p, (char*)&zScript[1], n-1, 0); break; } case SBSTT_STRING: { rc = SbS_Push(p, (char*)&zScript[1], n-2, 0); + break; + } + case SBSTT_QUOTED: { + char *z = mprintf("%.*s", n-2, &zScript[1]); + int i, j; + for(i=j=0; z[i]; i++, j++){ + int c = z[i]; + if( c=='\\' && z[i+1] ){ + c = z[++i]; + if( c=='n' ){ + c = '\n'; + }else if( c>='0' && c<='7' ){ + int k; + c -= '0'; + for(k=1; k<3 && z[i+k]>='0' && z[i+k]<='7'; k++){ + c = c*8 + z[i+k] - '0'; + } + i += k-1; + } + } + z[j] = c; + } + z[j] = 0; + rc = SbS_Push(p, z, j, 1); break; } case SBSTT_VERB: { /* First look up the verb in the hash table */ const SbSValue *pVal = sbs_fetch(&p->symTab, (char*)zScript, n);
Modified src/tkt.c from [c07694441f] to [f8ab2686b7].
@@ -50,11 +50,14 @@ return strcmp(*(char**)a, *(char**)b); } /* ** Obtain a list of all fields of the TICKET table. Put them -** in sorted order. +** in sorted order in azField[]. +** +** Also allocate space for azValue[] and azAppend[] and initialize +** all the values there to zero. */ static void getAllTicketFields(void){ Stmt q; if( nField>0 ) return; db_prepare(&q, "PRAGMA table_info(ticket)"); @@ -76,18 +79,19 @@ memset(azAppend, 0, sizeof(azAppend[0])*nField*2); azValue = &azAppend[nField]; } /* -** Return true if zField is a field within the TICKET table. -*/ -static int isTicketField(const char *zField){ +** Return the index into azField[] of the given field name. +** Return -1 if zField is not in azField[]. +*/ +static int fieldId(const char *zField){ int i; for(i=0; i<nField; i++){ - if( strcmp(azField[i], zField)==0 ) return 1; - } - return 0; + if( strcmp(azField[i], zField)==0 ) return i; + } + return -1; } /* ** Query the database for all TICKET fields for the specific ** ticket whose name is given by the "name" CGI parameter. @@ -189,14 +193,14 @@ zSep = "SET"; for(i=0; i<p->nField; i++){ const char *zName = p->aField[i].zName; if( zName[0]=='+' ){ zName++; - if( !isTicketField(zName) ) continue; + if( fieldId(zName)<0 ) continue; blob_appendf(&sql,", %s=%s || %Q", zName, zName, p->aField[i].zValue); }else{ - if( !isTicketField(zName) ) continue; + if( fieldId(zName)<0 ) continue; blob_appendf(&sql,", %s=%Q", zName, p->aField[i].zValue); } } blob_appendf(&sql, " WHERE tkt_uuid='%s' AND tkt_mtime<:mtime", p->zTicketUuid); @@ -312,11 +316,11 @@ SbS_Render(pInterp, zScript); style_footer(); } /* -** Subscript command: LABEL submit_new_ticket +** Subscript command: submit_new_ticket ** ** If the variable named LABEL exists, then submit a new ticket ** based on the values of other defined variables. */ static int submitNewCmd(struct Subscript *p, void *pNotify){ @@ -370,10 +374,108 @@ } SbS_Pop(p, 1); return SBS_OK; } + +/* +** Subscript command: STRING FIELD append_field +** +** FIELD is the name of a database column to which we might want +** to append text. STRING is the text to be appended to that +** column. The append does not actually occur until the +** submit_ticket_change verb is run. +*/ +static int appendRemarkCmd(struct Subscript *p, void *notUsed){ + int idx; + const char *zField, *zValue; + int nField, nValue; + + if( SbS_RequireStack(p, 2, "append_field") ) 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; + } + zValue = SbS_StackValue(p, 1, &nValue); + azAppend[idx] = mprintf("%.*s", nValue, zValue); + SbS_Pop(p, 2); + return SBS_OK; +} + +/* +** Subscript command: submit_ticket +** +** Construct and submit a new ticket artifact. +*/ +static int submitTicketCmd(struct Subscript *p, void *pUuid){ + char *zDate; + const char *zUuid; + int i; + int rid; + Blob tktchng, cksum; + + zUuid = (const char *)pUuid; + 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)); + } + } + } + } + if( *(char**)pUuid==0 ){ + zUuid = db_text(0, + "SELECT tkt_uuid FROM ticket WHERE tkt_uuid GLOB '%s*'", P("name") + ); + }else{ + zUuid = db_text(0, "SELECT lower(hex(randomblob(20)))"); + } + *(const char**)pUuid = zUuid; + blob_appendf(&tktchng, "K %s\n", 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; +} + + /* ** WEBPAGE: tktnew */ void tktnew_page(void){ char *zScript; @@ -387,11 +489,13 @@ getAllTicketFields(); initializeVariablesFromCGI(); @ <form method="POST" action="%s(g.zBaseURL)/tktnew"> zScript = (char*)SbS_Fetch(pInterp, "tktnew_template", -1, &nScript); zScript = mprintf("%.*s", nScript, zScript); - SbS_AddVerb(pInterp, "submit_new_ticket", submitNewCmd, (void*)&zNewUuid); + SbS_Store(pInterp, "login", g.zLogin, 0); + SbS_Store(pInterp, "date", db_text(0, "SELECT datetime('now')"), 2); + SbS_AddVerb(pInterp, "submit_ticket", submitNewCmd, (void*)&zNewUuid); if( SbS_Render(pInterp, zScript)==SBS_RETURN && zNewUuid ){ cgi_redirect(mprintf("%s/tktview/%s", g.zBaseURL, zNewUuid)); return; } @ </form> @@ -399,171 +503,19 @@ } /* -** 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. +** WEBPAGE: tktedit */ -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; + char *zUuid = 0; login_check_credentials(); if( !g.okApndTkt && !g.okWrTkt ){ login_needed(); return; } style_header("Edit Ticket"); zName = P("name"); @@ -591,14 +543,16 @@ 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)); + SbS_Store(pInterp, "login", g.zLogin, 0); + SbS_Store(pInterp, "date", db_text(0, "SELECT datetime('now')"), 2); + SbS_AddVerb(pInterp, "append_field", appendRemarkCmd, 0); + SbS_AddVerb(pInterp, "submit_ticket", submitTicketCmd, (void*)&zUuid); + if( SbS_Render(pInterp, zScript)==SBS_RETURN && zUuid ){ + cgi_redirect(mprintf("%s/tktview/%s", g.zBaseURL, zUuid)); return; } @ </form> style_footer(); }
Modified src/tktconfig.c from [dabb2f23c9] to [745ff35aaa].
@@ -169,11 +169,14 @@ @ # rendered. @ # @ { @ <!-- load database field names not found in CGI with an empty string --> @ <!-- start a form --> -@ [{Open} /status set /submit submit_new_ticket] +@ [{ +@ {Open} /status set +@ submit_new_ticket +@ } /submit exists if] @ <table cellpadding="5"> @ <tr> @ <td colspan="2"> @ Enter a one-line summary of the problem:<br> @ <input type="text" name="title" size="60" value="[{} /title get html]"> @@ -242,20 +245,34 @@ @ <!-- end of form --> @ } /tktnew_template set @ @ ########################################################################## @ # The template for the "edit ticket" page +@ # +@ # Then generated text is inserted inside a form which feeds back to itself. +@ # All CGI parameters are loaded into variables. All database files are +@ # loaded into variables if they have not previously been loaded by +@ # CGI parameters. @ { -@ <!-- database field names not found as CGI parameters are loaded -@ from the database automatically --> -@ <!-- start a form --> -@ [{ -@ <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] +@ [ +@ login /username get /username set +@ { +@ { +@ username login eq /samename set +@ "samename=" html samename html "<br>" puts +@ { +@ "\n<hr><i>" login " added on " date ":</i></br>\n" cmappnd 6 concat +@ /comment append_field +@ } samename if +@ { +@ "\n<hr><i>" login " claiming to be " username " added on " date +@ "</i><br>\n" cmappnd 8 concat /comment append_field +@ } samename not if +@ } 0 {} /cmappnd get length lt if +@ submit_ticket +@ } /submit exists if +@ ] @ <table cellpadding="5"> @ <tr><td align="right">Title:</td><td> @ <input type="text" name="title" value="[title html]" size="60"> @ </td></tr> @ <tr><td align="right">Status:</td><td> @@ -283,34 +300,40 @@ @ [1 enable_output] @ <tr><td align="right">Version Found In:</td><td> @ <input type="text" name="foundin" size="50" value="[foundin html]"> @ </td></tr> @ <tr><td colspan="2"> -@ [0 /eall 0 get /eall set] -@ [/aonlybtn exists not /eall set] -@ [/eallbtn exists /eall set] -@ [/w hascap eall and /eall set] +@ +@ [ +@ 0 /eall get /eall set # eall means "edit all". default==no +@ /aonlybtn exists not /eall set # Edit all if no aonlybtn CGI param +@ /eallbtn exists /eall set # Edit all if eallbtn CGI param +@ /w hascap eall and /eall set # WrTkt permission needed to edit all +@ ] +@ @ [eall enable_output] @ Description And Comments:<br> @ <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> +@ Append Remark from +@ <input type="text" name="username" value="[username html]" size="30">:<br> @ <textarea name="cmappnd" cols="80" rows="15" @ 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"> @ </td></tr> @ </table> -@ <!-- end-form inserted automatically --> @ } /tktedit_template set @ @ ########################################################################## @ # The template for the "view ticket" page @ {