Diff
Not logged in

Differences From:

File src/wiki.c part of check-in [22c1ac41d4] - Add separate "clone" permissions. Previously, one needed "History" premission in order to clone. But sometimes we want to grant clone without granting history. by drh on 2007-08-23 19:52:19. [view]

To:

File src/wiki.c part of check-in [b2e55c0d4d] - Add the /wiki and /bwiki web pages. Currently renders content from the check-out as readonly. by drh on 2007-09-01 21:11:33. Also file src/wiki.c part of check-in [bbcb6326c9] - Pulled in the navbar and timeline changes. by aku on 2007-09-17 00:58:51. [view]

@@ -26,18 +26,159 @@
 #include <assert.h>
 #include "config.h"
 #include "wiki.h"
 
+
+/*
+** Create a fake replicate of the "vfile" table as a TEMP table
+** using the manifest identified by manid.
+*/
+static void 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);
+}
+
+/*
+** Locate the wiki page with the name zPageName and render it.
+*/
+static void locate_and_render_wikipage(const char *zPageName){
+  Stmt q;
+  int id = 0;
+  int rid = 0;
+  int chnged = 0;
+  char *zPathname = 0;
+  db_prepare(&q,
+     "SELECT id, rid, chnged, pathname FROM vfile"
+     " WHERE (pathname='%q.wiki' OR pathname LIKE '%%/%q.wiki')"
+     "   AND NOT deleted", zPageName, zPageName
+  );
+  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 page, src;
+    char *zTitle = "wiki";
+    char *z;
+    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);
+    }
+
+    /* The wiki page content is now in src.  Check to see if
+    ** there is a <readonly/> or <appendonly/> element at the
+    ** beginning of the content.
+    */
+    z = blob_str(&src);
+    while( isspace(*z) ) z++;
+    if( strncmp(z, "<readonly/>", 11)==0 ){
+      z += 11;
+    }else if( strncmp(z, "<appendonly/>", 13)==0 ){
+      z += 13;
+    }
+
+    /* Check for <title>...</title> markup and remove it if present. */
+    while( isspace(*z) ) z++;
+    if( strncmp(z, "<title>", 7)==0 ){
+      int i;
+      for(i=7; z[i] && z[i]!='<'; i++){}
+      if( z[i]=='<' && strncmp(&z[i], "</title>", 8)==0 ){
+        zTitle = htmlize(&z[7], i-7);
+        z = &z[i+8];
+      }
+    }
+
+    /* Render the page */
+    style_header(zTitle);
+    blob_init(&page, z, -1);
+    wiki_convert(&page, cgi_output_blob(), WIKI_HTML);
+    blob_reset(&src);
+  }else{
+    style_header("Unknown Wiki Page");
+    @ The wiki page "%h(zPageName)" does not exist.
+  }
+  style_footer();
+}
+
 /*
 ** WEBPAGE: wiki
+** URL: /wiki/PAGENAME
 **
-** Render the wiki page that is named after the /wiki/ part of
-** the url.
+** If the local database is available (which only happens if run
+** as "server" instead of "cgi" or "http") then the file is taken
+** from the local checkout.  If there is no local checkout, then
+** the content is taken from the "head" baseline.
 */
 void wiki_page(void){
-  style_header("Wiki");
-  @ extra=%h(g.zExtra)
-  style_footer();
+  login_check_credentials();
+  if( !g.okRdWiki ){ login_needed(); return; }
+  if( !g.localOpen ){
+    int headid = db_int(0,
+       "SELECT cid FROM plink ORDER BY mtime DESC LIMIT 1"
+    );
+    create_fake_vfile(headid);
+  }
+  locate_and_render_wikipage(g.zExtra);
+}
+
+/*
+** The g.zExtra value is of the form UUID/otherstuff.
+** Extract the UUID and convert it to a record id.  Leave
+** g.zExtra holding just otherstuff.  If UUID does not exist
+** or is malformed, return 0 and leave g.zExtra unchanged.
+*/
+int extract_uuid_from_url(void){
+  int i, rid;
+  Blob uuid;
+  for(i=0; g.zExtra[i] && g.zExtra[i]!='/'; i++){}
+  blob_zero(&uuid);
+  blob_append(&uuid, g.zExtra, i);
+  rid = name_to_uuid(&uuid, 0);
+  blob_reset(&uuid);
+  if( rid ){
+    while( g.zExtra[i]=='/' ){ i++; }
+    g.zExtra = &g.zExtra[i];
+  }
+  return rid;
+}
+
+/*
+** WEBPAGE: bwiki
+** URL: /bwiki/UUID/PAGENAME
+**
+** UUID specifies a baseline.  Render the wiki page PAGENAME as
+** it appears in that baseline.
+*/
+void bwiki_page(void){
+  int headid;
+  login_check_credentials();
+  if( !g.okRdWiki || !g.okHistory ){ login_needed(); return; }
+  headid = extract_uuid_from_url();
+  if( headid ){
+    create_fake_vfile(headid);
+  }
+  locate_and_render_wikipage(g.zExtra);
 }
 
 /*
 ** WEBPAGE: ambiguous