Index: src/report.c ================================================================== --- src/report.c +++ src/report.c @@ -145,11 +145,11 @@ ** This is the SQLite authorizer callback used to make sure that the ** SQL statements entered by users do not try to do anything untoward. ** If anything suspicious is tried, set *(char**)pError to an error ** message obtained from malloc. */ -static int report_query_authorizer( +int report_query_authorizer( void *pError, int code, const char *zArg1, const char *zArg2, const char *zArg3, @@ -942,5 +942,169 @@ sqlite3_exec(g.db, zSql, output_tab_separated, &count, &zErr2); sqlite3_set_authorizer(g.db, 0, 0); cgi_set_content_type("text/plain"); } } + +/* +** report number for full table ticket export +*/ +static const char zFullTicketRptRn[] = "0"; + +/* +** report title for full table ticket export +*/ +static const char zFullTicketRptTitle[] = "full ticket export"; + +/* +** show all reports, which can be used for ticket show. +** Output is written to stdout as tab delimited table +*/ +void rpt_list_reports(void){ + Stmt q; + char const aRptOutFrmt[] = "%s\t%s\n"; + + printf("Available reports:\n"); + printf(aRptOutFrmt,"report number","report title"); + printf(aRptOutFrmt,zFullTicketRptRn,zFullTicketRptTitle); + db_prepare(&q,"SELECT rn,title FROM reportfmt ORDER BY rn"); + while( db_step(&q)==SQLITE_ROW ){ + const char *zRn = db_column_text(&q, 0); + const char *zTitle = db_column_text(&q, 1); + + printf(aRptOutFrmt,zRn,zTitle); + } + db_finalize(&q); +} + +/* +** user defined separator used by ticket show command +*/ +static const char *zSep = 0; + +/* +** select the quoting algorithm for "ticket show" +*/ +#if INTERFACE +typedef enum eTktShowEnc { tktNoTab=0, tktFossilize=1 } tTktShowEncoding; +#endif +static tTktShowEncoding tktEncode = tktNoTab; + +/* +** Output the text given in the argument. Convert tabs and newlines into +** spaces. +*/ +static void output_no_tabs_file(const char *z){ + switch( tktEncode ){ + case tktFossilize: + { char *zFosZ; + + if( z && *z ){ + zFosZ = fossilize(z,-1); + printf("%s",zFosZ); + free(zFosZ); + } + break; + } + default: + while( z && z[0] ){ + int i, j; + for(i=0; z[i] && (!isspace(z[i]) || z[i]==' '); i++){} + if( i>0 ){ + printf("%.*s", i, z); + } + for(j=i; isspace(z[j]); j++){} + if( j>i ){ + printf("%*s", j-i, ""); + } + z += j; + } + break; + } +} + +/* +** Output a row as a tab-separated line of text. +*/ +int output_separated_file( + void *pUser, /* Pointer to row-count integer */ + int nArg, /* Number of columns in this result row */ + char **azArg, /* Text of data in all columns */ + char **azName /* Names of the columns */ +){ + int *pCount = (int*)pUser; + int i; + + if( *pCount==0 ){ + for(i=0; i } + +/* +** COMMAND: ticket +** Usage: %fossil ticket SUBCOMMAND ... +** +** Run various subcommands to control tickets +** +** %fossil ticket show (REPORTTITLE|REPORTNR) ?TICKETFILTER? ?options? +** +** options can be: +** ?-l|--limit LIMITCHAR? +** ?-q|--quote? +** +** Run the ticket report, identified by the report format title +** used in the gui. The data is written as flat file on stdout, +** using "," as separator. The seperator "," can be changed using +** the -l or --limit option. +** If TICKETFILTER is given on the commandline, the query is +** limited with a new WHERE-condition. +** example: Report lists a column # with the uuid +** TICKETFILTER may be [#]='uuuuuuuuu' +** example: Report only lists rows with status not open +** TICKETFILTER: status != 'open' +** If the option -q|--quote is used, the tickets are encoded by +** quoting special chars(space -> \\s, tab -> \\t, newline -> \\n, +** cr -> \\r, formfeed -> \\f, vtab -> \\v, nul -> \\0, \\ -> \\\\). +** Otherwise, the simplified encoding as on the show report raw +** page in the gui is used. +** +** Instead of the report title its possible to use the report +** number. Using the special report number 0 list all columns, +** defined in the ticket table. +** +** %fossil ticket list fields +** +** list all fields, defined for ticket in the fossil repository +** +** %fossil ticket list reports +** +** list all ticket reports, defined in the fossil repository +** +** %fossil ticket set TICKETUUID FIELD VALUE ?FIELD VALUE .. ? ?-q|--quote? +** %fossil ticket change TICKETUUID FIELD VALUE ?FIELD VALUE .. ? ?-q|--quote? +** +** change ticket identified by TICKETUUID and set the value of +** field FIELD to VALUE. Valid field descriptions are: +** status, type, severity, priority, resolution, +** foundin, private_contact, resolution, title or comment +** Field names given above are the ones, defined in a standard +** fossil environment. If you have added, deleted columns, you +** change the all your configured columns. +** You can use more than one field/value pair on the commandline. +** Using -q|--quote enables the special character decoding as +** in "ticket show". So it's possible, to set multiline text or +** text with special characters. +** +** %fossil ticket add FIELD VALUE ?FIELD VALUE .. ? ?-q|--quote? +** +** like set, but create a new ticket with the given values. +** +** The values in set|add are not validated against the definitions +** given in "Ticket Common Script". +*/ +void ticket_cmd(void){ + int n; + + /* do some ints, we want to be inside a checkout */ + db_must_be_within_tree(); + db_find_and_open_repository(1); + user_select(); + /* + ** Check that the user exists. + */ + if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){ + fossil_fatal("no such user: %s", g.zLogin); + } + + if( g.argc<3 ){ + usage("add|fieldlist|set|show"); + }else{ + n = strlen(g.argv[2]); + if( n==1 && g.argv[2][0]=='s' ){ + /* set/show cannot be distinguished, so show the usage */ + usage("add|fieldlist|set|show"); + }else if( strncmp(g.argv[2],"list",n)==0 ){ + if( g.argc==3 ){ + usage("list fields|reports"); + }else{ + n = strlen(g.argv[3]); + if( !strncmp(g.argv[3],"fields",n) ){ + /* simply show all field names */ + int i; + + /* read all available ticket fields */ + getAllTicketFields(); + for(i=0; i4 ){ + zFilterUuid = g.argv[4]; + } + + rptshow( zRep, zSep, zFilterUuid, tktEncoding ); + + } + }else{ + /* add a new ticket or update an existing ticket */ + enum { set,add,err } eCmd = err; + int i; + int rid; + const char *zTktUuid; + Blob tktchng, cksum; + + /* 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 ){ + eCmd = set; + if( g.argc==3 ){ + usage("set TICKETUUID"); + } + zTktUuid = db_text(0, + "SELECT tkt_uuid FROM ticket WHERE tkt_uuid GLOB '%s*'", g.argv[3] + ); + if( !zTktUuid ){ + fossil_fatal("unknown ticket: '%s'!",g.argv[3]); + } + i=4; + }else if( strncmp(g.argv[2],"add",n)==0 ){ + eCmd = add; + i = 3; + zTktUuid = db_text(0, "SELECT lower(hex(randomblob(20)))"); + } + /* none of set/add, so show the usage! */ + if( eCmd==err ){ + usage("add|fieldlist|set|show"); + } + + /* read all given ticket field/value pairs from command line */ + if( i==g.argc ){ + fossil_fatal("empty %s command aborted!",g.argv[2]); + } + getAllTicketFields(); + /* read commandline and assign fields in the azValue array */ + while( i $@ + +$(OBJDIR)\event$O : event_.c event.h + $(TCC) -o$@ -c event_.c + +event_.c : $(SRCDIR)\event.c + +translate$E $** > $@ $(OBJDIR)\encode$O : encode_.c encode.h $(TCC) -o$@ -c encode_.c encode_.c : $(SRCDIR)\encode.c