- 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;