One-step create & edit.
authorrich <rich>
Sat, 9 Oct 2004 09:41:38 +0000 (09:41 +0000)
committerrich <rich>
Sat, 9 Oct 2004 09:41:38 +0000 (09:41 +0000)
scripts/.depend
scripts/Makefile
scripts/create.ml [deleted file]
scripts/create_form.ml [deleted file]
scripts/edit.ml
scripts/wikilib.ml
templates/create_form.html [deleted file]
templates/edit.html

index dd737e6..4362d17 100644 (file)
@@ -22,28 +22,18 @@ cocanwiki_links.cmo: wikilib.cmi cocanwiki_links.cmi
 cocanwiki_links.cmx: wikilib.cmx cocanwiki_links.cmi 
 cocanwiki_ok.cmo: cocanwiki_template.cmi 
 cocanwiki_ok.cmx: cocanwiki_template.cmx 
-cocanwiki_template.cmo: cocanwiki_files.cmo cocanwiki_version.cmo \
-    cocanwiki_template.cmi 
-cocanwiki_template.cmx: cocanwiki_files.cmx cocanwiki_version.cmx \
-    cocanwiki_template.cmi 
+cocanwiki_template.cmo: cocanwiki_files.cmo cocanwiki_template.cmi 
+cocanwiki_template.cmx: cocanwiki_files.cmx cocanwiki_template.cmi 
 contact.cmo: cocanwiki.cmo cocanwiki_ok.cmo cocanwiki_template.cmi 
 contact.cmx: cocanwiki.cmx cocanwiki_ok.cmx cocanwiki_template.cmx 
 contact_show.cmo: cocanwiki.cmo cocanwiki_template.cmi 
 contact_show.cmx: cocanwiki.cmx cocanwiki_template.cmx 
 contacts.cmo: cocanwiki.cmo cocanwiki_template.cmi 
 contacts.cmx: cocanwiki.cmx cocanwiki_template.cmx 
-create.cmo: cocanwiki.cmo cocanwiki_emailnotify.cmo cocanwiki_ok.cmo \
-    wikilib.cmi 
-create.cmx: cocanwiki.cmx cocanwiki_emailnotify.cmx cocanwiki_ok.cmx \
-    wikilib.cmx 
 create_contact.cmo: cocanwiki.cmo cocanwiki_ok.cmo cocanwiki_strings.cmo 
 create_contact.cmx: cocanwiki.cmx cocanwiki_ok.cmx cocanwiki_strings.cmx 
 create_contact_form.cmo: cocanwiki.cmo cocanwiki_template.cmi 
 create_contact_form.cmx: cocanwiki.cmx cocanwiki_template.cmx 
-create_form.cmo: cocanwiki.cmo cocanwiki_ok.cmo cocanwiki_template.cmi \
-    wikilib.cmi 
-create_form.cmx: cocanwiki.cmx cocanwiki_ok.cmx cocanwiki_template.cmx \
-    wikilib.cmx 
 create_user.cmo: cocanwiki.cmo cocanwiki_ok.cmo cocanwiki_strings.cmo 
 create_user.cmx: cocanwiki.cmx cocanwiki_ok.cmx cocanwiki_strings.cmx 
 create_user_form.cmo: cocanwiki.cmo cocanwiki_template.cmi 
@@ -70,10 +60,10 @@ diff.cmo: cocanwiki.cmo cocanwiki_diff.cmo cocanwiki_template.cmi
 diff.cmx: cocanwiki.cmx cocanwiki_diff.cmx cocanwiki_template.cmx 
 edit.cmo: cocanwiki.cmo cocanwiki_diff.cmo cocanwiki_emailnotify.cmo \
     cocanwiki_links.cmi cocanwiki_ok.cmo cocanwiki_strings.cmo \
-    cocanwiki_template.cmi 
+    cocanwiki_template.cmi wikilib.cmi 
 edit.cmx: cocanwiki.cmx cocanwiki_diff.cmx cocanwiki_emailnotify.cmx \
     cocanwiki_links.cmx cocanwiki_ok.cmx cocanwiki_strings.cmx \
-    cocanwiki_template.cmx 
+    cocanwiki_template.cmx wikilib.cmx 
 edit_contact.cmo: cocanwiki.cmo cocanwiki_ok.cmo cocanwiki_strings.cmo 
 edit_contact.cmx: cocanwiki.cmx cocanwiki_ok.cmx cocanwiki_strings.cmx 
 edit_contact_form.cmo: cocanwiki.cmo cocanwiki_template.cmi 
