Index: src/tkt.c ================================================================== --- src/tkt.c +++ src/tkt.c @@ -30,22 +30,27 @@ static int nField = 0; static struct tktFieldInfo { char *zName; /* Name of the database field */ char *zValue; /* Value to store */ char *zAppend; /* Value to append */ + char *zBsln; /* "baseline for $zName" if that field exists*/ unsigned mUsed; /* 01: TICKET 02: TICKETCHNG */ } *aField; #define USEDBY_TICKET 01 #define USEDBY_TICKETCHNG 02 #define USEDBY_BOTH 03 +#define JCARD_ASSIGN ('=') +#define JCARD_APPEND ('+') +#define JCARD_PRIVATE ('p') static u8 haveTicket = 0; /* True if the TICKET table exists */ static u8 haveTicketCTime = 0; /* True if TICKET.TKT_CTIME exists */ static u8 haveTicketChng = 0; /* True if the TICKETCHNG table exists */ static u8 haveTicketChngRid = 0; /* True if TICKETCHNG.TKT_RID exists */ static u8 haveTicketChngUser = 0;/* True if TICKETCHNG.TKT_USER exists */ static u8 useTicketGenMt = 0; /* use generated TICKET.MIMETYPE */ static u8 useTicketChngGenMt = 0;/* use generated TICKETCHNG.MIMETYPE */ +static int nTicketBslns = 0; /* number of valid "baseline for ..." */ /* ** Compare two entries in aField[] for sorting purposes */ @@ -73,31 +78,56 @@ ** The haveTicket and haveTicketChng variables are set to 1 if the TICKET and ** TICKETCHANGE tables exist, respectively. */ static void getAllTicketFields(void){ Stmt q; - int i, noRegularMimetype; + int i, noRegularMimetype, nBaselines; static int once = 0; if( once ) return; once = 1; + nBaselines = 0; db_prepare(&q, "PRAGMA table_info(ticket)"); while( db_step(&q)==SQLITE_ROW ){ const char *zFieldName = db_column_text(&q, 1); haveTicket = 1; if( memcmp(zFieldName,"tkt_",4)==0 ){ if( strcmp(zFieldName, "tkt_ctime")==0 ) haveTicketCTime = 1; continue; + } + if( memcmp(zFieldName,"baseline for ",13)==0 ){ + if( strcmp(db_column_text(&q,2),"INTEGER")==0 ){ + nBaselines++; + } + continue; } if( strchr(zFieldName,' ')!=0 ) continue; if( nField%10==0 ){ aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) ); } + aField[nField].zBsln = 0; aField[nField].zName = mprintf("%s", zFieldName); aField[nField].mUsed = USEDBY_TICKET; nField++; } db_finalize(&q); + if( nBaselines ){ + db_prepare(&q, "SELECT 1 FROM pragma_table_info('ticket') " + "WHERE type = 'INTEGER' AND name = :n"); + for(i=0; inField; i++){ const char * const zName = p->aField[i].zName; const char * const zBaseName = zName[0]=='+' ? zName+1 : zName; j = fieldId(zBaseName); if( j<0 ) continue; @@ -244,12 +274,16 @@ aUsed[j] = 1; if( aField[j].mUsed & USEDBY_TICKET ){ if( zName[0]=='+' ){ blob_append_sql(&sql1,", \"%w\"=coalesce(\"%w\",'') || %Q", zBaseName, zBaseName, p->aField[i].zValue); + /* when appending keep "baseline for ..." unchanged */ }else{ blob_append_sql(&sql1,", \"%w\"=%Q", zBaseName, p->aField[i].zValue); + if( aField[j].zBsln ){ + blob_append_sql(&sql1,", \"%w\"=%d", aField[j].zBsln, rid); + } } } if( aField[j].mUsed & USEDBY_TICKETCHNG ){ blob_append_sql(&sql2, ",\"%w\"", zBaseName); blob_append_sql(&sql3, ",%Q", p->aField[i].zValue); @@ -742,19 +776,35 @@ ** Write a ticket into the repository. */ static int ticket_put( Blob *pTicket, /* The text of the ticket change record */ const char *zTktId, /* The ticket to which this change is applied */ + const char *aUsed, /* Indicators for fields' modifications */ int needMod /* True if moderation is needed */ ){ int result; int rid; manifest_crosslink_begin(); rid = content_put_ex(pTicket, 0, 0, 0, needMod); if( rid==0 ){ fossil_fatal("trouble committing ticket: %s", g.zErrMsg); } + if( nTicketBslns ){ + int i, s, buf[8], nSrc=0, *aSrc=&(buf[0]); + if( nTicketBslns > count(buf) ){ + aSrc = (int*)fossil_malloc(sizeof(int)*nTicketBslns); + } + for(i=0; i 0 ) aSrc[nSrc++] = s; + } + } + if( nSrc ) content_deltify(rid, aSrc, nSrc, 0); + if( aSrc!=&(buf[0]) ) fossil_free( aSrc ); + } if( needMod ){ moderation_table_create(); db_multi_exec( "INSERT INTO modreq(objid, tktid) VALUES(%d,%Q)", rid, zTktId @@ -787,14 +837,14 @@ void *pUuid, int argc, const char **argv, int *argl ){ - char *zDate; + char *zDate, *aUsed; const char *zUuid; int i; - int nJ = 0; + int nJ = 0, rc = TH_OK; Blob tktchng, cksum; int needMod; login_verify_csrf_secret(); if( !captcha_is_correct(0) ){ @@ -804,15 +854,17 @@ zUuid = (const char *)pUuid; blob_zero(&tktchng); zDate = date_in_standard_format("now"); blob_appendf(&tktchng, "D %s\n", zDate); free(zDate); + aUsed = fossil_malloc_zero( nField ); for(i=0; iTicket artifact that would have been submitted:

