Added <meta keywords> on pages.
[cocanwiki.git] / scripts / lib / cocanwiki_diff.ml
1 (* COCANWIKI - a wiki written in Objective CAML.
2  * Written by Richard W.M. Jones <rich@merjis.com>.
3  * Copyright (C) 2004 Merjis Ltd.
4  * $Id: cocanwiki_diff.ml,v 1.7 2006/08/04 12:45:33 rich Exp $
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; see the file COPYING.  If not, write to
18  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *)
21
22 open Apache
23 open Registry
24 open Cgi
25 open Printf
26
27 open Cocanwiki_pages
28 open Cocanwiki_files
29 open Cocanwiki
30
31 (* Convenience code for generating diffs between versions.  See diff.ml
32  * and edit.ml which both use this code.
33  *)
34 let page_for_diff model css =
35   let title_or_url = match model.pt with Page t -> t | Title t -> t in
36   "Title or URL: " ^ title_or_url ^ "\n" ^
37   "Description: " ^ model.description ^ "\n\n" ^
38   (match model.keywords with
39    | None -> ""
40    | Some keywords -> "Keywords: " ^ keywords ^ "\n\n") ^
41   (match model.redirect with
42    | None -> ""
43    | Some redirect -> "Redirect: " ^ redirect ^ "\n\n") ^
44   (String.concat ""
45      (List.map (
46         fun (sectionname, divname, jsgo, content) ->
47           (match sectionname with
48            | None -> ""
49            | Some sectionname -> "HEADING: " ^ sectionname ^ "\n\n") ^
50           content ^ "\n\n" ^
51           (match divname with
52            | None -> ""
53            | Some divname -> "CSS Id: " ^ divname ^ "\n") ^
54           (match jsgo with
55            | None -> ""
56            | Some jsgo -> "Javascript Onclick: " ^ jsgo ^ "\n") ^
57           "\n"
58       ) model.contents_)
59   ) ^
60   (match css with
61    | None -> ""
62    | Some css -> "CSS:\n\n" ^ css ^ "\n")
63
64 let le_re = Pcre.regexp "\r?\n"
65 let le_subst = Pcre.subst "\n"
66
67 let diff_cmd old_page new_page =
68   (* Convert line-endings in the input files from \r\n to \n.  Diff
69    * can get confused by the \r characters, particularly in side-by-side
70    * mode when asked to expand tabs (-y -t).
71    *)
72   let f = Pcre.replace ~rex:le_re ~itempl:le_subst in
73   let new_page = f new_page in
74   let old_page = f old_page in
75
76   let new_filename = output_tempfile new_page in
77   let old_filename = output_tempfile old_page in
78
79   (* Side-by-side mode was good, but stupidly implemented.  It's
80    * disabled right now.
81    *)
82   let diff_sidebyside = false in
83
84   let options =
85     if not diff_sidebyside then
86       "-u"
87     else
88       "-y --left-column" in
89   let options = options ^ " -t -b -B" in
90
91   let cmd = sprintf "diff %s %s %s ||:" options old_filename new_filename in
92   let diff = pget cmd in
93
94   (* Remove the temporary files. *)
95   unlink new_filename; unlink old_filename;
96
97   let diff =
98     if not diff_sidebyside then
99       match diff with
100           _ :: _ :: diff -> diff
101         | diff -> diff
102     else diff in
103
104   String.concat "\n" diff
105
106 let get_version_for_diff dbh version =
107   if version = 0l then ""
108   else (
109     let title, description, keywords, redirect, css = List.hd (
110       PGSQL(dbh)
111         "select title, description, keywords, redirect, css from pages
112           where id = $version"
113     ) in
114
115     let contents_ = PGSQL(dbh)
116       "select sectionname, divname, jsgo, content
117          from contents where pageid = $version
118         order by ordering" in
119
120     let model = { id = version;
121                   pt = Title title;
122                   description = description;
123                   keywords = keywords;
124                   redirect = redirect;
125                   contents_ = contents_ } in
126
127     let page = page_for_diff model css in
128
129     page
130   )
131
132 let get_diff dbh hostid page ?old_version ~version ()=
133   let old_version =
134     match old_version with
135       | Some version -> version
136       | None ->
137           try
138             List.hd (
139               PGSQL(dbh)
140                 "select id from pages
141                   where hostid = $hostid
142                     and url_deleted = $page
143                     and id < $version
144                   order by 1 desc limit 1"
145             )
146           with
147             Not_found | ExtList.List.Empty_list | Failure "hd" -> 0l in
148
149   (* Get the two versions. *)
150   let new_page = get_version_for_diff dbh version in
151   let old_page = get_version_for_diff dbh old_version in
152
153   (* Compute the diff of the two versions. *)
154   let diff = diff_cmd old_page new_page in
155   diff, old_version