index bb56bd0..2a4c710 100644 (file)
@@ -1,5 +1,5 @@
 # Makefile for COCANWIKI.
-# $Id: Makefile,v 1.33 2004/10/07 16:54:24 rich Exp $
+# $Id: Makefile,v 1.34 2004/10/09 09:41:38 rich Exp $
 
 include ../Makefile.config
 
@@ -30,8 +30,6 @@ OBJS := change_password.cmo \
        contact.cmo \
        contact_show.cmo \
        contacts.cmo \
-       create.cmo \
-       create_form.cmo \
        create_contact.cmo \
        create_contact_form.cmo \
        create_user.cmo \
diff --git a/scripts/create.ml b/scripts/create.ml
deleted file mode 100644 (file)
index 4b4caa6..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-(* COCANWIKI - a wiki written in Objective CAML.
- * Written by Richard W.M. Jones <rich@merjis.com>.
- * Copyright (C) 2004 Merjis Ltd.
- * $Id: create.ml,v 1.8 2004/09/23 11:56:47 rich Exp $
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *)
-
-open Apache
-open Registry
-open Cgi
-open Printf
-
-open ExtString
-
-open Cocanwiki
-open Cocanwiki_emailnotify
-open Cocanwiki_ok
-
-let run r (q : cgi) (dbh : Dbi.connection) hostid {hostname = hostname} user =
-  (* Get the page title. *)
-  let title = q#param "title" in
-
-  let url =
-    match Wikilib.generate_url_of_title dbh hostid title with
-       Wikilib.GenURL_OK url -> url
-      | Wikilib.GenURL_TooShort | Wikilib.GenURL_BadURL ->
-         error ~back_button:true ~title:"Bad page name"
-           q "The page name supplied is too short or invalid.";
-         return ()
-      | Wikilib.GenURL_Duplicate url ->
-         q#redirect ("http://" ^ hostname ^ "/" ^ url);
-         return () in
-
-  (* Description field must contain something. *)
-  let description = q#param "description" in
-  if description = "" then (
-    error ~back_button:true ~title:"Description field missing"
-      q "You must write a brief description for search engines and
-         directories.";
-    return ()
-  );
-
-  (* Get the IP address of the user, if available. *)
-  let logged_ip =
-    try `String (Connection.remote_ip (Request.connection r))
-    with Not_found -> `Null in
-
-  let logged_user =
-    match user with
-      | User (id, _, _) -> `Int id
-      | _ -> `Null in
-
-  (* Create the page. *)
-  let sth = dbh#prepare_cached "insert into pages (hostid, url, title,
-                                  description, logged_ip, logged_user)
-                                values (?, ?, ?, ?, ?, ?)" in
-  sth#execute [`Int hostid; `String url; `String title; `String description;
-              logged_ip; logged_user];
-
-  let pageid = sth#serial "pages_id_seq" in
-
-  (* Create a single section. *)
-  let content = "Write some content here." in
-
-  let sth = dbh#prepare_cached "insert into contents (pageid, ordering,
-                                  sectionname, content) values (?, 1, ?, ?)" in
-  sth#execute [`Int pageid; `Null; `String content];
-
-  (* Commit. *)
-  dbh#commit ();
-
-  (* Email notification, if anyone is listed for this host. *)
-  let subject = "Page " ^ url ^ " has been created" in
-  let body = fun () ->
-    "Page: http://" ^ hostname ^ "/" ^ url ^ "\n" in
-
-  email_notify ~subject ~body dbh hostid;
-
-  (* Redirect to the editing page. *)
-  q#redirect ("http://" ^ hostname ^ "/" ^ url ^ "/edit")
-
-let () =
-  register_script ~restrict:[CanEdit] run
diff --git a/scripts/create_form.ml b/scripts/create_form.ml
deleted file mode 100644 (file)
index 990cfc0..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-(* COCANWIKI - a wiki written in Objective CAML.
- * Written by Richard W.M. Jones <rich@merjis.com>.
- * Copyright (C) 2004 Merjis Ltd.
- * $Id: create_form.ml,v 1.7 2004/09/23 11:56:47 rich Exp $
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *)
-
-open Apache
-open Registry
-open Cgi
-open Printf
-
-open ExtString
-
-open Cocanwiki
-open Cocanwiki_template
-open Cocanwiki_ok
-
-let run r (q : cgi) (dbh : Dbi.connection) hostid { hostname = hostname } _ =
-  let template = get_template dbh hostid "create_form.html" in
-
-  (* Get the page title. *)
-  let title = q#param "title" in
-
-  let url =
-    match Wikilib.generate_url_of_title dbh hostid title with
-       Wikilib.GenURL_OK url -> url
-      | Wikilib.GenURL_TooShort | Wikilib.GenURL_BadURL ->
-         error ~back_button:true ~title:"Bad page name"
-           q "The page name supplied is too short or invalid.";
-         return ()
-      | Wikilib.GenURL_Duplicate url ->
-         q#redirect ("http://" ^ hostname ^ "/" ^ url);
-         return () in
-
-  (* Show the form. *)
-  template#set "title" title;
-
-  q#template template
-
-let () =
-  register_script ~restrict:[CanEdit] run
index 0a07c46..3edce8c 100644 (file)
@@ -1,7 +1,7 @@
 (* COCANWIKI - a wiki written in Objective CAML.
  * Written by Richard W.M. Jones <rich@merjis.com>.
  * Copyright (C) 2004 Merjis Ltd.
- * $Id: edit.ml,v 1.15 2004/10/07 11:36:46 rich Exp $
+ * $Id: edit.ml,v 1.16 2004/10/09 09:41:38 rich Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -33,11 +33,15 @@ open Cocanwiki_emailnotify
 open Cocanwiki_diff
 open Cocanwiki_strings
 
+(* Page of title. *)
+type pt_t = Page of string | Title of string
+
 (* We keep an "internal model" of the page - see build_internal_model ()
  * below.
  *)
 type model_t = {
-  id : int;                            (* Original page ID. *)
+  id : int;                            (* Original page ID (0 = none). *)
+  pt : pt_t;                           (* Page of title (only used if id=0) *)
   description : string;                        (* Description. *)
   redirect : string;                   (* Redirect to ("" = none). *)
   contents : (string * string * string) list;
@@ -67,6 +71,10 @@ let run r (q : cgi) (dbh : Dbi.connection) hostid {hostname = hostname} user =
     let id = int_of_string (q#param "id") in
     let description = q#param "description" in
     let redirect = q#param "redirect" in
+    let pt = match q#param "pt_type" with
+       "page" -> Page (q#param "pt_value")
+      | "title" -> Title (q#param "pt_value")
+      | _ -> failwith "unknown value for pt_type parameter" in
 
     let contents = ref [] in
     let i = ref 1 in
@@ -80,6 +88,7 @@ let run r (q : cgi) (dbh : Dbi.connection) hostid {hostname = hostname} user =
     let contents = List.rev !contents in
 
     { id = id;
+      pt = pt;
       description = description;
       redirect = redirect;
       contents = contents; }
@@ -193,6 +202,14 @@ let run r (q : cgi) (dbh : Dbi.connection) hostid {hostname = hostname} user =
     template#set "id" (string_of_int model.id);
     template#set "description" model.description;
 
+    (match model.pt with
+        Page page ->
+          template#set "pt_type" "page";
+          template#set "pt_value" page
+       | Title title ->
+          template#set "pt_type" "title";
+          template#set "pt_value" title);
+
     (* Redirects table. *)
     let sth = dbh#prepare_cached "select url, title from pages
                                    where url is not null
@@ -208,12 +225,18 @@ let run r (q : cgi) (dbh : Dbi.connection) hostid {hostname = hostname} user =
                           | _ -> assert false) in
     template#table "redirects" table;
 
-    (* Need to go to the database to get the title of the page ... *)
-    let sth = dbh#prepare_cached "select title from pages
-                                   where hostid = ? and id = ?" in
-    sth#execute [`Int hostid; `Int model.id];
-    let title = sth#fetch1string () in
-    template#set "title" title;
+    if model.id <> 0 then (
+      (* Need to go to the database to get the title of the page ... *)
+      let sth = dbh#prepare_cached "select title from pages
+                                     where hostid = ? and id = ?" in
+      sth#execute [`Int hostid; `Int model.id];
+      let title = sth#fetch1string () in
+      template#set "title" title;
+    ) else (
+      match model.pt with
+         Page page -> template#set "title" page
+       | Title title -> template#set "title" title
+    );
 
     let ordering = ref 0 in
     let table =
@@ -234,6 +257,15 @@ let run r (q : cgi) (dbh : Dbi.connection) hostid {hostname = hostname} user =
     template#conditional "has_errors" (errors <> [])
   in
 
+  (* Check if a URL exists in the database. *)
+  let page_exists page =
+    let sth =
+      dbh#prepare_cached "select 1 from pages where hostid = ? and url = ?" in
+    sth#execute [`Int hostid; `String page];
+
+    try sth#fetch1int () = 1 with Not_found -> false
+  in
+
   (* Begin editing a page, pulling the page out of the database and building
    * a model from it.
    *)
@@ -267,6 +299,7 @@ let run r (q : cgi) (dbh : Dbi.connection) hostid {hostname = hostname} user =
                 | _ -> assert false) in
 
     let model = { id = pageid;
+                 pt = Page page;
                  description = description;
                  redirect = redirect;
                  contents = contents; } in
@@ -274,6 +307,31 @@ let run r (q : cgi) (dbh : Dbi.connection) hostid {hostname = hostname} user =
     model_to_template model template
   in
 
+  (* Begin editing with a blank page, typically a template. *)
+  let begin_editing_new pt =
+    let url, title =
+      match pt with
+         Page url -> url, url
+       | Title title ->
+           match Wikilib.generate_url_of_title dbh hostid title with
+               Wikilib.GenURL_OK url -> url, title
+             | Wikilib.GenURL_Duplicate url ->
+                 q#redirect ("http://" ^ hostname ^ "/" ^ url);
+                 return ()
+             | Wikilib.GenURL_TooShort | Wikilib.GenURL_BadURL ->
+                 error ~back_button:true ~title:"Bad page name"
+                   q "The page name supplied is too short or invalid.";
+                 return () in
+
+    let model = { id = 0;
+                 pt = pt;
+                 description = title;
+                 redirect = "";
+                 contents = [] } in
+
+    model_to_template model template
+  in
+
   let continue_editing () =
     let model = ref (build_internal_model ()) in
 
@@ -338,74 +396,6 @@ let run r (q : cgi) (dbh : Dbi.connection) hostid {hostname = hostname} user =
     if no_errors then (
       (* No errors, so we can save the page ... *)
 
-      (* Pull out fields from the database. *)
-      let sth = dbh#prepare_cached "select creation_date,
-                                           coalesce (url, url_deleted),
-                                           title, css
-                                      from pages
-                                     where hostid = ? and id = ?" in
-      sth#execute [`Int hostid; `Int model.id];
-
-      let creation_date, url, title, css =
-       match sth#fetch1 () with
-           [ creation_date; `String url; `String title; css ] ->
-             creation_date, url, title, css
-         | _ -> assert false in
-
-      (* Has someone else edited this page in the meantime? *)
-      let sth = dbh#prepare_cached "select max(id) from pages
-                                     where hostid = ? and url = ?" in
-      sth#execute [`Int hostid; `String url];
-
-      let max_id = sth#fetch1int () in
-      let edited = max_id <> model.id in
-
-      if edited then (
-       (* Edited by someone else ...  Get the other's changes. *)
-       let other_diff, _ =
-         get_diff dbh hostid url ~old_version:model.id ~version:max_id () in
-
-       (* Synthesize our own changes. *)
-       let old_page = get_version_for_diff dbh model.id in
-       let new_page =
-         let css = match css with
-             `Null -> "" | `String css -> css
-           | _ -> assert false in
-         page_for_diff css (List.map (fun (sectionname, _, content) ->
-                              sectionname, content) model.contents) in
-       let our_diff = diff_cmd old_page new_page in
-
-       (* Fill out the conflict template. *)
-       template_conflict#set "other_diff" other_diff;
-       template_conflict#set "our_diff" our_diff;
-       template_conflict#set "old_version" (string_of_int model.id);
-       template_conflict#set "new_version" (string_of_int max_id);
-       template_conflict#set "url" url;
-
-       q#template template_conflict;
-       return ()
-      );
-
-      (* Defer the pages_redirect_cn constraint because that would
-       * temporarily fail on the next UPDATE.
-       *)
-      let sth =
-       dbh#prepare_cached
-         "set constraints pages_redirect_cn, sitemenu_url_cn,
-               page_emails_url_cn, links_from_cn deferred" in
-      sth#execute [];
-
-      (* Mark the old page as deleted.  NB. There is a small race
-       * condition here because PostgreSQL doesn't do isolation
-       * properly.  If a user tries to visit this page between the
-       * delete and the creation of the new page, then they'll get
-       * a page not found error. (XXX)
-       *)
-      let sth = dbh#prepare_cached "update pages set url_deleted = url,
-                                                     url = null
-                                     where hostid = ? and id = ?" in
-      sth#execute [`Int hostid; `Int model.id];
-
       (* Get the IP address of the user, if available. *)
       let logged_ip =
        try `String (Connection.remote_ip (Request.connection r))
@@ -417,38 +407,207 @@ let run r (q : cgi) (dbh : Dbi.connection) hostid {hostname = hostname} user =
          | _ -> `Null in
 
       (* Get redirect. *)
-      let redirect = if model.redirect = "" then `Null
-                     else `String model.redirect in
-
-      (* Create the new page. *)
-      let sth = dbh#prepare_cached "insert into pages (hostid, url, title,
-                                      description, creation_date, logged_ip,
-                                      logged_user, redirect, css)
-                                    values (?, ?, ?, ?, ?, ?, ?, ?, ?)" in
-      sth#execute [`Int hostid; `String url; `String title;
-                  `String model.description; creation_date; logged_ip;
-                  logged_user; redirect; css];
-
-      (* New page ID <> old page ID model.id. *)
-      let pageid = sth#serial "pages_id_seq" in
-
-      (* Create the page contents. *)
-      let sth = dbh#prepare_cached "insert into contents (pageid,
-                                      ordering, sectionname, divname, content)
-                                    values (?, ?, ?, ?, ?)" in
-      let ordering = ref 0 in          (* Creating new ordering. *)
-      List.iter (fun (sectionname, divname, content) ->
-                  let divname =
-                    if string_is_whitespace divname then `Null
-                    else `String divname in
-                  let sectionname =
-                    if string_is_whitespace sectionname then `Null
-                    else `String sectionname in
-                  incr ordering; let ordering = !ordering in
-                  sth#execute [`Int pageid; `Int ordering;
-                               sectionname; divname;
-                               `String content])
-       model.contents;
+      let redirect =
+       if model.redirect = "" then `Null
+        else `String model.redirect in
+
+      let url, pageid =
+       (* Creating a new page (id = 0)?  If so, we're just going to insert
+        * a new row, which is easy.
+        *)
+       if model.id = 0 then (
+         (* Create the page title or URL. *)
+         let url, title =
+           match model.pt with
+               Page url -> url, url
+             | Title title ->
+                 match Wikilib.generate_url_of_title dbh hostid title with
+                     Wikilib.GenURL_OK url -> url, title
+                   | Wikilib.GenURL_Duplicate url ->
+                       error ~back_button:true ~title:"Page exists"
+                         q ("While you were editing that page, it looks " ^
+                            "like another user created the same page.");
+                       return ()
+                   | _ ->
+                       assert false (* This should have been detected in
+                                     * begin_editing_new.
+                                     *) in
+
+         let sth = dbh#prepare_cached "insert into pages (hostid, url, title,
+                                        description, logged_ip, logged_user,
+                                        redirect)
+                                        values (?, ?, ?, ?, ?, ?, ?)" in
+         sth#execute [`Int hostid; `String url; `String title;
+                      `String model.description; logged_ip; logged_user;
+                      redirect];
+
+         let pageid = sth#serial "pages_id_seq" in
+
+         (* Create the page contents. *)
+         let sth = dbh#prepare_cached "insert into contents (pageid,
+                                        ordering, sectionname, divname,
+                                        content)
+                                        values (?, ?, ?, ?, ?)" in
+         let ordering = ref 0 in       (* Creating new ordering. *)
+         List.iter (fun (sectionname, divname, content) ->
+                      let divname =
+                        if string_is_whitespace divname then `Null
+                        else `String divname in
+                      let sectionname =
+                        if string_is_whitespace sectionname then `Null
+                        else `String sectionname in
+                      incr ordering; let ordering = !ordering in
+                      sth#execute [`Int pageid; `Int ordering;
+                                   sectionname; divname;
+                                   `String content])
+           model.contents;
+
+         url, pageid
+       )
+       (* Otherwise it's an old page which we're updating. *)
+       else (
+         (* Pull out fields from the database. *)
+         let sth = dbh#prepare_cached "select creation_date,
+                                               coalesce (url, url_deleted),
+                                               title, css
+                                          from pages
+                                         where hostid = ? and id = ?" in
+         sth#execute [`Int hostid; `Int model.id];
+
+         let creation_date, url, title, css =
+           match sth#fetch1 () with
+               [ creation_date; `String url; `String title; css ] ->
+                 creation_date, url, title, css
+             | _ -> assert false in
+
+         (* Has someone else edited this page in the meantime? *)
+         let sth = dbh#prepare_cached "select max(id) from pages
+                                         where hostid = ? and url = ?" in
+         sth#execute [`Int hostid; `String url];
+
+         let max_id = sth#fetch1int () in
+         let edited = max_id <> model.id in
+
+         if edited then (
+           (* Edited by someone else ...  Get the other's changes. *)
+           let other_diff, _ =
+             get_diff dbh hostid url
+               ~old_version:model.id ~version:max_id () in
+
+           (* Synthesize our own changes. *)
+           let old_page = get_version_for_diff dbh model.id in
+           let new_page =
+             let css = match css with
+                 `Null -> "" | `String css -> css
+               | _ -> assert false in
+             page_for_diff css (List.map (fun (sectionname, _, content) ->
+                               sectionname, content) model.contents) in
+           let our_diff = diff_cmd old_page new_page in
+
+           (* Fill out the conflict template. *)
+           template_conflict#set "other_diff" other_diff;
+           template_conflict#set "our_diff" our_diff;
+           template_conflict#set "old_version" (string_of_int model.id);
+           template_conflict#set "new_version" (string_of_int max_id);
+           template_conflict#set "url" url;
+
+           q#template template_conflict;
+           return ()
+         );
+
+         (* Defer the pages_redirect_cn constraint because that would
+          * temporarily fail on the next UPDATE.
+          *)
+         let sth =
+           dbh#prepare_cached
+             "set constraints pages_redirect_cn, sitemenu_url_cn,
+                   page_emails_url_cn, links_from_cn deferred" in
+         sth#execute [];
+
+         (* Mark the old page as deleted.  NB. There is a small race
+          * condition here because PostgreSQL doesn't do isolation
+          * properly.  If a user tries to visit this page between the
+          * delete and the creation of the new page, then they'll get
+          * a page not found error. (XXX)
+          *)
+         let sth = dbh#prepare_cached "update pages set url_deleted = url,
+                                                         url = null
+                                         where hostid = ? and id = ?" in
+         sth#execute [`Int hostid; `Int model.id];
+
+         (* Create the new page. *)
+         let sth = dbh#prepare_cached "insert into pages (hostid, url, title,
+                                        description, creation_date, logged_ip,
+                                        logged_user, redirect, css)
+                                        values (?, ?, ?, ?, ?, ?, ?, ?, ?)" in
+         sth#execute [`Int hostid; `String url; `String title;
+                      `String model.description; creation_date; logged_ip;
+                      logged_user; redirect; css];
+
+         (* New page ID <> old page ID model.id. *)
+         let pageid = sth#serial "pages_id_seq" in
+
+         (* Create the page contents. *)
+         let sth = dbh#prepare_cached "insert into contents (pageid,
+                                        ordering, sectionname, divname,
+                                        content)
+                                        values (?, ?, ?, ?, ?)" in
+         let ordering = ref 0 in       (* Creating new ordering. *)
+         List.iter (fun (sectionname, divname, content) ->
+                      let divname =
+                        if string_is_whitespace divname then `Null
+                        else `String divname in
+                      let sectionname =
+                        if string_is_whitespace sectionname then `Null
+                        else `String sectionname in
+                      incr ordering; let ordering = !ordering in
+                      sth#execute [`Int pageid; `Int ordering;
+                                   sectionname; divname;
+                                   `String content])
+           model.contents;
+
+         (* General email notification of page edits.  Send an email to
+          * anyone in the page_emails table who has a confirmed address
+          * and who hasn't received an email already today.
+          *)
+         let sth = dbh#prepare_cached "select email, opt_out from page_emails
+                                         where hostid = ? and url = ?
+                                           and pending is null
+                                           and last_sent < current_date" in
+         sth#execute [`Int hostid; `String url];
+
+         let addrs = sth#map (function [`String email; `String opt_out] ->
+                                email, opt_out
+                                | _ -> assert false) in
+
+         if addrs <> [] then (
+           (* Construct the email. *)
+           template_email#set "hostname" hostname;
+           template_email#set "page" url;
+
+           let subject =
+             "Site notice: " ^ hostname ^ "/" ^ url ^ " has been updated" in
+
+           (* Send each email individually (they all have different opt out
+            * links).
+            *)
+           List.iter (fun (to_addr, opt_out) ->
+                        template_email#set "opt_out" opt_out;
+                        let body = template_email#to_string in
+                        Sendmail.send_mail ~subject
+                          ~to_addr:[to_addr] ~body ())
+             addrs
+         );
+
+         (* Update the database to record when these emails were sent. *)
+         let sth = dbh#prepare_cached "update page_emails
+                                           set last_sent = current_date
+                                         where hostid = ? and url = ?
+                                           and pending is null" in
+         sth#execute [`Int hostid; `String url];
+
+         url, pageid
+       ) in
 
       (* Keep the links table in synch. *)
       Cocanwiki_links.update_links_for_page dbh hostid url;
