Overview
SHA1 Hash: | 50a58adb76175391f3179deff1fb954a204b0f93 |
---|---|
Date: | 2007-10-10 21:15:17 |
User: | drh |
Comment: | Many changes and bug fixes in the wiki processing. Moving toward a workable wiki system. The "Home" menu option now takes you to the wiki page whose name is the same as the Project Name. There is a "wcontent" page, but no link to it yet. Many other changes. |
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/info.c from [ee44c7829b] to [9f9776b1a2].
@@ -421,11 +421,11 @@ } @ <tr><th>Original User:</th><td>%s(db_column_text(&q, 3))</td></tr> @ <tr><th>Commands:</th> @ <td> /* @ <a href="%s(g.zBaseURL)/wdiff/%d(rid)">diff</a> | */ - @ <a href="%s(g.zBaseURL)/wlist/%t(zName)">history</a> + @ <a href="%s(g.zBaseURL)/whistory/%t(zName)">history</a> @ | <a href="%s(g.zBaseURL)/fview/%d(rid)">raw-text</a> @ </td> @ </tr> @ </table></p> }else{
Modified src/login.c from [4002a249f4] to [9dc968113f].
@@ -287,11 +287,11 @@ */ void login_set_capabilities(const char *zCap){ int i; for(i=0; zCap[i]; i++){ switch( zCap[i] ){ - case 's': g.okSetup = g.okDelete = 1; + case 's': g.okSetup = 1; case 'a': g.okAdmin = g.okRdTkt = g.okWrTkt = g.okQuery = g.okRdWiki = g.okWrWiki = g.okNewWiki = g.okHistory = g.okClone = g.okNewTkt = g.okPassword = 1; case 'i': g.okRead = g.okWrite = 1; break;
Modified src/main.c from [9a7566a7fb] to [ef101c5a91].
@@ -59,10 +59,11 @@ int fSqlPrint; /* True if -sqlprint flag is present */ int fHttpTrace; /* Trace outbound HTTP requests */ char *zPath; /* Name of webpage being served */ char *zExtra; /* Extra path information past the webpage name */ char *zBaseURL; /* Full text of the URL being served */ + char *zTop; /* Parent directory of zPath */ const char *zContentType; /* The content type of the input HTTP request */ int iErrPriority; /* Priority of current error message */ char *zErrMsg; /* Text of an error message */ Blob cgiIn; /* Input to an xfer www method */ int cgiPanic; /* Write error messages to CGI */ @@ -98,10 +99,11 @@ int okClone; /* g: clone */ int okRdWiki; /* j: view wiki via web */ int okNewWiki; /* f: create new wiki via web */ int okApndWiki; /* m: append to wiki via web */ int okWrWiki; /* k: edit wiki via web */ + int okLockWiki; /* l: lock and unlock wiki via web */ int okRdTkt; /* r: view tickets via web */ int okNewTkt; /* n: create new tickets */ int okApndTkt; /* c: append to tickets via the web */ int okWrTkt; /* w: make changes to tickets via web */ @@ -412,15 +414,15 @@ } putchar('\n'); } /* -** RSS feeds need to reference absolute URLs so we need to calculate -** the base URL onto which we add components. This is basically -** cgi_redirect() stripped down and always returning an absolute URL. +** Set the g.zBaseURL value to the full URL for the toplevel of +** the fossil tree. Set g.zHomeURL to g.zBaseURL without the +** leading "http://" and the host and port. */ -static char *get_base_url(void){ +void set_base_url(void){ int i; const char *zHost = PD("HTTP_HOST",""); const char *zMode = PD("HTTPS","off"); const char *zCur = PD("REQUEST_URI","/"); @@ -436,13 +438,16 @@ } while( i>0 && zCur[i-1]!='/' ){ i--; } while( i>0 && zCur[i-1]=='/' ){ i--; } if( strcmp(zMode,"on")==0 ){ - return mprintf("https://%s%.*s", zHost, i, zCur); - } - return mprintf("http://%s%.*s", zHost, i, zCur); + g.zBaseURL = mprintf("https://%s%.*s", zHost, i, zCur); + g.zTop = &g.zBaseURL[8+strlen(zHost)+i]; + }else{ + g.zBaseURL = mprintf("http://%s%.*s", zHost, i, zCur); + g.zTop = &g.zBaseURL[7+strlen(zHost)+i]; + } } /* ** Preconditions: ** @@ -484,11 +489,11 @@ zPath[i] = 0; g.zExtra = &zPath[i+1]; }else{ g.zExtra = 0; } - g.zBaseURL = get_base_url(); + set_base_url(); if( g.zExtra ){ /* CGI parameters get this treatment elsewhere, but places like getfile ** will use g.zExtra directly. */ dehttpize(g.zExtra);
Modified src/setup.c from [2446896fe8] to [743163c8fa].
@@ -130,10 +130,11 @@ @ <li value="7"><b>Clone</b>: Clone the repository</li> @ <li value="8"><b>History</b>: View detail repository history</li> @ <li value="9"><b>Check-In</b>: Commit new versions in the repository</li> @ <li value="10"><b>Read-Wiki</b>: View wiki pages</li> @ <li value="11"><b>Write-Wiki</b>: Edit wiki pages</li> + @ <li value="12"><b>Lock-Wiki</b>: Lock or unlock wiki pages</li> @ <li value="13"><b>Append-Wiki</b>: Append to wiki pages</li> @ <li value="14"><b>New-Tkt</b>: Create new tickets</li> @ <li value="15"><b>Check-Out</b>: Check out versions</li> @ <li value="16"><b>Password</b>: Change your own password</li> @ <li value="17"><b>Query</b>: Create new queries against tickets</li> @@ -159,11 +160,11 @@ ** WEBPAGE: /setup_uedit */ void user_edit(void){ const char *zId, *zLogin, *zInfo, *zCap; char *oaa, *oas, *oar, *oaw, *oan, *oai, *oaj, *oao, *oap ; - char *oak, *oad, *oaq, *oac, *oaf, *oam, *oah, *oag; + char *oak, *oad, *oaq, *oac, *oaf, *oam, *oah, *oag, *oal; int doWrite; int uid; int higherUser = 0; /* True if user being edited is SETUP and the */ /* user doing the editing is ADMIN. Disallow editing */ @@ -213,19 +214,21 @@ int ac = P("ac")!=0; int af = P("af")!=0; int am = P("am")!=0; int ah = P("ah")!=0; int ag = P("ag")!=0; + int al = P("al")!=0; if( aa ){ zCap[i++] = 'a'; } if( ac ){ zCap[i++] = 'c'; } if( ad ){ zCap[i++] = 'd'; } if( af ){ zCap[i++] = 'f'; } if( ah ){ zCap[i++] = 'h'; } if( ag ){ zCap[i++] = 'g'; } if( ai ){ zCap[i++] = 'i'; } if( aj ){ zCap[i++] = 'j'; } if( ak ){ zCap[i++] = 'k'; } + if( al ){ zCap[i++] = 'l'; } if( am ){ zCap[i++] = 'm'; } if( an ){ zCap[i++] = 'n'; } if( ao ){ zCap[i++] = 'o'; } if( ap ){ zCap[i++] = 'p'; } if( aq ){ zCap[i++] = 'q'; } @@ -262,11 +265,11 @@ /* Load the existing information about the user, if any */ zLogin = ""; zInfo = ""; zCap = ""; - oaa = oac = oad = oaf = oag = oah = oai = oaj = oak = oam = + oaa = oac = oad = oaf = oag = oah = oai = oaj = oak = oal = oam = oan = oao = oap = oaq = oar = oas = oaw = ""; if( uid ){ zLogin = db_text("", "SELECT login FROM user WHERE uid=%d", uid); zInfo = db_text("", "SELECT info FROM user WHERE uid=%d", uid); zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", uid); @@ -277,10 +280,11 @@ if( strchr(zCap, 'g') ) oag = " checked"; if( strchr(zCap, 'h') ) oah = " checked"; if( strchr(zCap, 'i') ) oai = " checked"; if( strchr(zCap, 'j') ) oaj = " checked"; if( strchr(zCap, 'k') ) oak = " checked"; + if( strchr(zCap, 'l') ) oal = " checked"; if( strchr(zCap, 'm') ) oam = " checked"; if( strchr(zCap, 'n') ) oan = " checked"; if( strchr(zCap, 'o') ) oao = " checked"; if( strchr(zCap, 'p') ) oap = " checked"; if( strchr(zCap, 'q') ) oaq = " checked"; @@ -332,10 +336,11 @@ @ <input type="checkbox" name="ag"%s(oag)>Clone</input><br> @ <input type="checkbox" name="aj"%s(oaj)>Read Wiki</input><br> @ <input type="checkbox" name="af"%s(oaf)>New Wiki</input><br> @ <input type="checkbox" name="am"%s(oam)>Append Wiki</input><br> @ <input type="checkbox" name="ak"%s(oak)>Write Wiki</input><br> + @ <input type="checkbox" name="al"%s(oak)>Lock Wiki</input><br> @ <input type="checkbox" name="ar"%s(oar)>Read Tkt</input><br> @ <input type="checkbox" name="an"%s(oan)>New Tkt</input><br> @ <input type="checkbox" name="ac"%s(oac)>Append Tkt</input><br> @ <input type="checkbox" name="aw"%s(oaw)>Write Tkt</input> @ </td> @@ -362,11 +367,13 @@ } @ @ <li><p> @ The <b>Delete</b> privilege give the user the ability to erase @ wiki, tickets, and atttachments that have been added by anonymous - @ users. This capability is intended for deletion of spam. + @ users. This capability is intended for deletion of spam. The + @ delete capability is only in effect for 24 hours after the item + @ is first posted. The Setup user can delete anything at any time. @ </p></li> @ @ <li><p> @ The <b>Query</b> privilege allows the user to create or edit @ report formats by specifying appropriate SQL. Users can run
Modified src/style.c from [5a0e7535f4] to [9469a23cd8].
@@ -60,11 +60,11 @@ /* ** Compare two submenu items for sorting purposes */ static int submenuCompare(const void *a, const void *b){ const struct Submenu *A = (const struct Submenu*)a; - const struct Submenu *B = (const struct Submenu*)B; + const struct Submenu *B = (const struct Submenu*)b; return strcmp(A->zLabel, B->zLabel); } /* ** Draw the header. @@ -91,11 +91,11 @@ }else{ @ logged in as %h(g.zLogin) } @ </div> @ <div id="main-menu"> - @ <a href="%s(g.zBaseURL)/index">Home</a> + @ <a href="%s(g.zBaseURL)/home">Home</a> if( g.okRead ){ @ | <a href="%s(g.zBaseURL)/leaves">Leaves</a> @ | <a href="%s(g.zBaseURL)/timeline">Timeline</a> } #if 0 @@ -140,101 +140,21 @@ @ <div id="style-footer"> @ Fossil version %s(MANIFEST_VERSION) %s(MANIFEST_DATE) @ </div> } -/* -** WEBPAGE: index -** WEBPAGE: home -** WEBPAGE: not_found -*/ -void page_index(void){ - char *zHome = "Home"; - if( zHome ){ - g.zExtra = zHome; - g.okRdWiki = 1; - wiki_page(); - }else{ - style_header("Main Title Page"); - @ No homepage configured for this server - style_footer(); - } -} - -/* -** TODO: COPIED FROM WIKI.C... BAD -*/ -/* -** Create a fake replicate of the "vfile" table as a TEMP table -** using the manifest identified by manid. -*/ -static void style_create_fake_vfile(int manid){ - static const char zVfileDef[] = - @ CREATE TEMP TABLE vfile( - @ id INTEGER PRIMARY KEY, -- ID of the checked out file - @ vid INTEGER REFERENCES blob, -- The version this file is part of. - @ chnged INT DEFAULT 0, -- 0:unchnged 1:edited 2:m-chng 3:m-add - @ deleted BOOLEAN DEFAULT 0, -- True if deleted - @ rid INTEGER, -- Originally from this repository record - @ mrid INTEGER, -- Based on this record due to a merge - @ pathname TEXT, -- Full pathname - @ UNIQUE(pathname,vid) - @ ); - ; - db_multi_exec(zVfileDef); - load_vfile_from_rid(manid); -} - /* ** WEBPAGE: style.css */ void page_style_css(void){ - Stmt q; - int id = 0; - int rid = 0; - int chnged = 0; - char *zPathname = 0; - char *z; + char *zCSS = 0; cgi_set_content_type("text/css"); - - login_check_credentials(); - if( !g.localOpen ){ - int headid = db_int(0, - "SELECT cid FROM plink ORDER BY mtime DESC LIMIT 1" - ); - style_create_fake_vfile(headid); - } - - db_prepare(&q, - "SELECT id, rid, chnged, pathname FROM vfile" - " WHERE (pathname='style.css' OR pathname LIKE '%%/style.css')" - " AND NOT deleted" - ); - if( db_step(&q)==SQLITE_ROW ){ - id = db_column_int(&q, 0); - rid = db_column_int(&q, 1); - chnged = db_column_int(&q, 2); - if( chnged || rid==0 ){ - zPathname = db_column_malloc(&q, 3); - } - } - db_finalize(&q); - if( id ){ - Blob src; - blob_zero(&src); - if( zPathname ){ - zPathname = mprintf("%s/%z", g.zLocalRoot, zPathname); - blob_read_from_file(&src, zPathname); - free(zPathname); - }else{ - content_get(rid, &src); - } - - z = blob_str(&src); - @ %s(z) + zCSS = db_get("css",0); + if( zCSS ){ + cgi_append_content(zCSS, -1); }else{ /* No CSS file found, use our own */ /* ** Selector order: tags, ids, classes, other ** Content order: margin, borders, padding, fonts, colors, other
Modified src/timeline.c from [dc6941a79a] to [0cd823eb58].
@@ -233,10 +233,11 @@ ** n=INTEGER number of events to show. dflt: 25 ** e=INTEGER starting event id. dflt: nil ** u=NAME show only events from user. dflt: nil ** a show events after and including. dflt: false ** r show only related events. dflt: false +** y=TYPE show only TYPE ('ci' or 'w') dflt: nil */ void page_timeline(void){ Stmt q; char *zSQL; Blob scriptInit; @@ -245,10 +246,11 @@ int nEntry = atoi(PD("n","20")); const char *zUser = P("u"); int objid = atoi(PD("e","0")); int relatedEvents = P("r")!=0; int afterFlag = P("a")!=0; + const char *zType = P("y"); int firstEvent; int lastEvent; /* To view the timeline, must have permission to read project data. */ @@ -259,13 +261,16 @@ if( !g.okHistory && db_exists("SELECT 1 FROM user" " WHERE login='anonymous'" " AND cap LIKE '%%h%%'") ){ @ <p><b>Note:</b> You will be able to access <u>much</u> more - @ historical information if <a href="%s(g.zBaseURL)/login">login</a>.</p> + @ historical information if <a href="%s(g.zTop)/login">login</a>.</p> } zSQL = mprintf("%s", timeline_query_for_www()); + if( zType ){ + zSQL = mprintf("%z AND event.type=%Q", zSQL, zType); + } if( zUser ){ zSQL = mprintf("%z AND event.user=%Q", zSQL, zUser); } if( objid ){ char *z = db_text(0, "SELECT datetime(event.mtime) FROM event" @@ -386,38 +391,10 @@ @ <input type="hidden" value="%d(firstEvent)" name="e"> @ <input type="hidden" value="1" name="a"> @ <input type="hidden" value="%d(nEntry)" name="n"> @ <input type="submit" value="Previous %d(nEntry) Rows"> @ </form> - style_footer(); -} - - -/* -** WEBPAGE: wlist -** -** Show the complete change history for a single wiki page. The name -** of the wiki is in g.zExtra -*/ -void wlist_page(void){ - Stmt q; - char *zTitle; - char *zSQL; - login_check_credentials(); - if( !g.okHistory ){ login_needed(); return; } - zTitle = mprintf("History Of %h", g.zExtra); - style_header(zTitle); - free(zTitle); - - zSQL = mprintf("%s AND event.objid IN " - " (SELECT rid FROM tagxref WHERE tagid=" - "(SELECT tagid FROM tag WHERE tagname='wiki-%q'))", - timeline_query_for_www(), g.zExtra); - db_prepare(&q, zSQL); - free(zSQL); - www_print_timeline(&q, 0, 0, 0, 0); - db_finalize(&q); style_footer(); } /* ** The input query q selects various records. Print a human-readable
Modified src/wiki.c from [83c17e31dc] to [9a9d53861a].
@@ -70,18 +70,46 @@ } return 0; } /* +** WEBPAGE: home +** WEBPAGE: index +** WEBPAGE: not_found +*/ +void home_page(void){ + char *zPageName = db_get("project-name",0); + if( zPageName ){ + login_check_credentials(); + g.zExtra = zPageName; + g.okRdWiki = 1; + g.okApndWiki = 0; + g.okWrWiki = 0; + g.okHistory = 0; + wiki_page(); + return; + } + style_header("Home"); + @ <p>This is a stub home-page for the project. + @ To fill in this page, first go to + @ <a href="%s(g.zBaseURL)/setup_config">setup/config</a> + @ and establish a "Project Name". Then create a + @ wiki page with that name. The content of that wiki page + @ will be displayed in place of this message. + style_footer(); +} + +/* ** WEBPAGE: wiki ** URL: /wiki/PAGENAME */ void wiki_page(void){ char *zTag; int rid; Blob wiki; Manifest m; + int seenHr = 0; char *zPageName; char *zHtmlPageName; char *zBody = mprintf("%s","<i>Empty Page</i>"); login_check_credentials(); @@ -104,20 +132,38 @@ manifest_parse(&m, &content); if( m.type==CFTYPE_WIKI ){ zBody = m.zWiki; } } + if( (rid && g.okWrWiki) || (!rid && g.okNewWiki) ){ + style_submenu_element("Edit", "Edit Wiki Page", + mprintf("%s/wikiedit/%s", g.zTop, g.zExtra)); + } + if( g.okHistory ){ + style_submenu_element("History", "History", + mprintf("%s/whistory/%s", g.zTop, g.zExtra)); + } zHtmlPageName = mprintf("%h", zPageName); style_header(zHtmlPageName); blob_init(&wiki, zBody, -1); wiki_convert(&wiki, 0); blob_reset(&wiki); manifest_clear(&m); +#if 0 if( (rid && g.okWrWiki) || (!rid && g.okNewWiki) ){ @ <hr> @ [<a href="%s(g.zBaseURL)/wikiedit/%s(g.zExtra)">Edit</a>] + seenHr = 1; + } + if( g.okHistory ){ + if( !seenHr ){ + @ <hr> + seenHr = 1; + } + @ [<a href="%s(g.zBaseUrl)/whistory/%s(g.zExtra)">History</a>] } +#endif style_footer(); } /* ** WEBPAGE: wikiedit @@ -224,10 +270,61 @@ @ <input type="submit" name="cancel" value="Cancel"> @ </form> manifest_clear(&m); style_footer(); +} + +/* +** WEBPAGE: whistory +** +** Show the complete change history for a single wiki page. The name +** of the wiki is in g.zExtra +*/ +void whistory_page(void){ + Stmt q; + char *zTitle; + char *zSQL; + login_check_credentials(); + if( !g.okHistory ){ login_needed(); return; } + zTitle = mprintf("History Of %h", g.zExtra); + style_header(zTitle); + free(zTitle); + + zSQL = mprintf("%s AND event.objid IN " + " (SELECT rid FROM tagxref WHERE tagid=" + "(SELECT tagid FROM tag WHERE tagname='wiki-%q'))" + "ORDER BY mtime DESC", + timeline_query_for_www(), g.zExtra); + db_prepare(&q, zSQL); + free(zSQL); + www_print_timeline(&q, 0, 0, 0, 0); + db_finalize(&q); + style_footer(); +} + +/* +** WEBPAGE: wcontent +** +** List all available wiki pages with date created and last modified. +*/ +void wcontent_page(void){ + Stmt q; + login_check_credentials(); + if( !g.okRdWiki ){ login_needed(); return; } + style_header("Available Wiki Pages"); + @ <ul> + db_prepare(&q, + "SELECT substr(tagname, 6, 1000) FROM tag WHERE tagname GLOB 'wiki-*'" + " ORDER BY lower(tagname)" + ); + while( db_step(&q)==SQLITE_ROW ){ + const char *zName = db_column_text(&q, 0); + @ <li><a href="%s(g.zBaseURL)/wiki/%t(zName)">%h(zName)</a></li> + } + db_finalize(&q); + style_footer(); } /* ** WEBPAGE: ambiguous **
Modified src/wikiformat.c from [83901f90e7] to [5c4069b176].
@@ -760,10 +760,12 @@ || strncmp(zTarget, "https:", 6)==0 || strncmp(zTarget, "ftp:", 4)==0 || strncmp(zTarget, "mailto:", 7)==0 ){ blob_appendf(p->pOut, zTarget); + }else if( zTarget[0]=='/' ){ + blob_appendf(p->pOut, "%s%h", g.zBaseURL, zTarget); }else if( wiki_name_is_wellformed(zTarget) ){ blob_appendf(p->pOut, "%s/wiki/%T", g.zBaseURL, zTarget); }else{ blob_appendf(p->pOut, "error"); }