@
%h(blob_str(&tktchng))
@
Moderation would be %h(zNeedMod).
@ @
- return TH_OK; }else{ if( g.thTrace ){ Th_Trace("submit_ticket {\n
\n%h\n
\n" "}
\n", blob_str(&tktchng)); } - ticket_put(&tktchng, zUuid, needMod); + ticket_put(&tktchng, zUuid, aUsed, needMod); + rc = ticket_change(zUuid); } - return ticket_change(zUuid); + finish: + fossil_free( aUsed ); + return rc; } /* ** WEBPAGE: tktnew @@ -1460,10 +1516,11 @@ }else{ /* add a new ticket or update an existing ticket */ enum { set,add,history,err } eCmd = err; int i = 0; Blob tktchng, cksum; + char *aUsed; /* get command type (set/add) and get uuid, if needed for set */ if( strncmp(g.argv[2],"set",n)==0 || strncmp(g.argv[2],"change",n)==0 || strncmp(g.argv[2],"history",n)==0 ){ if( strncmp(g.argv[2],"history",n)==0 ){ @@ -1602,10 +1659,11 @@ }else{ aField[j].zValue = zFValue; } } } + aUsed = fossil_malloc_zero( nField ); /* now add the needed artifacts to the repository */ blob_zero(&tktchng); /* add the time to the ticket manifest */ blob_appendf(&tktchng, "D %s\n", zDate); @@ -1615,34 +1673,39 @@ char *zPfx; if( aField[i].zAppend && aField[i].zAppend[0] ){ zPfx = " +"; zValue = aField[i].zAppend; + aUsed[i] = JCARD_APPEND; }else if( aField[i].zValue && aField[i].zValue[0] ){ zPfx = " "; zValue = aField[i].zValue; + aUsed[i] = JCARD_ASSIGN; }else{ continue; } if( memcmp(aField[i].zName, "private_", 8)==0 ){ zValue = db_conceal(zValue, strlen(zValue)); blob_appendf(&tktchng, "J%s%s %s\n", zPfx, aField[i].zName, zValue); + aUsed[i] = JCARD_PRIVATE; }else{ blob_appendf(&tktchng, "J%s%s %#F\n", zPfx, aField[i].zName, strlen(zValue), zValue); } } blob_appendf(&tktchng, "K %s\n", zTktUuid); blob_appendf(&tktchng, "U %F\n", zUser); md5sum_blob(&tktchng, &cksum); blob_appendf(&tktchng, "Z %b\n", &cksum); - if( ticket_put(&tktchng, zTktUuid, ticket_need_moderation(1))==0 ){ + if( ticket_put(&tktchng, zTktUuid, aUsed, + ticket_need_moderation(1) )==0 ){ fossil_fatal("%s", g.zErrMsg); }else{ fossil_print("ticket %s succeeded for %s\n", (eCmd==set?"set":"add"),zTktUuid); } + fossil_free( aUsed ); } } }