@@ -467,53 +626,10 @@ let run r (q : cgi) (dbh : Dbi.connection) hostid {hostname = hostname} user =
 
       email_notify ~body ~subject dbh hostid;
 
-      (* General email notification of page edits.  Send an email to
-       * anyone in the page_emails table who has a confirmed address
-       * and who hasn't received an email already today.
-       *)
-      let sth = dbh#prepare_cached "select email, opt_out from page_emails
-                                     where hostid = ? and url = ?
-                                       and pending is null
-                                       and last_sent < current_date" in
-      sth#execute [`Int hostid; `String url];
-
-      let addrs = sth#map (function [`String email; `String opt_out] ->
-                            email, opt_out
-                            | _ -> assert false) in
-
-      if addrs <> [] then (
-       (* Construct the email. *)
-       template_email#set "hostname" hostname;
-       template_email#set "page" url;
-
-       let subject =
-         "Site notice: " ^ hostname ^ "/" ^ url ^ " has been updated" in
-
-       (* Send each email individually (they all have different opt out
-        * links).
-        *)
-       List.iter (fun (to_addr, opt_out) ->
-                    template_email#set "opt_out" opt_out;
-                    let body = template_email#to_string in
-                    Sendmail.send_mail ~subject ~to_addr:[to_addr] ~body ())
-         addrs
-      );
-
-      (* Update the database to record when these emails were sent. *)
-      let sth = dbh#prepare_cached "update page_emails
-                                       set last_sent = current_date
-                                     where hostid = ? and url = ?
-                                       and pending is null" in
-      sth#execute [`Int hostid; `String url];
-
-      dbh#commit ();
-
-      let buttons = [ ok_button ("/" ^ url) ] in
-      ok ~title:"Saved" ~buttons
-        q "The page was saved."
+      (* Redirect back to the URL. *)
+      q#redirect ("http://" ^ hostname ^ "/" ^ url);
+      return ()
     );
