Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Add ticket configuration editing capability. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA1: |
5f3ddcc1b80bc8e20a09be8ff131522c |
| User & Date: | drh 2007-11-25 21:11:33.000 |
Context
|
2007-11-26
| ||
| 01:33 | Begin porting the CVSTrac ticket reporting code over to fossil. The new code is not yet connected into the system. The port is incomplete. ... (check-in: 62f37c9722 user: drh tags: trunk) | |
|
2007-11-25
| ||
| 21:11 | Add ticket configuration editing capability. ... (check-in: 5f3ddcc1b8 user: drh tags: trunk) | |
| 17:13 | Changes to the diff algorithm to put bounds on run-time for very large files with many differences. (This came up on the previous check-in when you try to diff the two versions of sqlite3.c.) ... (check-in: 4c22ae52fd user: drh tags: trunk) | |
Changes
Changes to src/setup.c.
| ︙ | ︙ | |||
36 37 38 39 40 41 42 |
** the menu entry has no hyperlink - it is disabled.
*/
void setup_menu_entry(
const char *zTitle,
const char *zLink,
const char *zDesc
){
| | < | | | | | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
** the menu entry has no hyperlink - it is disabled.
*/
void setup_menu_entry(
const char *zTitle,
const char *zLink,
const char *zDesc
){
@ <tr><td valign="top" align="right">
if( zLink && zLink[0] ){
@ <a href="%s(zLink)">%h(zTitle)</a>
}else{
@ %h(zTitle)
}
@ </td><td valign="top">%h(zDesc)</td></tr>
}
/*
** WEBPAGE: /setup
*/
void setup_page(void){
login_check_credentials();
if( !g.okSetup ){
login_needed();
}
style_header("Setup");
@ <table border="0" cellspacing="20">
setup_menu_entry("Users", "setup_ulist",
"Grant privileges to individual users.");
setup_menu_entry("Access", "setup_access",
"Control access settings.");
setup_menu_entry("Configuration", "setup_config",
"Configure the WWW components of the repository");
setup_menu_entry("Tickets", "setup_ticket",
"Configure the trouble-ticketing system for this repository");
setup_menu_entry("CSS", "setup_editcss",
"Edit the Cascading Style Sheet used by all pages of this repository");
setup_menu_entry("Header", "setup_header",
"Edit HTML text inserted at the top of every page");
setup_menu_entry("Footer", "setup_footer",
"Edit HTML text inserted at the bottom of every page");
@ </table>
style_footer();
}
/*
** WEBPAGE: setup_ulist
**
|
| ︙ | ︙ | |||
652 653 654 655 656 657 658 | @ <hr> @ Here is the default page footer: @ <blockquote><pre> @ %h(zDefaultFooter) @ </pre></blockquote> db_end_transaction(0); } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 |
@ <hr>
@ Here is the default page footer:
@ <blockquote><pre>
@ %h(zDefaultFooter)
@ </pre></blockquote>
db_end_transaction(0);
}
/*
** WEBPAGE: setup_ticket
*/
void setup_ticket(void){
const char *zConfig;
int isSubmit;
login_check_credentials();
if( !g.okSetup ){
login_needed();
}
isSubmit = P("submit")!=0;
db_begin_transaction();
zConfig = P("cfg");
if( zConfig==0 ){
zConfig = db_text((char*)zDefaultTicketConfig,
"SELECT value FROM config WHERE name='ticket-configuration'");
}
style_header("Edit Ticket Configuration");
if( P("clear")!=0 ){
db_multi_exec("DELETE FROM config WHERE name='ticket-configuration'");
zConfig = zDefaultTicketConfig;
}else if( isSubmit ){
char *zErr = ticket_config_check(zConfig);
if( zErr==0 ){
db_multi_exec(
"REPLACE INTO config(name,value) VALUES('ticket-configuration',"
"%Q)", zConfig
);
}else{
@ <p><font color="red"><b>
@ SCRIPT ERROR: %h(zErr)
@ </b></font></p>
}
}
@ <form action="%s(g.zBaseURL)/setup_ticket" method="POST">
@ <p>Edit the "subscript" script that defines the ticketing
@ system setup for this server.</p>
@ <textarea name="cfg" rows="40" cols="80">%h(zConfig)</textarea>
@ <br />
@ <input type="submit" name="submit" value="Apply Changes">
@ <input type="submit" name="clear" value="Revert To Default">
@ </form>
@ <hr>
@ Here is the default page header:
@ <blockquote><pre>
@ %h(zDefaultTicketConfig)
@ </pre></blockquote>
db_end_transaction(0);
}
|
Changes to src/style.c.
| ︙ | ︙ | |||
44 45 46 47 48 49 50 | /* ** Add a new element to the submenu */ void style_submenu_element( const char *zLabel, const char *zTitle, | | > > > | > | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
/*
** Add a new element to the submenu
*/
void style_submenu_element(
const char *zLabel,
const char *zTitle,
const char *zLink,
...
){
va_list ap;
assert( nSubmenu < sizeof(aSubmenu)/sizeof(aSubmenu[0]) );
aSubmenu[nSubmenu].zLabel = zLabel;
aSubmenu[nSubmenu].zTitle = zTitle;
va_start(ap, zLink);
aSubmenu[nSubmenu].zLink = vmprintf(zLink, ap);
va_end(ap);
nSubmenu++;
}
/*
** Compare two submenu items for sorting purposes
*/
static int submenuCompare(const void *a, const void *b){
|
| ︙ | ︙ |
Changes to src/tkt.c.
| ︙ | ︙ | |||
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 |
}
db_finalize(&q);
db_end_transaction(0);
}
/*
** WEBPAGE: tktview
*/
void tktview_page(void){
char *zScript;
int nScript;
login_check_credentials();
if( !g.okRdTkt ){ login_needed(); return; }
style_header("View Ticket");
ticket_init();
initializeVariablesFromDb();
zScript = (char*)SbS_Fetch(pInterp, "tktview_template", -1, &nScript);
zScript = mprintf("%.*s", nScript, zScript);
SbS_Render(pInterp, zScript);
style_footer();
| > > > > > > | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
}
db_finalize(&q);
db_end_transaction(0);
}
/*
** WEBPAGE: tktview
**
** View a ticket.
*/
void tktview_page(void){
char *zScript;
int nScript;
login_check_credentials();
if( !g.okRdTkt ){ login_needed(); return; }
if( g.okWrTkt ){
style_submenu_element("Edit", "Edit The Ticket", "%s/tktedit?name=%T",
g.zTop, PD("name",""));
}
style_header("View Ticket");
ticket_init();
initializeVariablesFromDb();
zScript = (char*)SbS_Fetch(pInterp, "tktview_template", -1, &nScript);
zScript = mprintf("%.*s", nScript, zScript);
SbS_Render(pInterp, zScript);
style_footer();
|
| ︙ | ︙ | |||
419 420 421 422 423 424 425 426 427 428 429 430 431 432 |
return SBS_RETURN;
}
/*
** WEBPAGE: tktnew
** WEBPAGE: debug_tktnew
*/
void tktnew_page(void){
char *zScript;
int nScript;
char *zNewUuid = 0;
login_check_credentials();
| > > > > > > > > | 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 |
return SBS_RETURN;
}
/*
** WEBPAGE: tktnew
** WEBPAGE: debug_tktnew
**
** Enter a new ticket. the tktnew_template script in the ticket
** configuration is used. The /tktnew page is the official ticket
** entry page. The /debug_tktnew page is used for debugging the
** tktnew_template in the ticket configuration. /debug_tktnew works
** just like /tktnew except that it does not really save the new ticket
** when you press submit - it just prints the ticket artifact at the
** top of the screen.
*/
void tktnew_page(void){
char *zScript;
int nScript;
char *zNewUuid = 0;
login_check_credentials();
|
| ︙ | ︙ | |||
445 446 447 448 449 450 451 |
cgi_redirect(mprintf("%s/tktview/%s", g.zBaseURL, zNewUuid));
return;
}
@ </form>
style_footer();
}
| < < > > > > > > > | 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 |
cgi_redirect(mprintf("%s/tktview/%s", g.zBaseURL, zNewUuid));
return;
}
@ </form>
style_footer();
}
/*
** WEBPAGE: tktedit
** WEBPAGE: debug_tktedit
**
** Edit a ticket. The ticket is identified by the name CGI parameter.
** /tktedit is the official page. The /debug_tktedit page does the same
** thing except that it does not save the ticket change record when you
** press submit - it instead prints the ticket change record at the top
** of the page. The /debug_tktedit page is intended to be used when
** debugging ticket configurations.
*/
void tktedit_page(void){
char *zScript;
int nScript;
int nName;
const char *zName;
int nRec;
|
| ︙ | ︙ | |||
499 500 501 502 503 504 505 |
if( SbS_Render(pInterp, zScript)==SBS_RETURN && zName ){
cgi_redirect(mprintf("%s/tktview/%s", g.zBaseURL, zName));
return;
}
@ </form>
style_footer();
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 |
if( SbS_Render(pInterp, zScript)==SBS_RETURN && zName ){
cgi_redirect(mprintf("%s/tktview/%s", g.zBaseURL, zName));
return;
}
@ </form>
style_footer();
}
/*
** Check the ticket configuration in zConfig to see if it appears to
** be well-formed. If everything is OK, return NULL. If something is
** amiss, then return a pointer to a string (obtained from malloc) that
** describes the problem.
*/
char *ticket_config_check(const char *zConfig){
struct Subscript *p;
char *zErr = 0;
const char *z;
int n;
int i;
int rc;
sqlite3 *db;
static const char *azRequired[] = {
"tktnew_template",
"tktview_template",
"tktedit_template",
};
p = SbS_Create();
rc = SbS_Eval(p, zConfig, strlen(zConfig));
if( rc!=SBS_OK ){
zErr = mprintf("%s", SbS_GetErrorMessage(p));
SbS_Destroy(p);
return zErr;
}
for(i=0; i<sizeof(azRequired)/sizeof(azRequired[0]); i++){
z = SbS_Fetch(p, azRequired[i], -1, &n);
if( z==0 ){
zErr = mprintf("missing definition: %s", azRequired[i]);
SbS_Destroy(p);
return zErr;
}
}
z = SbS_Fetch(p, "ticket_sql", -1, &n);
if( z==0 ){
zErr = mprintf("missing definition: ticket_sql");
SbS_Destroy(p);
return zErr;
}
rc = sqlite3_open(":memory:", &db);
if( rc==SQLITE_OK ){
char *zSql = mprintf("%.*s", n, z);
rc = sqlite3_exec(db, zSql, 0, 0, &zErr);
if( rc!=SQLITE_OK ){
sqlite3_close(db);
SbS_Destroy(p);
return zErr;
}
/* TODO: verify that the TICKET table exists and has required fields */
sqlite3_close(db);
}
SbS_Destroy(p);
return 0;
}
|
Changes to src/tktconfig.c.
| ︙ | ︙ | |||
83 84 85 86 87 88 89 | ** VALUE NAME set ** ** This configuration file just sets the values of various variables. ** Some of the variables have special meanings. The content of some ** of the variables are additional subscript scripts. */ | | < < < < < < < < | < < | > > > | | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
** VALUE NAME set
**
** This configuration file just sets the values of various variables.
** Some of the variables have special meanings. The content of some
** of the variables are additional subscript scripts.
*/
/* @-comment: ** */
const char zDefaultTicketConfig[] =
@ ############################################################################
@ # Every ticket configuration *must* define an SQL statement that creates
@ # the TICKET table. This table must have three columns named
@ # tkt_id, tkt_uuid, and tkt_mtime. tkt_id must be the integer primary
@ # key and tkt_uuid and tkt_mtime must be unique. A configuration should
@ # define addition columns as necessary. All columns should be in all
@ # lower-case letters and should not begin with "tkt".
@ #
@ {
@ CREATE TABLE ticket(
@ -- Do not change any column that begins with tkt_
@ tkt_id INTEGER PRIMARY KEY,
@ tkt_uuid TEXT,
@ tkt_mtime DATE,
|
| ︙ | ︙ |
Changes to src/wiki.c.
| ︙ | ︙ | |||
159 160 161 162 163 164 165 |
manifest_parse(&m, &content);
if( m.type==CFTYPE_WIKI ){
zBody = m.zWiki;
}
}
}
if( isSandbox || (rid && g.okWrWiki) || (!rid && g.okNewWiki) ){
| | | | | | | | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
manifest_parse(&m, &content);
if( m.type==CFTYPE_WIKI ){
zBody = m.zWiki;
}
}
}
if( isSandbox || (rid && g.okWrWiki) || (!rid && g.okNewWiki) ){
style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T",
g.zTop, zPageName);
}
if( isSandbox || (rid && g.okApndWiki) ){
style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T",
g.zTop, zPageName);
}
if( !isSandbox && g.okHistory ){
style_submenu_element("History", "History", "%s/whistory?name=%T",
g.zTop, zPageName);
}
zHtmlPageName = mprintf("%h", zPageName);
style_header(zHtmlPageName);
blob_init(&wiki, zBody, -1);
wiki_convert(&wiki, 0, 0);
blob_reset(&wiki);
if( !isSandbox ){
|
| ︙ | ︙ |