From 4bc6c4992dbf48fce59efc39cd31f97f03291383 Mon Sep 17 00:00:00 2001 From: rich Date: Sat, 9 Oct 2004 09:41:38 +0000 Subject: [PATCH 1/1] One-step create & edit. --- scripts/.depend | 18 +- scripts/Makefile | 4 +- scripts/create.ml | 97 ---------- scripts/create_form.ml | 56 ------ scripts/edit.ml | 470 ++++++++++++++++++++++++++++----------------- scripts/wikilib.ml | 4 +- templates/create_form.html | 74 ------- templates/edit.html | 5 +- 8 files changed, 308 insertions(+), 420 deletions(-) delete mode 100644 scripts/create.ml delete mode 100644 scripts/create_form.ml delete mode 100644 templates/create_form.html diff --git a/scripts/.depend b/scripts/.depend index dd737e6..4362d17 100644 --- a/scripts/.depend +++ b/scripts/.depend @@ -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 diff --git a/scripts/Makefile b/scripts/Makefile index bb56bd0..2a4c710 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -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 index 4b4caa6..0000000 --- a/scripts/create.ml +++ /dev/null @@ -1,97 +0,0 @@ -(* COCANWIKI - a wiki written in Objective CAML. - * Written by Richard W.M. Jones . - * 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 index 990cfc0..0000000 --- a/scripts/create_form.ml +++ /dev/null @@ -1,56 +0,0 @@ -(* COCANWIKI - a wiki written in Objective CAML. - * Written by Richard W.M. Jones . - * 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 diff --git a/scripts/edit.ml b/scripts/edit.ml index 0a07c46..3edce8c 100644 --- a/scripts/edit.ml +++ b/scripts/edit.ml @@ -1,7 +1,7 @@ (* COCANWIKI - a wiki written in Objective CAML. * Written by Richard W.M. Jones . * 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 diff --git a/scripts/wikilib.ml b/scripts/wikilib.ml index b366ae2..8d7b83b 100644 --- a/scripts/wikilib.ml +++ b/scripts/wikilib.ml @@ -1,7 +1,7 @@ (* COCANWIKI - a wiki written in Objective CAML. * Written by Richard W.M. Jones . * 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 " - - -This page does not exist yet - - - - - - -

This page does not exist yet

- -

-Here you are being asked to create a new page and create some initial -content for that page. -

- -
- -
- -
- - - - - - - - - - - - - - - - - - - -
Page title: ::title_html::
Description:

- (Enter a short description of the page here for search engines - and directories to use).

- -
- -
- - - - - - - \ No newline at end of file diff --git a/templates/edit.html b/templates/edit.html index 8aa5a14..6209ef5 100644 --- a/templates/edit.html +++ b/templates/edit.html @@ -11,8 +11,10 @@

::title_html:: [edit]

-
+ + +

Description: @@ -29,7 +31,6 @@ Redirect to (if given, page contents are ignored): ::if(has_errors)::

-

Errors:

    ::table(errors)::
  • ::error_html::
  • ::end::
-- 1.8.3.1