-
-    no_errors
   in
 
   let cancel id =
@@ -522,7 +638,8 @@ let run r (q : cgi) (dbh : Dbi.connection) hostid {hostname = hostname} user =
     sth#execute [`Int hostid; `Int id];
     let url = sth#fetch1string () in
 
-    q#redirect ("http://" ^ hostname ^ "/" ^ url)
+    q#redirect ("http://" ^ hostname ^ "/" ^ url);
+    return ()
   in
 
   (* This codes decides where we are in the current editing cycle.
@@ -532,24 +649,33 @@ let run r (q : cgi) (dbh : Dbi.connection) hostid {hostname = hostname} user =
    *   save - if set, then we want to save the page.
    *   cancel - if set, abandon changes and go back to viewing the page.
    *   action_* - one of the action buttons was set, eg. move up/down.
-   *   page - the page URL opened newly for editing.
+   *   page - the page URL opened newly for editing, or a template which
+   *          doesn't yet exist.
+   *   title - page doesn't yet exist; create it.
    *)
-  (try
-     let id = int_of_string (q#param "id") in
-     if q#param_true "cancel" then (
-       cancel id;
-       return ()
-     );
-     if q#param_true "save" then (
-       let ok = try_save () in
-       if ok then return ()            (* ... else fall through *)
-     );
-     continue_editing ()               (* Processes the action, if any. *)
-   with
-       Not_found ->
-        let page = q#param "page" in
-        let page = if page = "" then "index" else page in
-        begin_editing page);
+  let id =
+    try Some (int_of_string (q#param "id")) with Not_found -> None in
+  (match id with
+     | None ->                         (* Begin editing the page. *)
+        if q#param_exists "page" then (
+          let page = q#param "page" in
+          let page = if page = "" then "index" else page in
+          if page_exists page then
+            begin_editing page
+          else
+            begin_editing_new (Page page)
+        ) else (
+          let title = q#param "title" in
+          begin_editing_new (Title title)
+        )
+
+     | Some id ->
+        if q#param_true "cancel" then
+          cancel id;
+        if q#param_true "save" then
+          try_save ();                 (* might fail and fall through ... *)
+        continue_editing ()
+  );
 
   q#template template
 
index b366ae2..8d7b83b 100644 (file)
@@ -1,7 +1,7 @@
 (* COCANWIKI - a wiki written in Objective CAML.
  * Written by Richard W.M. Jones <rich@merjis.com>.
  * Copyright (C) 2004 Merjis Ltd.
- * $Id: wikilib.ml,v 1.8 2004/09/30 14:58:14 rich Exp $
+ * $Id: wikilib.ml,v 1.9 2004/10/09 09:41:39 rich Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -234,7 +234,7 @@ let markup_link dbh hostid link =
          "/" ^ url, "internal", title
        with
            Not_found ->
-             "/_bin/create_form.cmo?title=" ^ escape_url url, "newpage", title
+             "/_bin/edit.cmo?title=" ^ escape_url url, "newpage", title
       ) in
 
     "<a href=\"" ^ url ^
diff --git a/templates/create_form.html b/templates/create_form.html
deleted file mode 100644 (file)
index 07ddc45..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head>
-<title>This page does not exist yet</title>
-<meta name="robots" content="noindex,nofollow"/>
-<meta name="author" content="http://www.merjis.com/" />
-<link rel="stylesheet" href="::theme_css_html_tag::" type="text/css" title="Standard"/>
-<link rel="stylesheet" href="/_css/create.css" type="text/css" title="Standard"/>
-</head><body>
-
-<h1>This page does not exist yet</h1>
-
-<p>
-Here you are being asked to create a new page and create some initial
-content for that page.
-</p>
-
-<form><input type="button" value="&lt;&lt; Go Back"
-             onclick="history.go (-1)"></form>
-
-<hr/>
-
-<form method="post" action="/_bin/create.cmo">
-<input type="hidden" name="title" value="::title_html_tag::"/>
-
-<table id="create">
-<tr>
-<th> Page title: </th>
-<td> ::title_html:: </td>
-</tr>
-<tr>
-<th> Description: </th>
-<td> <input name="description" value="::title_html_tag::" size="60"/> </td>
-</tr>
-<tr>
-<td></td>
-<td> <p class="explanation">
-     (Enter a short description of the page here for search engines
-      and directories to use).</p> </td>
-</tr>
-<tr>
-<td></td>
-<td> <input type="submit" value="Create new page - only do this if you have something to put on this page" /> </td>
-</tr>
-</table>
-
-</form>
-
-<ul id="topmenu" class="menu">
-<li class="first"> <a href="/">Home&nbsp;page</a> </li>
-<li> <a href="/_sitemap">Sitemap</a> </li>
-<li> <a href="/_recent">Recent&nbsp;changes</a> </li>
-</ul>
-
-<div id="menu_div">
-<ul id="bottommenu" class="menu">
-<li class="first"> <a href="/">Home&nbsp;page</a> </li>
-::table(sitemenu)::<li> <a href="/::url_html_tag::">::label_html::</a> </li>
-::end::
-<li> <a href="/_sitemap">Sitemap</a> </li>
-</ul>
-</div>
-
-<div id="footer_div">
-<hr/>
-
-<ul id="footer" class="menu">
-<li class="first"> <a href="/copyright">Copyright &copy; ::year::</a> </li>
-<li> Powered by <a href="http://sandbox.merjis.com/">::cocanwiki_package_html:: ::cocanwiki_version_html::</a> </li>
-</ul>
-</div>
-
-</body>
-</html>
\ No newline at end of file
index 8aa5a14..6209ef5 100644 (file)
 
 <h1>::title_html:: [edit]</h1>
 
-<form method="post" action="edit">
+<form method="post" action="">
 <input type="hidden" name="id" value="::id::"/>
+<input type="hidden" name="pt_type" value="::pt_type::"/>
+<input type="hidden" name="pt_value" value="::pt_value_html_tag::"/>
 
 <p>
 Description:
@@ -29,7 +31,6 @@ Redirect to (if given, page contents are ignored):
 
 ::if(has_errors)::
 <div id="errors">
-<p><strong>Errors:</strong></p>
 <ul>
 ::table(errors)::<li>::error_html::</li>
 ::end::</ul>