Check-in [50a58adb76]
Not logged in
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
Changes
[hide diffs]

Modified src/info.c from [ee44c7829b] to [9f9776b1a2].

@@ -421,11 +421,11 @@
     }
     @ <tr><th>Original&nbsp;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");
   }