Index: trunk/extensions/WikiTrust/analysis/wikipedia_api.ml |
— | — | @@ -1,193 +0,0 @@ |
2 | | -(* |
3 | | - |
4 | | -Copyright (c) 2007-2008 The Regents of the University of California |
5 | | -All rights reserved. |
6 | | - |
7 | | -Authors: Luca de Alfaro, Ian Pye |
8 | | - |
9 | | -Redistribution and use in source and binary forms, with or without |
10 | | -modification, are permitted provided that the following conditions are met: |
11 | | - |
12 | | -1. Redistributions of source code must retain the above copyright notice, |
13 | | -this list of conditions and the following disclaimer. |
14 | | - |
15 | | -2. Redistributions in binary form must reproduce the above copyright notice, |
16 | | -this list of conditions and the following disclaimer in the documentation |
17 | | -and/or other materials provided with the distribution. |
18 | | - |
19 | | -3. The names of the contributors may not be used to endorse or promote |
20 | | -products derived from this software without specific prior written |
21 | | -permission. |
22 | | - |
23 | | -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
24 | | -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
25 | | -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
26 | | -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
27 | | -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
28 | | -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
29 | | -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
30 | | -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
31 | | -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
32 | | -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
33 | | -POSSIBILITY OF SUCH DAMAGE. |
34 | | - |
35 | | - *) |
36 | | - |
37 | | -(* Using the wikipedia API, retrieves information about pages and revisions *) |
38 | | - |
39 | | -open Http_client;; |
40 | | -open ExtLib;; |
41 | | -open Gzip;; |
42 | | -open Xml;; |
43 | | -open Online_types;; |
44 | | -open Str;; |
45 | | - |
46 | | -exception Http_client_error |
47 | | - |
48 | | -Random.self_init () |
49 | | - |
50 | | -let pipeline = new pipeline |
51 | | -let buf_len = 8192 |
52 | | -let requested_encoding_type = "gzip" |
53 | | -let tmp_prefix = "wiki" |
54 | | -let rev_lim = "50" |
55 | | -let api_tz_re = Str.regexp "\\([0-9][0-9][0-9][0-9]\\)-\\([0-9][0-9]\\)-\\([0-9][0-9]\\)T\\([0-9][0-9]\\):\\([0-9][0-9]\\):\\([0-9][0-9]\\)Z" |
56 | | - |
57 | | -(* Maps the Wikipedias api timestamp to our internal one. *) |
58 | | -let api_ts2mw_ts s = |
59 | | - let ts = if string_match api_tz_re s 0 then |
60 | | - (matched_group 1 s) ^ (matched_group 2 s) ^ (matched_group 3 s) |
61 | | - ^ (matched_group 4 s) ^ (matched_group 5 s) ^ (matched_group 6 s) |
62 | | - else "19700201000000" in |
63 | | - ts |
64 | | - |
65 | | -(* Given an input channel, return a string representing all there is |
66 | | - to be read of this channel. *) |
67 | | -let input_all ic = |
68 | | - let rec loop acc total buf ofs = |
69 | | - let n = input ic buf ofs (buf_len - ofs) in |
70 | | - if n = 0 then |
71 | | - let res = String.create total in |
72 | | - let pos = total - ofs in |
73 | | - let _ = String.blit buf 0 res pos ofs in |
74 | | - let coll pos buf = |
75 | | - let new_pos = pos - buf_len in |
76 | | - String.blit buf 0 res new_pos buf_len; |
77 | | - new_pos in |
78 | | - let _ = List.fold_left coll pos acc in |
79 | | - res |
80 | | - else |
81 | | - let new_ofs = ofs + n in |
82 | | - let new_total = total + n in |
83 | | - if new_ofs = buf_len then |
84 | | - loop (buf :: acc) new_total (String.create buf_len) 0 |
85 | | - else loop acc new_total buf new_ofs in |
86 | | - loop [] 0 (String.create buf_len) 0 |
87 | | - |
88 | | -(* |
89 | | - Given a string url, make a get call and return the response as a string. |
90 | | -*) |
91 | | -let run_call url = |
92 | | - let call = new get url in |
93 | | - let request_header = call # request_header `Base in |
94 | | - (* Accept gziped format *) |
95 | | - request_header # update_field "Accept-encoding" requested_encoding_type; |
96 | | - call # set_request_header request_header; |
97 | | - pipeline # add call; |
98 | | - pipeline # run(); |
99 | | - match call # status with |
100 | | - | `Successful -> ( |
101 | | - let body = call # response_body # value in |
102 | | - let repsponse_header = call # response_header in |
103 | | - Printf.printf "content_type: %s\n" |
104 | | - (let cnt,_ = (repsponse_header # content_type ()) in cnt); |
105 | | - match (repsponse_header # content_type ()) with |
106 | | - | ("text/xml",_) -> ( |
107 | | - let tmp_file = Tmpfile.new_tmp_file_name tmp_prefix in |
108 | | - Std.output_file ~filename:tmp_file ~text:body; |
109 | | - let in_chan = Gzip.open_in tmp_file in |
110 | | - let decoded_body = input_all in_chan in |
111 | | - Gzip.close_in in_chan; |
112 | | - Tmpfile.remove_tmp_file tmp_file; |
113 | | - decoded_body |
114 | | - ) |
115 | | - | _ -> body |
116 | | - ) |
117 | | - | _ -> raise Http_client_error |
118 | | -;; |
119 | | - |
120 | | -(* |
121 | | - Internal xml processing for the api |
122 | | -*) |
123 | | -let process_rev (rev : xml) : wiki_revision = |
124 | | - let w_rev = { |
125 | | - revision_id = int_of_string (Xml.attrib rev "revid"); |
126 | | - revision_page = 0; |
127 | | - revision_text_id = int_of_string (Xml.attrib rev "revid"); |
128 | | - revision_comment = (try (Xml.attrib rev "comment") |
129 | | - with Xml.No_attribute e -> ""); |
130 | | - revision_user = -1; |
131 | | - revision_user_text = (Xml.attrib rev "user"); |
132 | | - revision_timestamp = api_ts2mw_ts (Xml.attrib rev "timestamp"); |
133 | | - revision_minor_edit = (try ignore(Xml.attrib rev "minor"); true |
134 | | - with Xml.No_attribute e -> false); |
135 | | - revision_deleted = false; |
136 | | - revision_len = (try int_of_string (Xml.attrib rev "size") with Xml.No_attribute e -> 0); |
137 | | - revision_parent_id = 0; |
138 | | - revision_content = (Netencoding.Html.decode ~in_enc:`Enc_utf8 |
139 | | - ~out_enc:`Enc_utf8 () |
140 | | - (Xml.to_string (List.hd (Xml.children rev)))); |
141 | | - } in |
142 | | - w_rev |
143 | | - |
144 | | -(* |
145 | | - Internal xml processing for the api |
146 | | -*) |
147 | | -let process_page (page : xml) : (wiki_page option * wiki_revision list) = |
148 | | - let w_page = { |
149 | | - page_id = int_of_string (Xml.attrib page "pageid"); |
150 | | - page_namespace = (int_of_string (Xml.attrib page "ns")); |
151 | | - page_title = (Xml.attrib page "title"); |
152 | | - page_restrictions = ""; |
153 | | - page_counter = int_of_string (Xml.attrib page "counter"); |
154 | | - page_is_redirect = (try ignore(Xml.attrib page "redirect"); true |
155 | | - with Xml.No_attribute e -> false); |
156 | | - page_is_new = false; |
157 | | - page_random = (Random.float 1.0); |
158 | | - page_touched = api_ts2mw_ts (Xml.attrib page "touched"); |
159 | | - page_latest = int_of_string (Xml.attrib page "lastrevid"); |
160 | | - page_len = int_of_string (Xml.attrib page "length") |
161 | | - } in |
162 | | - let revs = Xml.children page in |
163 | | - (Some w_page, (Xml.map process_rev (List.hd revs))) |
164 | | - |
165 | | -(* |
166 | | - Given a page and date to start with, returns the next n revs for this page. |
167 | | -*) |
168 | | -let fetch_page_and_revs_after (page_title : string) (rev_date : string) : (wiki_page option * wiki_revision list) = |
169 | | - let url = !Online_command_line.target_wikimedia |
170 | | - ^ "?action=query&prop=revisions|" |
171 | | - ^ "info&format=xml&inprop=&rvprop=ids|flags|timestamp|user|size|comment|" |
172 | | - ^ "content&rvstart=" ^ rev_date ^ "&rvlimit=" ^ rev_lim |
173 | | - ^ "&rvdir=newer&titles=" ^ page_title in |
174 | | - if !Online_command_line.dump_db_calls then Printf.printf "%s\n" url; |
175 | | - let res = run_call url in |
176 | | - let api = Xml.parse_string res in |
177 | | - let query = Xml.children (api) in |
178 | | - let poss_pages = Xml.children (List.hd query) in |
179 | | - let pick_page acc page = |
180 | | - if (Xml.tag page = "pages") then |
181 | | - process_page (List.hd (Xml.children page)) |
182 | | - else acc |
183 | | - in |
184 | | - List.fold_left pick_page (None,[]) poss_pages |
185 | | -;; |
186 | | - |
187 | | -(* Given a user_name, returns the corresponding user_id *) |
188 | | -let get_user_id (user_name : string) : int = |
189 | | - let url = !Online_command_line.user_id_server ^ "?n=" ^ user_name in |
190 | | - if !Online_command_line.dump_db_calls then Printf.printf "%s\n" url; |
191 | | - let uids = ExtString.String.nsplit (run_call url) "`" in |
192 | | - let uid = List.nth uids 1 in |
193 | | - try int_of_string uid with int_of_string -> 0 in |
194 | | -;; |
Index: trunk/extensions/WikiTrust/analysis/tmpfile.ml |
— | — | @@ -1,37 +0,0 @@ |
2 | | -(***********************************************************************) |
3 | | -(* *) |
4 | | -(* Objective Caml *) |
5 | | -(* *) |
6 | | -(* Fran�ois Pessaux, projet Cristal, INRIA Rocquencourt *) |
7 | | -(* Pierre Weis, projet Cristal, INRIA Rocquencourt *) |
8 | | -(* Jun Furuse, projet Cristal, INRIA Rocquencourt *) |
9 | | -(* *) |
10 | | -(* Copyright 1999 - 2003 *) |
11 | | -(* Institut National de Recherche en Informatique et en Automatique. *) |
12 | | -(* Distributed only by permission. *) |
13 | | -(* *) |
14 | | -(***********************************************************************) |
15 | | - |
16 | | -(* temporary directory *) |
17 | | -let tmp_dir = ref (try Sys.getenv "CAMLTMPDIR" with Not_found -> "/tmp");; |
18 | | - |
19 | | -let cnter = ref 0;; |
20 | | - |
21 | | -let rec new_tmp_name prefx = |
22 | | - incr cnter; |
23 | | - let name = |
24 | | - Filename.concat !tmp_dir |
25 | | - (Printf.sprintf "camltmp-%s-%d" prefx !cnter) in |
26 | | - if not (Sys.file_exists name) then name else begin |
27 | | - prerr_endline ("Warning: tmp file " ^ name ^ " already exists"); |
28 | | - new_tmp_name prefx |
29 | | - end;; |
30 | | - |
31 | | -let remove_tmp_file tmpfile = try Sys.remove tmpfile with _ -> ();; |
32 | | - |
33 | | -let new_tmp_file_name prefx = |
34 | | - if not (Sys.file_exists !tmp_dir) then |
35 | | - failwith ("Temporary directory " ^ !tmp_dir ^ " does not exist") else |
36 | | - let f = new_tmp_name prefx in |
37 | | - at_exit (fun () -> remove_tmp_file f); |
38 | | - f;; |
Index: trunk/extensions/WikiTrust/analysis/server.ml |
— | — | @@ -1,235 +0,0 @@ |
2 | | -(* This is a webserver built from the Netplex and Nethttpd components. |
3 | | - * It is configured in the netplex.cfg file. |
4 | | - * Note: start program with option "-conf netplex.cfg" |
5 | | - * The basic code is copied from the nethttpd example. |
6 | | - *) |
7 | | - |
8 | | -open Netcgi1_compat.Netcgi_types;; |
9 | | -open Printf;; |
10 | | -open Mysql;; |
11 | | -open Online_db;; |
12 | | -open Online_command_line;; |
13 | | -open Gzip;; |
14 | | - |
15 | | -let tmp_prefix = "wiki-com" |
16 | | -let not_found_text_token = "TEXT_NOT_FOUND" |
17 | | -let sleep_time_sec = 3 |
18 | | - |
19 | | -let dbh = ref None |
20 | | - |
21 | | -let text = Netencoding.Html.encode_from_latin1;; |
22 | | -(* This function encodes "<", ">", "&", double quotes, and Latin 1 characters |
23 | | - * as character entities. E.g. text "<" = "<", and text "�" = "ä" |
24 | | - *) |
25 | | - |
26 | | -let compress_str raw = |
27 | | - let tmp_file = Tmpfile.new_tmp_file_name tmp_prefix in |
28 | | - let out = Gzip.open_out tmp_file in |
29 | | - Gzip.output out raw 0 (String.length raw); |
30 | | - Gzip.close_out out; |
31 | | - let compressed = Std.input_file ?bin:(Some true) tmp_file in |
32 | | - Tmpfile.remove_tmp_file tmp_file; |
33 | | - compressed |
34 | | -;; |
35 | | - |
36 | | -let handle_missing_rev (rev_id : int) (page_id : int) (page_title : string) |
37 | | - (rev_time : string) (user_id : int) = |
38 | | - match !dbh with |
39 | | - | Some db -> ( |
40 | | - db # mark_to_color rev_id page_id page_title rev_time user_id; |
41 | | - Unix.sleep sleep_time_sec; |
42 | | - try (db # read_colored_markup_with_median rev_id) with |
43 | | - | Online_db.DB_Not_Found -> (not_found_text_token,1.0) |
44 | | - ) |
45 | | - | None -> ("DB not initialized",1.0) |
46 | | - |
47 | | -(* Return colored markup *) |
48 | | -let generate_text_page (cgi : Netcgi.cgi_activation) (rev_id : int) |
49 | | - (page_id : int) (page_title : string) (rev_time : string) (user_id : int) |
50 | | - = |
51 | | - let out = cgi # out_channel # output_string in |
52 | | - let safe_page_title = Mysql.escape page_title in |
53 | | - let safe_rev_time = Mysql.escape rev_time in |
54 | | - match !dbh with |
55 | | - | Some db -> ( |
56 | | - let (colored_text,median) = |
57 | | - try (db # read_colored_markup_with_median rev_id) |
58 | | - with Online_db.DB_Not_Found -> (handle_missing_rev rev_id page_id |
59 | | - safe_page_title safe_rev_time |
60 | | - user_id) |
61 | | - in |
62 | | - if colored_text != not_found_text_token then |
63 | | - let compressed = compress_str ((string_of_float median) ^ |
64 | | - "," ^ colored_text) in |
65 | | - cgi # set_header |
66 | | - ~content_type:"application/x-gzip" |
67 | | - ~content_length:(String.length compressed) |
68 | | - (); |
69 | | - out compressed |
70 | | - else |
71 | | - out colored_text |
72 | | - ) |
73 | | - | None -> out "DB not initialized" |
74 | | -;; |
75 | | - |
76 | | -(* Return information about an incorrect request. *) |
77 | | -let generate_help_page (cgi : Netcgi.cgi_activation) = |
78 | | - let out = cgi # out_channel # output_string in |
79 | | - out not_found_text_token |
80 | | -;; |
81 | | - |
82 | | -(* Record that a vote happened. *) |
83 | | -let generate_vote_page (cgi : Netcgi.cgi_activation) (rev_id : int) |
84 | | - (page_id : int) (user_id : int) (v_time : string) (page_title : string) = |
85 | | - let out = cgi # out_channel # output_string in |
86 | | - let safe_page_title = Mysql.escape page_title in |
87 | | - match !dbh with |
88 | | - | Some db -> ( |
89 | | - let vote = { |
90 | | - vote_time=(Mysql.escape v_time); |
91 | | - vote_page_id=page_id; |
92 | | - vote_revision_id=rev_id; |
93 | | - vote_voter_id=user_id; |
94 | | - } in |
95 | | - let res = try (db # vote vote; |
96 | | - db # mark_to_color rev_id page_id safe_page_title |
97 | | - (Mysql.escape v_time) user_id; |
98 | | - "good") with |
99 | | - Online_db.DB_TXN_Bad -> "bad" in |
100 | | - out res |
101 | | - ) |
102 | | - | None -> out "DB not initialized" |
103 | | -;; |
104 | | - |
105 | | -let generate_page (cgi : Netcgi.cgi_activation) = |
106 | | - (* Check which page is to be displayed. This is contained in the CGI |
107 | | - * argument "page". |
108 | | - *) |
109 | | - |
110 | | - let page_id = try (int_of_string (cgi # argument_value "page")) |
111 | | - with int_of_string -> -1 in |
112 | | - let rev_id = try (int_of_string (cgi # argument_value "rev")) |
113 | | - with int_of_string -> -1 in |
114 | | - let page_title = (cgi # argument_value "page_title") in |
115 | | - let time_str = (cgi # argument_value "time") in |
116 | | - let user_id = try (int_of_string (cgi # argument_value "user")) |
117 | | - with int_of_string -> 0 in |
118 | | - match cgi # argument_value "vote" with |
119 | | - | "" -> ( |
120 | | - if rev_id < 0 || page_id < 0 then generate_help_page cgi else |
121 | | - generate_text_page cgi rev_id page_id page_title time_str |
122 | | - user_id |
123 | | - ) |
124 | | - | _ -> ( |
125 | | - generate_vote_page cgi rev_id page_id user_id time_str page_title |
126 | | - ) |
127 | | -;; |
128 | | - |
129 | | -let process2 (cgi : Netcgi.cgi_activation) = |
130 | | - (* The [try] block catches errors during the page generation. *) |
131 | | - try |
132 | | - (* Set the header. The header specifies that the page must not be |
133 | | - * cached. This is important for dynamic pages called by the GET |
134 | | - * method, otherwise the browser might display an old version of |
135 | | - * the page. |
136 | | - * Furthermore, we set the content type and the character set. |
137 | | - * Note that the header is not sent immediately to the browser because |
138 | | - * we have enabled HTML buffering. |
139 | | - *) |
140 | | - cgi # set_header |
141 | | - ~cache:`No_cache |
142 | | - ~content_type:"text/plain; charset=\"iso-8859-1\"" |
143 | | - (); |
144 | | - |
145 | | - generate_page cgi; |
146 | | - |
147 | | - (* After the page has been fully generated, we can send it to the |
148 | | - * browser. |
149 | | - *) |
150 | | - cgi # out_channel # commit_work(); |
151 | | - with |
152 | | - error -> |
153 | | - (* An error has happened. Generate now an error page instead of |
154 | | - * the current page. By rolling back the output buffer, any |
155 | | - * uncomitted material is deleted. |
156 | | - *) |
157 | | - cgi # out_channel # rollback_work(); |
158 | | - |
159 | | - (* We change the header here only to demonstrate that this is |
160 | | - * possible. |
161 | | - *) |
162 | | - cgi # set_header |
163 | | - ~status:`Forbidden (* Indicate the error *) |
164 | | - ~cache:`No_cache |
165 | | - ~content_type:"text/plain; charset=\"iso-8859-1\"" |
166 | | - (); |
167 | | - |
168 | | - cgi # out_channel # output_string "While processing the request an O'Caml exception has been raised:\n"; |
169 | | - cgi # out_channel # output_string ("" ^ text(Printexc.to_string error) ^ "\n"); |
170 | | - |
171 | | - (* Now commit the error page: *) |
172 | | - cgi # out_channel # commit_work() |
173 | | -;; |
174 | | - |
175 | | - |
176 | | -let process1 (cgi : Netcgi1_compat.Netcgi_types.cgi_activation) = |
177 | | - let cgi' = Netcgi1_compat.Netcgi_types.of_compat_activation cgi in |
178 | | - process2 cgi' |
179 | | - |
180 | | - |
181 | | -(**********************************************************************) |
182 | | -(* Create the webserver *) |
183 | | -(**********************************************************************) |
184 | | - |
185 | | - |
186 | | -let start() = |
187 | | - let (opt_list, cmdline_cfg) = Netplex_main.args() in |
188 | | - |
189 | | - let use_mt = ref false in |
190 | | - |
191 | | - let opt_list' = |
192 | | - [ ("-mt", Arg.Set use_mt, |
193 | | - " Use multi-threading instead of multi-processing"); |
194 | | - ] @ (command_line_format @ opt_list) in |
195 | | - |
196 | | - Arg.parse |
197 | | - opt_list' |
198 | | - (fun s -> raise (Arg.Bad ("Don't know what to do with: " ^ s))) |
199 | | - "usage: netplex [options]"; |
200 | | - |
201 | | - (* Prepares the database connection information *) |
202 | | - let mediawiki_db = { |
203 | | - dbhost = Some !mw_db_host; |
204 | | - dbname = Some !mw_db_name; |
205 | | - dbport = Some !mw_db_port; |
206 | | - dbpwd = Some !mw_db_pass; |
207 | | - dbuser = Some !mw_db_user; |
208 | | - } in |
209 | | - dbh := Some (new Online_db.db !db_prefix mediawiki_db None !dump_db_calls); |
210 | | - |
211 | | - let parallelizer = |
212 | | - if !use_mt then |
213 | | - Netplex_mt.mt() (* multi-threading *) |
214 | | - else |
215 | | - Netplex_mp.mp() in (* multi-processing *) |
216 | | - let trust_store = |
217 | | - { Nethttpd_services.dyn_handler = (fun _ -> process1); |
218 | | - dyn_activation = Nethttpd_services.std_activation `Std_activation_buffered; |
219 | | - dyn_uri = None; (* not needed *) |
220 | | - dyn_translator = (fun _ -> ""); (* not needed *) |
221 | | - dyn_accept_all_conditionals = false; |
222 | | - } in |
223 | | - let nethttpd_factory = |
224 | | - Nethttpd_plex.nethttpd_factory |
225 | | - ~handlers:[ "trust", trust_store ] |
226 | | - () in |
227 | | - Netplex_main.startup |
228 | | - parallelizer |
229 | | - Netplex_log.logger_factories (* allow all built-in logging styles *) |
230 | | - Netplex_workload.workload_manager_factories (* ... all ways of workload management *) |
231 | | - [ nethttpd_factory ] (* make this nethttpd available *) |
232 | | - cmdline_cfg |
233 | | -;; |
234 | | - |
235 | | -Sys.set_signal Sys.sigpipe Sys.Signal_ignore; |
236 | | -start();; |
Index: trunk/extensions/WikiTrust/analysis/server_coloring_dispatcher.ml |
— | — | @@ -1,257 +0,0 @@ |
2 | | -(* |
3 | | - |
4 | | -Copyright (c) 2007-2008 The Regents of the University of California |
5 | | -All rights reserved. |
6 | | - |
7 | | -Authors: Luca de Alfaro, Ian Pye |
8 | | - |
9 | | -Redistribution and use in source and binary forms, with or without |
10 | | -modification, are permitted provided that the following conditions are met: |
11 | | - |
12 | | -1. Redistributions of source code must retain the above copyright notice, |
13 | | -this list of conditions and the following disclaimer. |
14 | | - |
15 | | -2. Redistributions in binary form must reproduce the above copyright notice, |
16 | | -this list of conditions and the following disclaimer in the documentation |
17 | | -and/or other materials provided with the distribution. |
18 | | - |
19 | | -3. The names of the contributors may not be used to endorse or promote |
20 | | -products derived from this software without specific prior written |
21 | | -permission. |
22 | | - |
23 | | -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
24 | | -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
25 | | -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
26 | | -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
27 | | -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
28 | | -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
29 | | -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
30 | | -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
31 | | -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
32 | | -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
33 | | -POSSIBILITY OF SUCH DAMAGE. |
34 | | - |
35 | | - *) |
36 | | - |
37 | | -(* Figures out which pages to update, and starts them going. *) |
38 | | - |
39 | | -open Printf |
40 | | -open Mysql |
41 | | -open Unix |
42 | | -open Online_command_line |
43 | | -open Wikipedia_api |
44 | | -open Online_db |
45 | | -open Online_types |
46 | | - |
47 | | -let max_concurrent_procs = 10 |
48 | | -let sleep_time_sec = 1 |
49 | | -let custom_line_format = [] @ command_line_format |
50 | | - |
51 | | -let _ = Arg.parse custom_line_format noop "Usage: dispatcher";; |
52 | | - |
53 | | -let working_children = Hashtbl.create max_concurrent_procs |
54 | | - |
55 | | -(* Prepares the database connection information *) |
56 | | -let mediawiki_db = { |
57 | | - dbhost = Some !mw_db_host; |
58 | | - dbname = Some !mw_db_name; |
59 | | - dbport = Some !mw_db_port; |
60 | | - dbpwd = Some !mw_db_pass; |
61 | | - dbuser = Some !mw_db_user; |
62 | | -} |
63 | | - |
64 | | -(* Here begins the sequential code *) |
65 | | -let db = new Online_db.db !db_prefix mediawiki_db None !dump_db_calls in |
66 | | -let logger = new Online_log.logger !log_name !synch_log in |
67 | | -let n_processed_events = ref 0 in |
68 | | -let trust_coeff = Online_types.get_default_coeff in |
69 | | - |
70 | | -(* There are two types of throttle delay: a second each time we are multiples of an int, |
71 | | - or a number of seconds before each revision. *) |
72 | | -let each_event_delay = int_of_float !color_delay in |
73 | | -let every_n_events_delay = |
74 | | - let frac = !color_delay -. (floor !color_delay) in |
75 | | - if frac > 0.001 |
76 | | - then Some (max 1 (int_of_float (1. /. frac))) |
77 | | - else None |
78 | | -in |
79 | | - |
80 | | -(* Wait for the processes to stop before accepting more *) |
81 | | -let clean_kids k v = ( |
82 | | - let stat = Unix.waitpid [WNOHANG] v in |
83 | | - match (stat) with |
84 | | - | (0,_) -> () (* Process not yet done. *) |
85 | | - | (_, WEXITED s) -> Hashtbl.remove working_children k (* Otherwise, remove the process. *) |
86 | | - | (_, WSIGNALED s) -> Hashtbl.remove working_children k |
87 | | - | (_, WSTOPPED s) -> Hashtbl.remove working_children k |
88 | | -) in |
89 | | - |
90 | | -(* This is the function that evaluates a revision. |
91 | | - The function is recursive, because if some past revision of the same page |
92 | | - that falls within the analysis horizon is not yet evaluated and colored |
93 | | - for trust, it evaluates and colors it first. |
94 | | - *) |
95 | | -let rec evaluate_revision (page_id: int) (rev_id: int): unit = |
96 | | - if !n_processed_events < !max_events_to_process then |
97 | | - begin |
98 | | - begin (* try ... with ... *) |
99 | | - try |
100 | | - Printf.printf "Evaluating revision %d of page %d\n" rev_id page_id; |
101 | | - let page = new Online_page.page db logger page_id rev_id trust_coeff !times_to_retry_trans in |
102 | | - n_processed_events := !n_processed_events + 1; |
103 | | - if page#eval then begin |
104 | | - Printf.printf "Done revision %d of page %d\n" rev_id page_id; |
105 | | - end else begin |
106 | | - Printf.printf "Revision %d of page %d was already done\n" rev_id page_id; |
107 | | - end; |
108 | | - (* Waits, if so requested to throttle the computation. *) |
109 | | - if each_event_delay > 0 then Unix.sleep (each_event_delay); |
110 | | - begin |
111 | | - match every_n_events_delay with |
112 | | - Some d -> begin |
113 | | - if (!n_processed_events mod d) = 0 then Unix.sleep (1); |
114 | | - end |
115 | | - | None -> () |
116 | | - end; |
117 | | - |
118 | | - with Online_page.Missing_trust (page_id', rev_id') -> |
119 | | - begin |
120 | | - (* We need to evaluate page_id', rev_id' first *) |
121 | | - (* This if is a basic sanity check only. It should always be true *) |
122 | | - if rev_id' <> rev_id then |
123 | | - begin |
124 | | - Printf.printf "Missing trust info: we need first to evaluate revision %d of page %d\n" rev_id' page_id'; |
125 | | - evaluate_revision page_id' rev_id'; |
126 | | - evaluate_revision page_id rev_id |
127 | | - end (* rev_id' <> rev_id *) |
128 | | - end (* with: Was missing trust of a previous revision *) |
129 | | - end (* End of try ... with ... *) |
130 | | - end |
131 | | -in |
132 | | - |
133 | | -(* This is the code that evaluates a vote *) |
134 | | -let evaluate_vote (page_id: int) (revision_id: int) (voter_id: int) = |
135 | | - if !n_processed_events < !max_events_to_process then |
136 | | - begin |
137 | | - Printf.printf "Evaluating vote by %d on revision %d of page %d\n" voter_id revision_id page_id; |
138 | | - let page = new Online_page.page db logger page_id revision_id trust_coeff !times_to_retry_trans in |
139 | | - if page#vote voter_id then begin |
140 | | - n_processed_events := !n_processed_events + 1; |
141 | | - Printf.printf "Done revision %d of page %d\n" revision_id page_id; |
142 | | - end; |
143 | | - (* Waits, if so requested to throttle the computation. *) |
144 | | - if each_event_delay > 0 then Unix.sleep (each_event_delay); |
145 | | - begin |
146 | | - match every_n_events_delay with |
147 | | - Some d -> begin |
148 | | - if (!n_processed_events mod d) = 0 then Unix.sleep (1); |
149 | | - end |
150 | | - | None -> () |
151 | | - end; |
152 | | - end |
153 | | -in |
154 | | - |
155 | | -(* |
156 | | - Returns the user id of the user name if we have it, |
157 | | - or asks a web service for it if we do not. |
158 | | -*) |
159 | | -let get_user_id u_name = |
160 | | - try db # get_user_id u_name with DB_Not_Found -> get_user_id u_name |
161 | | -in |
162 | | - |
163 | | -(* Color the asked for revision. *) |
164 | | -let process_revs (page_id : int) (rev_ids : int list) (page_title : string) |
165 | | - (rev_timestamp : string) (user_id : int) = |
166 | | - let rec do_processing (rev_id : int) = |
167 | | - (* I assume that a user cannot vote on an unprocessed revision here. *) |
168 | | - if (db # revision_needs_coloring rev_id) then ( |
169 | | - (* Grab the text and color it. *) |
170 | | - let last_colored_timestamp = try db # get_latest_colored_rev_timestamp |
171 | | - page_id with DB_Not_Found -> "19700201000000" in |
172 | | - let (wpage, wrevs) = fetch_page_and_revs_after page_title last_colored_timestamp in |
173 | | - match wpage with |
174 | | - | None -> Printf.printf "Failed for page %s\n" page_title |
175 | | - | Some pp -> ( |
176 | | - Printf.printf "Got page titled %s\n" pp.page_title; |
177 | | - db # write_page pp |
178 | | - ); |
179 | | - let update_and_write_rev rev = |
180 | | - rev.revision_page <- page_id; |
181 | | - rev.revision_user <- (get_user_id rev.revision_user_text); |
182 | | - db # write_revision rev |
183 | | - in |
184 | | - List.iter update_and_write_rev wrevs; |
185 | | - let f rev = |
186 | | - evaluate_revision page_id rev.revision_id |
187 | | - in |
188 | | - List.iter f wrevs; |
189 | | - Unix.sleep sleep_time_sec; |
190 | | - if !synch_log then flush Pervasives.stdout; |
191 | | - if (db # revision_needs_coloring rev_id) then ( |
192 | | - do_processing rev_id |
193 | | - ) |
194 | | - else () |
195 | | - ) else ( (* Vote! *) |
196 | | - let process_vote v = ( |
197 | | - if v.vote_page_id == page_id then |
198 | | - evaluate_vote page_id rev_id v.vote_voter_id |
199 | | - ) in |
200 | | - let votes = db # fetch_unprocessed_votes !max_events_to_process in |
201 | | - List.iter process_vote votes |
202 | | - ) |
203 | | - in |
204 | | - List.iter do_processing rev_ids; |
205 | | - Printf.printf "Finished processing page %s\n" page_title; |
206 | | - exit 0 (* No more work to do, stop this process. *) |
207 | | -in |
208 | | - |
209 | | -(* Start a new process going which actually processes the missing page. *) |
210 | | -let dispatch_page rev_pages = |
211 | | - let new_pages = Hashtbl.create (List.length rev_pages) in |
212 | | - let is_new_page p = |
213 | | - try ignore (Hashtbl.find working_children p); false with Not_found -> true |
214 | | - in |
215 | | - let set_revs_to_get (r,p,title,time,uid) = |
216 | | - Printf.printf "page %d\n" p; |
217 | | - if (is_new_page p) then ( |
218 | | - ( |
219 | | - let current_revs = try Hashtbl.find new_pages p with |
220 | | - Not_found -> ([],title,time,uid) in |
221 | | - (Hashtbl.replace new_pages p ((r::(let x,_,_,_ = |
222 | | - current_revs in x)), |
223 | | - title,time,uid)) |
224 | | - ) |
225 | | - ) else () |
226 | | - in |
227 | | - let launch_processing p (r,t,rt,uid) = ( |
228 | | - let new_pid = Unix.fork () in |
229 | | - match new_pid with |
230 | | - | 0 -> ( |
231 | | - Printf.printf "I'm the child\n Running on page %d rev %d\n" p |
232 | | - (List.hd r); |
233 | | - process_revs p r t rt uid |
234 | | - ) |
235 | | - | _ -> (Printf.printf "Parent of pid %d\n" new_pid; |
236 | | - Hashtbl.add working_children p (new_pid) |
237 | | - ) |
238 | | - ) in |
239 | | - Hashtbl.iter clean_kids working_children; |
240 | | - List.iter set_revs_to_get rev_pages; |
241 | | - Hashtbl.iter launch_processing new_pages |
242 | | -in |
243 | | - |
244 | | -(* Poll to see if there is any more work to be done. *) |
245 | | -let rec main_loop () = |
246 | | - if (Hashtbl.length working_children) >= max_concurrent_procs then ( |
247 | | - Hashtbl.iter clean_kids working_children |
248 | | - ) else ( |
249 | | - let revs_to_process = db # fetch_next_to_color |
250 | | - (max (max_concurrent_procs - Hashtbl.length working_children) 0) in |
251 | | - dispatch_page revs_to_process |
252 | | - ); |
253 | | - Unix.sleep sleep_time_sec; |
254 | | - if !synch_log then flush Pervasives.stdout; |
255 | | - main_loop () |
256 | | -in |
257 | | - |
258 | | -main_loop () |
Index: trunk/extensions/WikiTrust/analysis/tmpfile.mli |
— | — | @@ -1,25 +0,0 @@ |
2 | | -(***********************************************************************) |
3 | | -(* *) |
4 | | -(* Objective Caml *) |
5 | | -(* *) |
6 | | -(* Fran�ois Pessaux, projet Cristal, INRIA Rocquencourt *) |
7 | | -(* Pierre Weis, projet Cristal, INRIA Rocquencourt *) |
8 | | -(* Jun Furuse, projet Cristal, INRIA Rocquencourt *) |
9 | | -(* *) |
10 | | -(* Copyright 1999 - 2003 *) |
11 | | -(* Institut National de Recherche en Informatique et en Automatique. *) |
12 | | -(* Distributed only by permission. *) |
13 | | -(* *) |
14 | | -(***********************************************************************) |
15 | | - |
16 | | -val tmp_dir : string ref |
17 | | -(* swap file directory: the default is /tmp, but note that it is often |
18 | | - the case that /tmp is not large enough for some huge images!! *) |
19 | | - |
20 | | -val new_tmp_file_name : string -> string |
21 | | -(* [new_swap_file_name prefix] returns a new swap file name with |
22 | | - prefix [prefix]. *) |
23 | | - |
24 | | -val remove_tmp_file : string -> unit |
25 | | -(* [remove_tmp_file fname] removes [fname] if it can; nothing |
26 | | - happens if [fname] cannot be removed. *) |
Index: trunk/extensions/WikiTrust/analysis/Makefile |
— | — | @@ -30,7 +30,7 @@ |
31 | 31 | # POSSIBILITY OF SUCH DAMAGE. |
32 | 32 | |
33 | 33 | # Vars we use in our rules to build ocaml programs |
34 | | -PACKAGES = unix,str,vec,mapmin,hashtbl_bounded,fileinfo,intvmap,extlib,mysql,netsys,netclient,camlzip,xml-light,sexplib.syntax |
| 34 | +PACKAGES = unix,str,vec,mapmin,hashtbl_bounded,fileinfo,intvmap,extlib,mysql,sexplib.syntax |
35 | 35 | SYNTAX = camlp4o |
36 | 36 | OUR_LIBS = evalwiki.cma |
37 | 37 | OUR_LIBS_OPT = evalwiki.cmxa |
— | — | @@ -72,11 +72,11 @@ |
73 | 73 | # one for the optimizing compilation. |
74 | 74 | OUR_ONLINE_OBJS = online_types.cmo online_db.cmo online_revision.cmo \ |
75 | 75 | db_page.cmo online_page.cmo online_log.cmo event_feed.cmo \ |
76 | | - online_command_line.cmo tmpfile.cmo wikipedia_api.cmo \ |
| 76 | + online_command_line.cmo \ |
77 | 77 | |
78 | 78 | OUR_OPT_ONLINE_OBJS = online_types.cmx online_db.cmx online_revision.cmx \ |
79 | 79 | db_page.cmx online_page.cmx online_log.cmx event_feed.cmx \ |
80 | | - online_command_line.cmx tmpfile.cmx wikipedia_api.cmx \ |
| 80 | + online_command_line.cmx \ |
81 | 81 | |
82 | 82 | |
83 | 83 | online_eval: $(OUR_ONLINE_OBJS) |
— | — | @@ -91,37 +91,21 @@ |
92 | 92 | vote_revisionopt: $(OUR_OPT_ONLINE_OBJS) |
93 | 93 | $(OCAMLOPT) -linkpkg -o vote_revision $(OCAMLOPT_FLAGS) $(OUR_LIBS_OPT) $(OUR_OPT_ONLINE_OBJS) vote_revision.ml |
94 | 94 | |
95 | | -server: $(OUR_ONLINE_OBJS) |
96 | | - $(OCAMLC) -package "netstring,netcgi2,unix,nethttpd-for-netcgi2,netplex" -linkpkg -o server $(OCAML_CFLAGS) $(OUR_LIBS) $(OUR_ONLINE_OBJS) -thread server.ml |
97 | | - |
98 | | -serveropt: $(OUR_OPT_ONLINE_OBJS) |
99 | | - $(OCAMLOPT) -package "netstring,netcgi2,unix,nethttpd-for-netcgi2,netplex" -linkpkg -o server $(OCAMLOPT_FLAGS) $(OUR_LIBS_OPT) $(OUR_OPT_ONLINE_OBJS) -thread server.ml |
100 | | - |
101 | | -dispatcher: $(OUR_ONLINE_OBJS) |
102 | | - $(OCAMLC) -linkpkg -o dispatcher $(OCAML_CFLAGS) $(OUR_LIBS) $(OUR_ONLINE_OBJS) server_coloring_dispatcher.ml |
103 | | - |
104 | | -dispatcheropt: $(OUR_OPT_ONLINE_OBJS) |
105 | | - $(OCAMLOPT) -linkpkg -o dispatcher $(OCAMLOPT_FLAGS) $(OUR_LIBS_OPT) $(OUR_OPT_ONLINE_OBJS) server_coloring_dispatcher.ml |
106 | | - |
107 | 95 | all: |
108 | 96 | cd ../batch/analysis; make all |
109 | 97 | make online_eval |
110 | 98 | make vote_revision |
111 | | - make server |
112 | | - make dispatcher |
113 | 99 | |
114 | 100 | allopt: |
115 | 101 | cd ../batch/analysis; make allopt |
116 | 102 | make online_evalopt |
117 | 103 | make vote_revisionopt |
118 | | - make serveropt |
119 | | - make dispatcheropt |
120 | 104 | |
121 | 105 | universe: all allopt |
122 | 106 | |
123 | 107 | clean: |
124 | 108 | cd ../batch/analysis; make clean |
125 | | - rm -f *.o *.cmo *.cmx *.cmi .depends run_harness eval_online_wiki vote_revision server dispatcher |
| 109 | + rm -f *.o *.cmo *.cmx *.cmi .depends run_harness eval_online_wiki vote_revision |
126 | 110 | |
127 | 111 | # Boilerplate code for building ocaml dependencies. |
128 | 112 | |
Index: trunk/extensions/WikiTrust/mediawiki/extensions/Trust/RemoteTrust.php |
— | — | @@ -1,675 +0,0 @@ |
2 | | -<?php |
3 | | - |
4 | | -# Copyright (c) 2007,2008 Luca de Alfaro |
5 | | -# Copyright (c) 2007,2008 Ian Pye |
6 | | -# Copyright (c) 2007 Jason Benterou |
7 | | -# |
8 | | -# This program is free software; you can redistribute it and/or |
9 | | -# modify it under the terms of the GNU General Public License as |
10 | | -# published by the Free Software Foundation; either version 2 of the |
11 | | -# License, or (at your option) any later version. |
12 | | - |
13 | | -# This program is distributed in the hope that it will be useful, but |
14 | | -# WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | | -# General Public License for more details. |
17 | | - |
18 | | -# You should have received a copy of the GNU General Public License |
19 | | -# along with this program; if not, write to the Free Software |
20 | | -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
21 | | -# USA |
22 | | - |
23 | | -## MW extension |
24 | | -# This defines a custom MW function to map trust values to HTML markup |
25 | | -# |
26 | | -# Uses Tool Tip JS library under the LGPL. |
27 | | -# http://www.walterzorn.com/tooltip/tooltip_e.htm |
28 | | - |
29 | | - // Turn old style errors into exceptions. |
30 | | -function exception_error_handler($errno, $errstr, $errfile, $errline ) { |
31 | | - throw new ErrorException($errstr, 0, $errno, $errfile, $errline); |
32 | | -} |
33 | | - |
34 | | - // But only for warnings. |
35 | | -set_error_handler("exception_error_handler", E_WARNING); |
36 | | - |
37 | | -class TextTrust extends TrustBase { |
38 | | - |
39 | | - ## Types of analysis to perform. |
40 | | - const TRUST_EVAL_VOTE = 0; |
41 | | - const TRUST_EVAL_EDIT = 10; |
42 | | - const TRUST_EVAL_MISSING = 15; |
43 | | - |
44 | | - ## the css tag to use |
45 | | - const TRUST_CSS_TAG = "background-color"; ## color the background |
46 | | - #$TRUST_CSS_TAG = "color"; ## color just the text |
47 | | - |
48 | | - ## ColorText is called multiple times, but we only want to color true text. |
49 | | - const DIFF_TOKEN_TO_COLOR = "Lin"; |
50 | | - |
51 | | - ## Trust normalization values; |
52 | | - const MAX_TRUST_VALUE = 9; |
53 | | - const MIN_TRUST_VALUE = 0; |
54 | | - const TRUST_MULTIPLIER = 10; |
55 | | - |
56 | | - ## Token to split trust and origin values on |
57 | | - const TRUST_SPLIT_TOKEN = ','; |
58 | | - |
59 | | - ## Token to be replaed with < |
60 | | - const TRUST_OPEN_TOKEN = "QQampo:"; |
61 | | - |
62 | | - ## Token to be replaed with > |
63 | | - const TRUST_CLOSE_TOKEN = ":ampc:"; |
64 | | - |
65 | | - ## Server forms |
66 | | - const NOT_FOUND_TEXT_TOKEN = "TEXT_NOT_FOUND"; |
67 | | - const TRUST_COLOR_TOKEN = "<!--trust-->"; |
68 | | - |
69 | | - ## Context for communicating with the trust server |
70 | | - const TRUST_TIMEOUT = 10; |
71 | | - |
72 | | - ## default values for variables found from LocalSettings.php |
73 | | - var $DEFAULTS = array( |
74 | | - 'wgShowVoteButton' => false, |
75 | | - 'wgVoteText' => "I believe this information is correct", |
76 | | - 'wgThankYouForVoting' => "Thank you for your vote.", |
77 | | - 'wgNoTrustExplanation' => |
78 | | - "<p><center><b>There is no trust information available for this text yet.</b></center></p>", |
79 | | - 'wgTrustCmd' => "eval_online_wiki", |
80 | | - 'wgVoteRev' => "vote_revision", |
81 | | - 'wgTrustLog' => "/dev/null", |
82 | | - 'wgTrustDebugLog' => "/dev/null", |
83 | | - 'wgRepSpeed' => 1.0, |
84 | | - 'wgNotPartExplanation' => "This page is not part of the trust coloring experement", |
85 | | - 'wgTrustTabText' => "Show Trust", |
86 | | - 'wgTrustExplanation' => |
87 | | - "<p><center><b>This is a product of the text trust algoruthm.</b></center></p>", |
88 | | - 'wgContentServerURL' => "http://localhost:4444/?" |
89 | | - ); |
90 | | - |
91 | | - ## Median Value of Trust |
92 | | - var $median = 1.0; |
93 | | - |
94 | | - ## Number of times a revision is looked at. |
95 | | - var $times_rev_loaded = 0; |
96 | | - |
97 | | - ## Load the article we are talking about |
98 | | - var $title; |
99 | | - |
100 | | - ## Only color the text once. |
101 | | - var $colored = false; |
102 | | - |
103 | | - ## Don't close the first opening span tag |
104 | | - var $first_span = true; |
105 | | - |
106 | | - ## And the same for origin tags |
107 | | - var $first_origin = true; |
108 | | - |
109 | | - ## And the last revision of the title |
110 | | - var $current_rev; |
111 | | - |
112 | | - ## Only add the scripts once. |
113 | | - var $scripts_added = false; |
114 | | - |
115 | | - ## Should we do all the fancy trust processing? |
116 | | - var $trust_engaged = false; |
117 | | - |
118 | | - ## map trust values to html color codes |
119 | | - var $COLORS = array( |
120 | | - "trust0", |
121 | | - "trust1", |
122 | | - "trust2", |
123 | | - "trust3", |
124 | | - "trust4", |
125 | | - "trust5", |
126 | | - "trust6", |
127 | | - "trust7", |
128 | | - "trust9", |
129 | | - "trust10", |
130 | | - ); |
131 | | - |
132 | | - ## Only write a new trust tag when the trust changes. |
133 | | - var $current_trust = "trust0"; |
134 | | - |
135 | | - var $trustJS = ' |
136 | | -<script type="text/javascript">/*<![CDATA[*/ |
137 | | -var ctrlState = false; |
138 | | -function showOrigin(revnum) { |
139 | | - document.location.href = wgScriptPath + "/index.php?title=" + encodeURIComponent(wgPageName) + "&diff=" + encodeURIComponent(revnum); |
140 | | -} |
141 | | - |
142 | | -// The Vote functionality |
143 | | -function voteCallback(http_request){ |
144 | | - if ((http_request.readyState == 4) && (http_request.status == 200)) { |
145 | | - document.getElementById("vote-button-done").style.visibility = "visible"; |
146 | | - document.getElementById("vote-button").style.visibility = "hidden"; |
147 | | - // alert(http_request.responseText); |
148 | | - return true; |
149 | | - } else { |
150 | | - alert(http_request.responseText); |
151 | | - return false; |
152 | | - } |
153 | | -} |
154 | | - |
155 | | -function getQueryVariable(variable) { |
156 | | - var query = window.location.search.substring(1); |
157 | | - var vars = query.split("&"); |
158 | | - for (var i=0;i<vars.length;i++) { |
159 | | - var pair = vars[i].split("="); |
160 | | - if (pair[0] == variable) { |
161 | | - return pair[1]; |
162 | | - } |
163 | | - } |
164 | | - return ""; |
165 | | -} |
166 | | - |
167 | | -function startVote(){ |
168 | | - |
169 | | - var revID = getQueryVariable("oldid"); |
170 | | - if (revID == ""){ |
171 | | - revID = getQueryVariable("diff"); |
172 | | - if (revID == ""){ |
173 | | - revID = wgCurRevisionId; |
174 | | - } |
175 | | - } |
176 | | - |
177 | | - return sajax_do_call( "TextTrust::handleVote", [wgUserName, wgArticleId, revID, wgPageName] , voteCallback ); |
178 | | -} |
179 | | - |
180 | | -/*]]>*/</script>'; |
181 | | - |
182 | | - var $trustCSS = ' |
183 | | -<style type="text/css">/*<![CDATA[*/ |
184 | | -.trust0 { |
185 | | - background-color: #FFB947; |
186 | | -} |
187 | | - |
188 | | -.trust1 { |
189 | | - background-color: #FFC05C; |
190 | | -} |
191 | | - |
192 | | -.trust2 { |
193 | | - background-color: #FFC870; |
194 | | -} |
195 | | - |
196 | | -.trust3 { |
197 | | - background-color: #FFD085; |
198 | | -} |
199 | | - |
200 | | -.trust4 { |
201 | | - background-color: #FFD899; |
202 | | -} |
203 | | - |
204 | | -.trust5 { |
205 | | - background-color: #FFE0AD; |
206 | | -} |
207 | | - |
208 | | -.trust6 { |
209 | | - background-color: #FFE8C2; |
210 | | -} |
211 | | - |
212 | | -.trust7 { |
213 | | - background-color: #FFEFD6; |
214 | | -} |
215 | | - |
216 | | -.trust8 { |
217 | | - background-color: #FFF7EB; |
218 | | -} |
219 | | - |
220 | | -.trust9 { |
221 | | - background-color: #FFFFFF; |
222 | | -} |
223 | | - |
224 | | -.trust10 { |
225 | | - background-color: #FFFFFF; |
226 | | -} |
227 | | - |
228 | | -#vote-button-done { |
229 | | - visibility: hidden; |
230 | | - position: absolute; |
231 | | - top: 10px; |
232 | | - left: 500px; |
233 | | -} |
234 | | - |
235 | | -#vote-button { |
236 | | - position: absolute; |
237 | | - top: 10px; |
238 | | - left: 500px; |
239 | | -} |
240 | | - |
241 | | -/*]]>*/</style>'; |
242 | | - |
243 | | - public static function &singleton( ) |
244 | | - { return parent::singleton( ); } |
245 | | - |
246 | | - public function TextTrust(){ |
247 | | - parent::__construct( ); |
248 | | - global $wgExtensionCredits, $wgShowVoteButton, $wgVoteText, $wgThankYouForVoting; |
249 | | - global $wgNoTrustExplanation, $wgTrustCmd, $wgVoteRev, $wgTrustLog, $wgTrustDebugLog, $wgRepSpeed; |
250 | | - global $wgTrustTabText, $wgTrustExplanation, $wgNotPartExplanation, $wgContentServerURL; |
251 | | - |
252 | | - //Add default values if globals not set. |
253 | | - if(!$wgShowVoteButton) |
254 | | - $wgShowVoteButton = $this->DEFAULTS['wgShowVoteButton']; |
255 | | - if(!$wgVoteText) |
256 | | - $wgVoteText = $this->DEFAULTS['wgVoteText' ]; |
257 | | - if(!$wgThankYouForVoting) |
258 | | - $wgThankYouForVoting = $this->DEFAULTS['wgThankYouForVoting']; |
259 | | - if(!$wgNoTrustExplanation) |
260 | | - $wgNoTrustExplanation = $this->DEFAULTS['wgNoTrustExplanation']; |
261 | | - if(!$wgNotPartExplanation) |
262 | | - $wgNotPartExplanation = $this->DEFAULTS['wgNotPartExplanation']; |
263 | | - if(!$wgTrustCmd) |
264 | | - $wgTrustCmd = $this->DEFAULTS['wgTrustCmd' ]; |
265 | | - if(!$wgVoteRev) |
266 | | - $wgVoteRev = $this->DEFAULTS['wgVoteRev']; |
267 | | - if(!$wgTrustLog) |
268 | | - $wgTrustLog = $this->DEFAULTS['wgTrustLog']; |
269 | | - if(!$wgTrustDebugLog) |
270 | | - $wgTrustDebugLog = $this->DEFAULTS['wgTrustDebugLog']; |
271 | | - if(!$wgRepSpeed) |
272 | | - $wgRepSpeed = $this->DEFAULTS['wgRepSpeed']; |
273 | | - if(!$wgTrustTabText) |
274 | | - $wgTrustTabText = $this->DEFAULTS['wgTrustTabText']; |
275 | | - if(!$wgTrustExplanation) |
276 | | - $wgTrustExplanation = $this->DEFAULTS['wgTrustExplanation']; |
277 | | - if(!$wgContentServerURL) |
278 | | - $wgContentServerURL = $this->DEFAULTS['wgContentServerURL']; |
279 | | - |
280 | | -# Define a setup function |
281 | | - $wgExtensionFunctions[] = 'ucscColorTrust_Setup'; |
282 | | - |
283 | | -# Credits |
284 | | - $wgExtensionCredits['parserhook'][] = array( |
285 | | - 'name' => 'Trust Coloring', |
286 | | - 'author' =>'Ian Pye', |
287 | | - 'url' => |
288 | | - 'http://trust.cse.ucsc.edu', |
289 | | - 'description' => 'This Extension |
290 | | -colors text according to trust.' |
291 | | - ); |
292 | | - } |
293 | | - |
294 | | - // Sets the extension hooks. |
295 | | - public function setup() { |
296 | | - parent::setup(); |
297 | | - global $wgHooks, $wgParser, $wgRequest, $wgUseAjax, $wgShowVoteButton, $wgAjaxExportList, $wgUser; |
298 | | - |
299 | | -# Code which takes the "I vote" action. |
300 | | -# This has to be statically called. |
301 | | - if($wgUseAjax && $wgShowVoteButton){ |
302 | | - $wgAjaxExportList[] = "TextTrust::handleVote"; |
303 | | - } |
304 | | - |
305 | | - // Is the user opting to use wikitrust? |
306 | | - $tname = "gadget-WikiTrust"; |
307 | | - if (!$wgUser->getOption( $tname ) ) { |
308 | | - return; |
309 | | - } |
310 | | - |
311 | | -# Updater fiered when updating to a new version of MW. |
312 | | - $wgHooks['LoadExtensionSchemaUpdates'][] = array(&$this, 'updateDB'); |
313 | | - |
314 | | -# And add and extra tab. |
315 | | - $wgHooks['SkinTemplateTabs'][] = array(&$this, 'ucscTrustTemplate'); |
316 | | - |
317 | | -# If the trust tab is not selected, or some other tabs are don't worry about things any more. |
318 | | - if(!$wgRequest->getVal('trust') || $wgRequest->getVal('action')){ |
319 | | - $this->trust_engaged = false; |
320 | | - return; |
321 | | - } |
322 | | - $this->trust_engaged = true; |
323 | | - |
324 | | -# Add trust CSS and JS |
325 | | - $wgHooks['OutputPageBeforeHTML'][] = array( &$this, 'ucscColorTrust_OP'); |
326 | | - |
327 | | -# Add a hook to initialise the magic words |
328 | | - $wgHooks['LanguageGetMagic'][] = array( &$this, 'ucscColorTrust_Magic'); |
329 | | - |
330 | | -# Set a function hook associating the blame and trust words with a callback function |
331 | | - $wgParser->setFunctionHook( 't', array( &$this, 'ucscColorTrust_Render')); |
332 | | - |
333 | | -# After everything, make the blame info work |
334 | | - $wgHooks['ParserAfterTidy'][] = array( &$this, 'ucscOrigin_Finalize'); |
335 | | - } |
336 | | - |
337 | | - /** |
338 | | - * Update the DB when MW is updated. |
339 | | - * This assums that the db has permissions to create tables. |
340 | | - */ |
341 | | - function updateDB(){ |
342 | | - // Create only those tables missing. |
343 | | - // Create the needed tables, if neccesary. |
344 | | - // Pull in the create scripts. |
345 | | - require_once("TrustUpdateScripts.inc"); |
346 | | - |
347 | | - $db =& wfGetDB( DB_MASTER ); |
348 | | - |
349 | | - // First check to see what tables have already been created. |
350 | | - $res = $db->query("show tables"); |
351 | | - while ($row = $db->fetchRow($res)){ |
352 | | - $db_tables[$row[0]] = True; |
353 | | - } |
354 | | - |
355 | | - foreach ($create_scripts as $table => $scripts) { |
356 | | - if (!$db_tables[$table]){ |
357 | | - foreach ($scripts as $script){ |
358 | | - $db->query($script); |
359 | | - } |
360 | | - } |
361 | | - } |
362 | | - } |
363 | | - |
364 | | - /** |
365 | | - Records the vote. |
366 | | - Called via ajax, so this must be static. |
367 | | - */ |
368 | | - static function handleVote($user_name_raw, $page_id_raw = 0, $rev_id_raw = 0, $page_title = ""){ |
369 | | - |
370 | | - global $wgContentServerURL; |
371 | | - $response = new AjaxResponse("0"); |
372 | | - |
373 | | - $dbr =& wfGetDB( DB_SLAVE ); |
374 | | - |
375 | | - $userName = $dbr->strencode($user_name_raw, $dbr); |
376 | | - $page_id = $dbr->strencode($page_id_raw, $dbr); |
377 | | - $rev_id = $dbr->strencode($rev_id_raw, $dbr); |
378 | | - |
379 | | - if($page_id){ |
380 | | - // First, look up the id numbers from the page and user strings |
381 | | - $res = $dbr->select('user', array('user_id'), array('user_name' => $userName), array()); |
382 | | - if ($res){ |
383 | | - $row = $dbr->fetchRow($res); |
384 | | - $user_id = $row['user_id']; |
385 | | - if (!$user_id) { |
386 | | - $user_id = 0; |
387 | | - } |
388 | | - } |
389 | | - $dbr->freeResult( $res ); |
390 | | - |
391 | | - $ctx = stream_context_create( |
392 | | - array('http' => array( |
393 | | - 'timeout' => |
394 | | - self::TRUST_TIMEOUT |
395 | | - ) |
396 | | - ) |
397 | | - ); |
398 | | - |
399 | | - $vote_str = ("Voting at " . $wgContentServerURL . "vote=1&rev=$rev_id&page=$page_id&user=$user_id&page_title=$page_title&time=" . wfTimestampNow()); |
400 | | - $colored_text = file_get_contents($wgContentServerURL . "vote=1&rev=$rev_id&page=$page_id&user=$user_id&page_title=$page_title&time=" . |
401 | | - wfTimestampNow(), 0, $ctx); |
402 | | - $response = new AjaxResponse($vote_str); |
403 | | - } |
404 | | - return $response; |
405 | | - } |
406 | | - |
407 | | - /** |
408 | | - Called just before rendering HTML. |
409 | | - We add the coloring scripts here. |
410 | | - */ |
411 | | - function ucscColorTrust_OP(&$out, &$text){ |
412 | | - if (!$this->scripts_added){ // Only add the scripts once. |
413 | | - $out->addScript($this->trustJS); |
414 | | - $out->addScript($this->trustCSS); |
415 | | - $this->scripts_added = true; |
416 | | - } |
417 | | - return true; |
418 | | - } |
419 | | - |
420 | | -# Actually add the tab. |
421 | | - function ucscTrustTemplate($skin, &$content_actions) { |
422 | | - |
423 | | - global $wgTrustTabText, $wgRequest; |
424 | | - if (!isset($wgTrustTabText)){ |
425 | | - $wgTrustTabText = "trust"; |
426 | | - } |
427 | | - |
428 | | - if ($wgRequest->getVal('action')){ |
429 | | - // we don't want trust for actions. |
430 | | - return true; |
431 | | - } |
432 | | - |
433 | | - if ($wgRequest->getVal('diff')){ |
434 | | - // or for diffs |
435 | | - return true; |
436 | | - } |
437 | | - |
438 | | - $trust_qs = $_SERVER['QUERY_STRING']; |
439 | | - if($trust_qs){ |
440 | | - $trust_qs = "?" . $trust_qs . "&trust=t"; |
441 | | - } else { |
442 | | - $trust_qs .= "?trust=t"; |
443 | | - } |
444 | | - |
445 | | - $content_actions['trust'] = array ( 'class' => '', |
446 | | - 'text' => $wgTrustTabText, |
447 | | - 'href' => |
448 | | - $_SERVER['PHP_SELF'] . $trust_qs ); |
449 | | - |
450 | | - if($wgRequest->getVal('trust')){ |
451 | | - $content_actions['trust']['class'] = 'selected'; |
452 | | - $content_actions['nstab-main']['class'] = ''; |
453 | | - $content_actions['nstab-main']['href'] .= ''; |
454 | | - } else { |
455 | | - $content_actions['trust']['href'] .= ''; |
456 | | - } |
457 | | - return true; |
458 | | - } |
459 | | - |
460 | | - /** |
461 | | - If colored text exists, use it instead of the normal text, |
462 | | - but only if the trust tab is selected. |
463 | | - */ |
464 | | - function ucscSeeIfColored(&$parser, &$text, &$strip_state = Null) { |
465 | | - global $wgRequest, $wgTrustExplanation, $wgUseAjax, $wgShowVoteButton, $wgDBprefix, $wgNoTrustExplanation, $wgVoteText, $wgThankYouForVoting, $wgNotPartExplanation, $wgContentServerURL; |
466 | | - |
467 | | - // Get the db. |
468 | | - $dbr =& wfGetDB( DB_SLAVE ); |
469 | | - |
470 | | - // Do we use a DB prefix? |
471 | | - $prefix = ($wgDBprefix)? "-db_prefix " . $dbr->strencode($wgDBprefix): ""; |
472 | | - |
473 | | - // Text for showing the "I like it" button |
474 | | - $voteitText = ""; |
475 | | - if ($wgUseAjax && $wgShowVoteButton){ |
476 | | - $voteitText = " |
477 | | -".self::TRUST_OPEN_TOKEN."div id='vote-button'".self::TRUST_CLOSE_TOKEN."".self::TRUST_OPEN_TOKEN."input type='button' name='vote' value='" . $wgVoteText . "' onclick='startVote()' /".self::TRUST_CLOSE_TOKEN."".self::TRUST_OPEN_TOKEN."/div".self::TRUST_CLOSE_TOKEN." |
478 | | -".self::TRUST_OPEN_TOKEN."div id='vote-button-done'".self::TRUST_CLOSE_TOKEN.$wgThankYouForVoting.self::TRUST_OPEN_TOKEN."/div".self::TRUST_CLOSE_TOKEN." |
479 | | -"; |
480 | | - } |
481 | | - |
482 | | - // Return if trust is not selected. |
483 | | - if (!$this->trust_engaged) |
484 | | - return true; |
485 | | - |
486 | | - // Save the title object, if it is not already present |
487 | | - if (!$this->title){ |
488 | | - $this->title = $parser->getTitle(); |
489 | | - } |
490 | | - |
491 | | - // count the number of times we load this text |
492 | | - $this->times_rev_loaded++; |
493 | | - |
494 | | - // Load the current revision id. |
495 | | - if (!$this->current_rev){ |
496 | | - if ($parser->mRevisionId){ |
497 | | - $this->current_rev = $parser->mRevisionId; |
498 | | - } else { |
499 | | - // Sometimes the revisionId field is not filled in. |
500 | | - $this->current_rev = $this->title->getPreviousRevisionID( PHP_INT_MAX ); |
501 | | - } |
502 | | - } |
503 | | - |
504 | | - /** |
505 | | - This method is being called multiple times for each page. |
506 | | - We only pull the colored text for the first time through. |
507 | | - */ |
508 | | - if ($this->colored){ |
509 | | - return true; |
510 | | - } |
511 | | - |
512 | | - if ($wgRequest->getVal('diff')){ |
513 | | - // For diffs, look for the absence of the diff token instead of counting |
514 | | - if(substr($text,0,3) == self::DIFF_TOKEN_TO_COLOR){ |
515 | | - return true; |
516 | | - } |
517 | | - } |
518 | | - |
519 | | - // if we made it here, we are going to color some text |
520 | | - $this->colored = true; |
521 | | - |
522 | | - // Check to see if this page is part of the coloring project. |
523 | | - // Disabled for now. |
524 | | - //if (!strstr($text, self::TRUST_COLOR_TOKEN)){ |
525 | | - // $text = $wgNotPartExplanation . "\n" . $text; |
526 | | - // return true; |
527 | | - //} |
528 | | - |
529 | | - // Get the page id and other data |
530 | | - $colored_text=""; |
531 | | - $page_id=0; |
532 | | - $rev_timestamp=""; |
533 | | - $rev_user=0; |
534 | | - $res = $dbr->select('revision', array('rev_page', 'rev_timestamp', 'rev_user'), array('rev_id' => $this->current_rev), array()); |
535 | | - if ($res){ |
536 | | - $row = $dbr->fetchRow($res); |
537 | | - $page_id = $row['rev_page']; |
538 | | - $rev_user = $row['rev_user']; |
539 | | - $rev_timestamp = $row['rev_timestamp']; |
540 | | - if (!$page_id) { |
541 | | - $page_id = 0; |
542 | | - } |
543 | | - } |
544 | | - $dbr->freeResult( $res ); |
545 | | - |
546 | | - $page_title = $_GET['title']; |
547 | | - $ctx = stream_context_create( |
548 | | - array('http' => array( |
549 | | - 'timeout' => |
550 | | - self::TRUST_TIMEOUT |
551 | | - ) |
552 | | - ) |
553 | | - ); |
554 | | - try { |
555 | | - // Should we do doing this via HTTPS? |
556 | | - $colored_raw = (file_get_contents($wgContentServerURL . "rev=" . $this->current_rev . "&page=$page_id&page_title=$page_title&time=$rev_timestamp&user=$rev_user", 0, $ctx)); |
557 | | - } catch (Exception $e) { |
558 | | - $colored_raw = ""; |
559 | | - } |
560 | | - |
561 | | - if ($colored_raw && $colored_raw != self::NOT_FOUND_TEXT_TOKEN){ |
562 | | - // Work around because of issues with php's built in |
563 | | - // gzip function. |
564 | | - $f = tempnam('/tmp', 'gz_fix'); |
565 | | - file_put_contents($f, $colored_raw); |
566 | | - $colored_raw = file_get_contents('compress.zlib://' . $f); |
567 | | - unlink($f); |
568 | | - |
569 | | - // Pick off the median value first. |
570 | | - $colored_data = explode(",", $colored_raw, 2); |
571 | | - $colored_text = $colored_data[1]; |
572 | | - if (preg_match("/^[+-]?(([0-9]+)|([0-9]*\.[0-9]+|[0-9]+\.[0-9]*)| |
573 | | - (([0-9]+|([0-9]*\.[0-9]+|[0-9]+\.[0-9]*))[eE][+-]?[0-9]+))$/", $colored_data[0])){ |
574 | | - $this->median = $colored_data[0]; |
575 | | - } |
576 | | - |
577 | | - // First, make sure that there are not any instances of our tokens in the colored_text |
578 | | - $colored_text = str_replace(self::TRUST_OPEN_TOKEN, "", $colored_text); |
579 | | - $colored_text = str_replace(self::TRUST_CLOSE_TOKEN, "", $colored_text); |
580 | | - |
581 | | - $colored_text = preg_replace("/'/", "'", $colored_text, -1); |
582 | | - |
583 | | - $colored_text = preg_replace("/&/", "&", $colored_text, -1); |
584 | | - |
585 | | - $colored_text = preg_replace("/</", self::TRUST_OPEN_TOKEN, $colored_text, -1); |
586 | | - $colored_text = preg_replace("/>/", self::TRUST_CLOSE_TOKEN, $colored_text, -1); |
587 | | - |
588 | | - // Now update the text. |
589 | | - $text = $voteitText . $colored_text . "\n" . $wgTrustExplanation; |
590 | | - } else { |
591 | | - // Return a message about the missing text. |
592 | | - $text = $wgNoTrustExplanation . "\n" . $text; |
593 | | - } |
594 | | - |
595 | | - return true; |
596 | | - } |
597 | | - |
598 | | - /* Register the tags we are intersted in expanding. */ |
599 | | - function ucscColorTrust_Magic( &$magicWords, $langCode ) { |
600 | | - $magicWords[ 't' ] = array( 0, 't' ); |
601 | | - return true; |
602 | | - } |
603 | | - |
604 | | - /* Pull in any colored text. Also handle closing tags. */ |
605 | | - function ucscOrigin_Finalize(&$parser, &$text) { |
606 | | - global $wgScriptPath, $IP, $wgOut; |
607 | | - |
608 | | - if(!$this->colored){ |
609 | | - // This is to handle caching problems. |
610 | | - if (!strstr($text, "This page has been accessed")){ |
611 | | - $colored_text = $text; |
612 | | - $this->ucscSeeIfColored($parser, $colored_text); |
613 | | - $text = $wgOut->parse( $colored_text ); |
614 | | - } else { |
615 | | - $colored_text = $text; |
616 | | - $this->ucscSeeIfColored($parser, $colored_text); |
617 | | - $wgOut->mBodytext = $wgOut->parse( $colored_text ); |
618 | | - } |
619 | | - } |
620 | | - |
621 | | - $count = 0; |
622 | | - $text = '<script type="text/javascript" src="'.$wgScriptPath.'/extensions/Trust/js/wz_tooltip.js"></script>' . $text; |
623 | | - $text = preg_replace('/' . self::TRUST_OPEN_TOKEN . '/', "<", $text, -1, $count); |
624 | | - $text = preg_replace('/' . self::TRUST_CLOSE_TOKEN .'/', ">", $text, -1, $count); |
625 | | - $text = preg_replace('/<\/p>/', "</span></p>", $text, -1, $count); |
626 | | - $text = preg_replace('/<p><\/span>/', "<p>", $text, -1, $count); |
627 | | - $text = preg_replace('/<li><\/span>/', "<li>", $text, -1, $count); |
628 | | - |
629 | | - return true; |
630 | | - } |
631 | | - |
632 | | - /* Text Trust */ |
633 | | - function ucscColorTrust_Render( &$parser, $combinedValue = "0,0,0" ) { |
634 | | - |
635 | | - // Split the value into trust and origin information. |
636 | | - // 0 = trust |
637 | | - // 1 = origin |
638 | | - // 2 = contributing author |
639 | | - $splitVals = explode(self::TRUST_SPLIT_TOKEN, $combinedValue); |
640 | | - |
641 | | - $class = $this->computeColorFromFloat($splitVals[0]); |
642 | | - $output = self::TRUST_OPEN_TOKEN . "span class=\"$class\"" |
643 | | - . "onmouseover=\"Tip('".$splitVals[2]."')\" onmouseout=\"UnTip()\"" |
644 | | - . "onclick=\"showOrigin(" |
645 | | - . $splitVals[1] . ")\"" . self::TRUST_CLOSE_TOKEN; |
646 | | - |
647 | | - $this->current_trust = $class; |
648 | | - if ($this->first_span){ |
649 | | - $this->first_span = false; |
650 | | - } else { |
651 | | - $output = self::TRUST_OPEN_TOKEN . "/span" . self::TRUST_CLOSE_TOKEN . $output; |
652 | | - } |
653 | | - |
654 | | - return array ( $output, "noparse" => false, "isHTML" => false ); |
655 | | - } |
656 | | - |
657 | | - /** |
658 | | - Maps from the online trust values to the css trust values. |
659 | | - Normalize the value for growing wikis. |
660 | | - */ |
661 | | - function computeColorFromFloat($trust){ |
662 | | - $normalized_value = min(self::MAX_TRUST_VALUE, max(self::MIN_TRUST_VALUE, |
663 | | - (($trust + .5) * self::TRUST_MULTIPLIER) |
664 | | - / $this->median)); |
665 | | - return $this->computeColor3($normalized_value); |
666 | | - } |
667 | | - |
668 | | - /* Maps a trust value to a HTML color representing the trust value. */ |
669 | | - function computeColor3($fTrustValue){ |
670 | | - return $this->COLORS[$fTrustValue]; |
671 | | - } |
672 | | -} |
673 | | - |
674 | | -TextTrust::singleton(); |
675 | | - |
676 | | -?> |
Index: trunk/extensions/WikiTrust/mediawiki/extensions/Trust/TrustUpdateScripts.inc |
— | — | @@ -112,6 +112,6 @@ |
113 | 113 | $remove_scripts[$wgDBprefix.'wikitrust_missing_revs'] = array("DROP TABLE |
114 | 114 | ".$wgDBprefix."wikitrust_missing_revs"); |
115 | 115 | |
116 | | -$remove_index_scripts[$wgDBprefix . "revision"]['wikitrust_revision_id_timestamp_idx'] = "DROP INDEX wikitrust_revision_id_timestamp_idx ON revision"; |
| 116 | +$remove_index_scripts[$wgDBprefix . "revision"]['wikitrust_revision_id_timestamp_idx'] = "DROP INDEX wikitrust_revision_id_timestamp_idx ON ".$wgDBprefix."revision"; |
117 | 117 | |
118 | 118 | ?> |
Index: trunk/extensions/WikiTrust/mediawiki/extensions/Trust/css/trust.css |
— | — | @@ -0,0 +1,56 @@ |
| 2 | +.trust0 { |
| 3 | + background-color: #FFB947; |
| 4 | +} |
| 5 | + |
| 6 | +.trust1 { |
| 7 | + background-color: #FFC05C; |
| 8 | +} |
| 9 | + |
| 10 | +.trust2 { |
| 11 | + background-color: #FFC870; |
| 12 | +} |
| 13 | + |
| 14 | +.trust3 { |
| 15 | + background-color: #FFD085; |
| 16 | +} |
| 17 | + |
| 18 | +.trust4 { |
| 19 | + background-color: #FFD899; |
| 20 | +} |
| 21 | + |
| 22 | +.trust5 { |
| 23 | + background-color: #FFE0AD; |
| 24 | +} |
| 25 | + |
| 26 | +.trust6 { |
| 27 | + background-color: #FFE8C2; |
| 28 | +} |
| 29 | + |
| 30 | +.trust7 { |
| 31 | + background-color: #FFEFD6; |
| 32 | +} |
| 33 | + |
| 34 | +.trust8 { |
| 35 | + background-color: #FFF7EB; |
| 36 | +} |
| 37 | + |
| 38 | +.trust9 { |
| 39 | + background-color: #FFFFFF; |
| 40 | +} |
| 41 | + |
| 42 | +.trust10 { |
| 43 | + background-color: #FFFFFF; |
| 44 | +} |
| 45 | + |
| 46 | +#vote-button-done { |
| 47 | + visibility: hidden; |
| 48 | + position: absolute; |
| 49 | + top: 10px; |
| 50 | + left: 500px; |
| 51 | +} |
| 52 | + |
| 53 | +#vote-button { |
| 54 | + position: absolute; |
| 55 | + top: 10px; |
| 56 | + left: 500px; |
| 57 | +} |
\ No newline at end of file |
Index: trunk/extensions/WikiTrust/mediawiki/extensions/Trust/js/trust.js |
— | — | @@ -0,0 +1,43 @@ |
| 2 | +var ctrlState = false; |
| 3 | +function showOrigin(revnum) { |
| 4 | + document.location.href = wgScriptPath + "/index.php?title=" + encodeURIComponent(wgPageName) + "&diff=" + encodeURIComponent(revnum); |
| 5 | +} |
| 6 | + |
| 7 | +// The Vote functionality |
| 8 | +function voteCallback(http_request){ |
| 9 | + if ((http_request.readyState == 4) && (http_request.status == 200)) { |
| 10 | + document.getElementById("vote-button-done").style.visibility = "visible"; |
| 11 | + document.getElementById("vote-button").style.visibility = "hidden"; |
| 12 | + //alert(http_request.responseText); |
| 13 | + return true; |
| 14 | + } else { |
| 15 | + // Turn off error reporting. |
| 16 | + //alert(http_request.responseText); |
| 17 | + return false; |
| 18 | + } |
| 19 | +} |
| 20 | + |
| 21 | +function getQueryVariable(variable) { |
| 22 | + var query = window.location.search.substring(1); |
| 23 | + var vars = query.split("&"); |
| 24 | + for (var i=0;i<vars.length;i++) { |
| 25 | + var pair = vars[i].split("="); |
| 26 | + if (pair[0] == variable) { |
| 27 | + return pair[1]; |
| 28 | + } |
| 29 | + } |
| 30 | + return ""; |
| 31 | +} |
| 32 | + |
| 33 | +function startVote(){ |
| 34 | + |
| 35 | + var revID = getQueryVariable("oldid"); |
| 36 | + if (revID == ""){ |
| 37 | + revID = getQueryVariable("diff"); |
| 38 | + if (revID == ""){ |
| 39 | + revID = wgCurRevisionId; |
| 40 | + } |
| 41 | + } |
| 42 | + |
| 43 | + return sajax_do_call( "TextTrustImpl::handleVote", [wgUserName, wgArticleId, revID, wgPageName] , voteCallback ); |
| 44 | +} |
Index: trunk/extensions/WikiTrust/test-scripts/load_data.py |
— | — | @@ -94,9 +94,9 @@ |
95 | 95 | |
96 | 96 | # clear out the pull db if requested |
97 | 97 | if do_clear: |
98 | | - curs.execute("delete from text") |
99 | | - curs.execute("delete from page") |
100 | | - curs.execute("delete from revision") |
| 98 | + curs.execute("delete from "+ini_config.get('db', 'prefix')+"text") |
| 99 | + curs.execute("delete from "+ini_config.get('db', 'prefix')+"page") |
| 100 | + curs.execute("delete from "+ini_config.get('db', 'prefix')+"revision") |
101 | 101 | connection.commit() |
102 | 102 | |
103 | 103 | for dump in dumps: |
Index: trunk/extensions/WikiTrust/remote/analysis/Makefile |
— | — | @@ -0,0 +1,115 @@ |
| 2 | +# Copyright (c) 2007-2008 The Regents of the University of California |
| 3 | +# All rights reserved. |
| 4 | +# |
| 5 | +# Authors: Luca de Alfaro, B. Thomas Adler, Ian Pye |
| 6 | +# |
| 7 | +# Redistribution and use in source and binary forms, with or without |
| 8 | +# modification, are permitted provided that the following conditions are met: |
| 9 | +# |
| 10 | +# 1. Redistributions of source code must retain the above copyright notice, |
| 11 | +# this list of conditions and the following disclaimer. |
| 12 | +# |
| 13 | +# 2. Redistributions in binary form must reproduce the above copyright notice, |
| 14 | +# this list of conditions and the following disclaimer in the documentation |
| 15 | +# and/or other materials provided with the distribution. |
| 16 | +# |
| 17 | +# 3. The names of the contributors may not be used to endorse or promote |
| 18 | +# products derived from this software without specific prior written |
| 19 | +# permission. |
| 20 | +# |
| 21 | +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| 22 | +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 23 | +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 24 | +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
| 25 | +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 26 | +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 27 | +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| 28 | +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| 29 | +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 30 | +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 31 | +# POSSIBILITY OF SUCH DAMAGE. |
| 32 | + |
| 33 | +# Vars we use in our rules to build ocaml programs |
| 34 | +PACKAGES = unix,str,vec,mapmin,hashtbl_bounded,fileinfo,intvmap,extlib,mysql,netsys,netclient,camlzip,xml-light,sexplib.syntax |
| 35 | +SYNTAX = camlp4o |
| 36 | +OUR_LIBS = evalwiki.cma online_types.cmo online_db.cmo online_revision.cmo \ |
| 37 | + db_page.cmo online_page.cmo online_log.cmo event_feed.cmo \ |
| 38 | + online_command_line.cmo |
| 39 | + |
| 40 | +OUR_LIBS_OPT = evalwiki.cmxa online_types.cmx online_db.cmx \ |
| 41 | + online_revision.cmx \ |
| 42 | + db_page.cmx online_page.cmx online_log.cmx event_feed.cmx \ |
| 43 | + online_command_line.cmx |
| 44 | + |
| 45 | +INCLUDES = -I ../../batch/analysis -I ../../analysis |
| 46 | + |
| 47 | +OCAMLC=ocamlfind ocamlc -package $(PACKAGES) -syntax $(SYNTAX) |
| 48 | +OCAMLOPT=ocamlfind ocamlopt -package $(PACKAGES) -syntax $(SYNTAX) |
| 49 | + |
| 50 | +OCAMLDEP=ocamlfind ocamldep -package $(PACKAGES) -syntax $(SYNTAX) |
| 51 | +OCAMLDOC=ocamldoc |
| 52 | + |
| 53 | +SUFFIXES= .ml .cmo .cmi .cmx |
| 54 | + |
| 55 | +# For profiling |
| 56 | +# OCAMLDEBUG = -g -p film |
| 57 | +OCAMLDEBUG = -g |
| 58 | + |
| 59 | + |
| 60 | +# Flags for commands, depending on optimization/debugging |
| 61 | +OCAML_CFLAGS=$(INCLUDES) $(OCAMLDEBUG) |
| 62 | +OCAMLOPT_FLAGS=$(INCLUDES) |
| 63 | + |
| 64 | +%.cmo: %.ml |
| 65 | + @echo '$(OCAMLC) $(OCAML_CFLAGS) -c $<'; \ |
| 66 | + $(OCAMLC) $(OCAML_CFLAGS) -c $< |
| 67 | + |
| 68 | +%.cmi: %.mli |
| 69 | + @echo '$(OCAMLC) $(OCAML_CFLAGS) -c $<'; \ |
| 70 | + $(OCAMLC) $(OCAML_CFLAGS) -c $< |
| 71 | + |
| 72 | +%.cmx: %.ml |
| 73 | + @echo '$(OCAMLOPT) $(OCAMLOPT_FLAGS) -c $<'; \ |
| 74 | + $(OCAMLOPT) $(OCAMLOPT_FLAGS) -c $< |
| 75 | + |
| 76 | +.PHONY: all allopt universe clean |
| 77 | + |
| 78 | +# Here are the objects that we want to build. |
| 79 | +# We need two lines of these, one for the debugging compilation, |
| 80 | +# one for the optimizing compilation. |
| 81 | +OUR_ONLINE_OBJS = tmpfile.cmo wikipedia_api.cmo \ |
| 82 | + |
| 83 | +OUR_OPT_ONLINE_OBJS = tmpfile.cmx wikipedia_api.cmx \ |
| 84 | + |
| 85 | +server: $(OUR_ONLINE_OBJS) |
| 86 | + $(OCAMLC) -package "netstring,netcgi2,unix,nethttpd-for-netcgi2,netplex" -linkpkg -o server $(OCAML_CFLAGS) $(OUR_LIBS) $(OUR_ONLINE_OBJS) -thread server.ml |
| 87 | + |
| 88 | +serveropt: $(OUR_OPT_ONLINE_OBJS) |
| 89 | + $(OCAMLOPT) -package "netstring,netcgi2,unix,nethttpd-for-netcgi2,netplex" -linkpkg -o server $(OCAMLOPT_FLAGS) $(OUR_LIBS_OPT) $(OUR_OPT_ONLINE_OBJS) -thread server.ml |
| 90 | + |
| 91 | +dispatcher: $(OUR_ONLINE_OBJS) |
| 92 | + $(OCAMLC) -linkpkg -o dispatcher $(OCAML_CFLAGS) $(OUR_LIBS) $(OUR_ONLINE_OBJS) server_coloring_dispatcher.ml |
| 93 | + |
| 94 | +dispatcheropt: $(OUR_OPT_ONLINE_OBJS) |
| 95 | + $(OCAMLOPT) -linkpkg -o dispatcher $(OCAMLOPT_FLAGS) $(OUR_LIBS_OPT) $(OUR_OPT_ONLINE_OBJS) server_coloring_dispatcher.ml |
| 96 | + |
| 97 | +all: |
| 98 | + make server |
| 99 | + make dispatcher |
| 100 | + |
| 101 | +allopt: |
| 102 | + make serveropt |
| 103 | + make dispatcheropt |
| 104 | + |
| 105 | +universe: all allopt |
| 106 | + |
| 107 | +clean: |
| 108 | + rm -f *.o *.cmo *.cmx *.cmi .depends server dispatcher |
| 109 | + |
| 110 | +# Boilerplate code for building ocaml dependencies. |
| 111 | + |
| 112 | +.depends: *.ml |
| 113 | + $(OCAMLDEP) $^ > $@ |
| 114 | + |
| 115 | +-include .depends |
| 116 | + |
Property changes on: trunk/extensions/WikiTrust/remote/analysis/Makefile |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 117 | + native |
Index: trunk/extensions/WikiTrust/remote/analysis/server.ml |
— | — | @@ -0,0 +1,235 @@ |
| 2 | +(* This is a webserver built from the Netplex and Nethttpd components. |
| 3 | + * It is configured in the netplex.cfg file. |
| 4 | + * Note: start program with option "-conf netplex.cfg" |
| 5 | + * The basic code is copied from the nethttpd example. |
| 6 | + *) |
| 7 | + |
| 8 | +open Netcgi1_compat.Netcgi_types;; |
| 9 | +open Printf;; |
| 10 | +open Mysql;; |
| 11 | +open Online_db;; |
| 12 | +open Online_command_line;; |
| 13 | +open Gzip;; |
| 14 | + |
| 15 | +let tmp_prefix = "wiki-com" |
| 16 | +let not_found_text_token = "TEXT_NOT_FOUND" |
| 17 | +let sleep_time_sec = 3 |
| 18 | + |
| 19 | +let dbh = ref None |
| 20 | + |
| 21 | +let text = Netencoding.Html.encode_from_latin1;; |
| 22 | +(* This function encodes "<", ">", "&", double quotes, and Latin 1 characters |
| 23 | + * as character entities. E.g. text "<" = "<", and text "�" = "ä" |
| 24 | + *) |
| 25 | + |
| 26 | +let compress_str raw = |
| 27 | + let tmp_file = Tmpfile.new_tmp_file_name tmp_prefix in |
| 28 | + let out = Gzip.open_out tmp_file in |
| 29 | + Gzip.output out raw 0 (String.length raw); |
| 30 | + Gzip.close_out out; |
| 31 | + let compressed = Std.input_file ?bin:(Some true) tmp_file in |
| 32 | + Tmpfile.remove_tmp_file tmp_file; |
| 33 | + compressed |
| 34 | +;; |
| 35 | + |
| 36 | +let handle_missing_rev (rev_id : int) (page_id : int) (page_title : string) |
| 37 | + (rev_time : string) (user_id : int) = |
| 38 | + match !dbh with |
| 39 | + | Some db -> ( |
| 40 | + db # mark_to_color rev_id page_id page_title rev_time user_id; |
| 41 | + Unix.sleep sleep_time_sec; |
| 42 | + try (db # read_colored_markup_with_median rev_id) with |
| 43 | + | Online_db.DB_Not_Found -> (not_found_text_token,1.0) |
| 44 | + ) |
| 45 | + | None -> ("DB not initialized",1.0) |
| 46 | + |
| 47 | +(* Return colored markup *) |
| 48 | +let generate_text_page (cgi : Netcgi.cgi_activation) (rev_id : int) |
| 49 | + (page_id : int) (page_title : string) (rev_time : string) (user_id : int) |
| 50 | + = |
| 51 | + let out = cgi # out_channel # output_string in |
| 52 | + let safe_page_title = Mysql.escape page_title in |
| 53 | + let safe_rev_time = Mysql.escape rev_time in |
| 54 | + match !dbh with |
| 55 | + | Some db -> ( |
| 56 | + let (colored_text,median) = |
| 57 | + try (db # read_colored_markup_with_median rev_id) |
| 58 | + with Online_db.DB_Not_Found -> (handle_missing_rev rev_id page_id |
| 59 | + safe_page_title safe_rev_time |
| 60 | + user_id) |
| 61 | + in |
| 62 | + if colored_text != not_found_text_token then |
| 63 | + let compressed = compress_str ((string_of_float median) ^ |
| 64 | + "," ^ colored_text) in |
| 65 | + cgi # set_header |
| 66 | + ~content_type:"application/x-gzip" |
| 67 | + ~content_length:(String.length compressed) |
| 68 | + (); |
| 69 | + out compressed |
| 70 | + else |
| 71 | + out colored_text |
| 72 | + ) |
| 73 | + | None -> out "DB not initialized" |
| 74 | +;; |
| 75 | + |
| 76 | +(* Return information about an incorrect request. *) |
| 77 | +let generate_help_page (cgi : Netcgi.cgi_activation) = |
| 78 | + let out = cgi # out_channel # output_string in |
| 79 | + out not_found_text_token |
| 80 | +;; |
| 81 | + |
| 82 | +(* Record that a vote happened. *) |
| 83 | +let generate_vote_page (cgi : Netcgi.cgi_activation) (rev_id : int) |
| 84 | + (page_id : int) (user_id : int) (v_time : string) (page_title : string) = |
| 85 | + let out = cgi # out_channel # output_string in |
| 86 | + let safe_page_title = Mysql.escape page_title in |
| 87 | + match !dbh with |
| 88 | + | Some db -> ( |
| 89 | + let vote = { |
| 90 | + vote_time=(Mysql.escape v_time); |
| 91 | + vote_page_id=page_id; |
| 92 | + vote_revision_id=rev_id; |
| 93 | + vote_voter_id=user_id; |
| 94 | + } in |
| 95 | + let res = try (db # vote vote; |
| 96 | + db # mark_to_color rev_id page_id safe_page_title |
| 97 | + (Mysql.escape v_time) user_id; |
| 98 | + "good") with |
| 99 | + Online_db.DB_TXN_Bad -> "bad" in |
| 100 | + out res |
| 101 | + ) |
| 102 | + | None -> out "DB not initialized" |
| 103 | +;; |
| 104 | + |
| 105 | +let generate_page (cgi : Netcgi.cgi_activation) = |
| 106 | + (* Check which page is to be displayed. This is contained in the CGI |
| 107 | + * argument "page". |
| 108 | + *) |
| 109 | + |
| 110 | + let page_id = try (int_of_string (cgi # argument_value "page")) |
| 111 | + with int_of_string -> -1 in |
| 112 | + let rev_id = try (int_of_string (cgi # argument_value "rev")) |
| 113 | + with int_of_string -> -1 in |
| 114 | + let page_title = (cgi # argument_value "page_title") in |
| 115 | + let time_str = (cgi # argument_value "time") in |
| 116 | + let user_id = try (int_of_string (cgi # argument_value "user")) |
| 117 | + with int_of_string -> 0 in |
| 118 | + match cgi # argument_value "vote" with |
| 119 | + | "" -> ( |
| 120 | + if rev_id < 0 || page_id < 0 then generate_help_page cgi else |
| 121 | + generate_text_page cgi rev_id page_id page_title time_str |
| 122 | + user_id |
| 123 | + ) |
| 124 | + | _ -> ( |
| 125 | + generate_vote_page cgi rev_id page_id user_id time_str page_title |
| 126 | + ) |
| 127 | +;; |
| 128 | + |
| 129 | +let process2 (cgi : Netcgi.cgi_activation) = |
| 130 | + (* The [try] block catches errors during the page generation. *) |
| 131 | + try |
| 132 | + (* Set the header. The header specifies that the page must not be |
| 133 | + * cached. This is important for dynamic pages called by the GET |
| 134 | + * method, otherwise the browser might display an old version of |
| 135 | + * the page. |
| 136 | + * Furthermore, we set the content type and the character set. |
| 137 | + * Note that the header is not sent immediately to the browser because |
| 138 | + * we have enabled HTML buffering. |
| 139 | + *) |
| 140 | + cgi # set_header |
| 141 | + ~cache:`No_cache |
| 142 | + ~content_type:"text/plain; charset=\"iso-8859-1\"" |
| 143 | + (); |
| 144 | + |
| 145 | + generate_page cgi; |
| 146 | + |
| 147 | + (* After the page has been fully generated, we can send it to the |
| 148 | + * browser. |
| 149 | + *) |
| 150 | + cgi # out_channel # commit_work(); |
| 151 | + with |
| 152 | + error -> |
| 153 | + (* An error has happened. Generate now an error page instead of |
| 154 | + * the current page. By rolling back the output buffer, any |
| 155 | + * uncomitted material is deleted. |
| 156 | + *) |
| 157 | + cgi # out_channel # rollback_work(); |
| 158 | + |
| 159 | + (* We change the header here only to demonstrate that this is |
| 160 | + * possible. |
| 161 | + *) |
| 162 | + cgi # set_header |
| 163 | + ~status:`Forbidden (* Indicate the error *) |
| 164 | + ~cache:`No_cache |
| 165 | + ~content_type:"text/plain; charset=\"iso-8859-1\"" |
| 166 | + (); |
| 167 | + |
| 168 | + cgi # out_channel # output_string "While processing the request an O'Caml exception has been raised:\n"; |
| 169 | + cgi # out_channel # output_string ("" ^ text(Printexc.to_string error) ^ "\n"); |
| 170 | + |
| 171 | + (* Now commit the error page: *) |
| 172 | + cgi # out_channel # commit_work() |
| 173 | +;; |
| 174 | + |
| 175 | + |
| 176 | +let process1 (cgi : Netcgi1_compat.Netcgi_types.cgi_activation) = |
| 177 | + let cgi' = Netcgi1_compat.Netcgi_types.of_compat_activation cgi in |
| 178 | + process2 cgi' |
| 179 | + |
| 180 | + |
| 181 | +(**********************************************************************) |
| 182 | +(* Create the webserver *) |
| 183 | +(**********************************************************************) |
| 184 | + |
| 185 | + |
| 186 | +let start() = |
| 187 | + let (opt_list, cmdline_cfg) = Netplex_main.args() in |
| 188 | + |
| 189 | + let use_mt = ref false in |
| 190 | + |
| 191 | + let opt_list' = |
| 192 | + [ ("-mt", Arg.Set use_mt, |
| 193 | + " Use multi-threading instead of multi-processing"); |
| 194 | + ] @ (command_line_format @ opt_list) in |
| 195 | + |
| 196 | + Arg.parse |
| 197 | + opt_list' |
| 198 | + (fun s -> raise (Arg.Bad ("Don't know what to do with: " ^ s))) |
| 199 | + "usage: netplex [options]"; |
| 200 | + |
| 201 | + (* Prepares the database connection information *) |
| 202 | + let mediawiki_db = { |
| 203 | + dbhost = Some !mw_db_host; |
| 204 | + dbname = Some !mw_db_name; |
| 205 | + dbport = Some !mw_db_port; |
| 206 | + dbpwd = Some !mw_db_pass; |
| 207 | + dbuser = Some !mw_db_user; |
| 208 | + } in |
| 209 | + dbh := Some (new Online_db.db !db_prefix mediawiki_db None !dump_db_calls); |
| 210 | + |
| 211 | + let parallelizer = |
| 212 | + if !use_mt then |
| 213 | + Netplex_mt.mt() (* multi-threading *) |
| 214 | + else |
| 215 | + Netplex_mp.mp() in (* multi-processing *) |
| 216 | + let trust_store = |
| 217 | + { Nethttpd_services.dyn_handler = (fun _ -> process1); |
| 218 | + dyn_activation = Nethttpd_services.std_activation `Std_activation_buffered; |
| 219 | + dyn_uri = None; (* not needed *) |
| 220 | + dyn_translator = (fun _ -> ""); (* not needed *) |
| 221 | + dyn_accept_all_conditionals = false; |
| 222 | + } in |
| 223 | + let nethttpd_factory = |
| 224 | + Nethttpd_plex.nethttpd_factory |
| 225 | + ~handlers:[ "trust", trust_store ] |
| 226 | + () in |
| 227 | + Netplex_main.startup |
| 228 | + parallelizer |
| 229 | + Netplex_log.logger_factories (* allow all built-in logging styles *) |
| 230 | + Netplex_workload.workload_manager_factories (* ... all ways of workload management *) |
| 231 | + [ nethttpd_factory ] (* make this nethttpd available *) |
| 232 | + cmdline_cfg |
| 233 | +;; |
| 234 | + |
| 235 | +Sys.set_signal Sys.sigpipe Sys.Signal_ignore; |
| 236 | +start();; |
Property changes on: trunk/extensions/WikiTrust/remote/analysis/server.ml |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 237 | + native |
Index: trunk/extensions/WikiTrust/remote/analysis/server.py |
— | — | @@ -0,0 +1,186 @@ |
| 2 | +""" |
| 3 | +Copyright (c) 2007-2008 The Regents of the University of California |
| 4 | +All rights reserved. |
| 5 | + |
| 6 | +Authors: Ian Pye |
| 7 | + |
| 8 | +Redistribution and use in source and binary forms, with or without |
| 9 | +modification, are permitted provided that the following conditions are met: |
| 10 | + |
| 11 | +1. Redistributions of source code must retain the above copyright notice, |
| 12 | +this list of conditions and the following disclaimer. |
| 13 | + |
| 14 | +2. Redistributions in binary form must reproduce the above copyright notice, |
| 15 | +this list of conditions and the following disclaimer in the documentation |
| 16 | +and/or other materials provided with the distribution. |
| 17 | + |
| 18 | +3. The names of the contributors may not be used to endorse or promote |
| 19 | +products derived from this software without specific prior written |
| 20 | +permission. |
| 21 | + |
| 22 | +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| 23 | +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 24 | +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 25 | +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
| 26 | +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 27 | +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 28 | +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| 29 | +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| 30 | +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 31 | +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 32 | +POSSIBILITY OF SUCH DAMAGE. |
| 33 | + |
| 34 | +""" |
| 35 | + |
| 36 | +# Works with RemoteTrust for connecting to a remote wiki. |
| 37 | + |
| 38 | +import MySQLdb |
| 39 | +import getopt |
| 40 | +import ConfigParser |
| 41 | +import zlib |
| 42 | +import gzip |
| 43 | +import cStringIO |
| 44 | +import time |
| 45 | + |
| 46 | +from mod_python import util |
| 47 | +from mod_python import apache |
| 48 | + |
| 49 | +BASE_DIR = "/home/ipye/git/wikitrust/test-scripts/" |
| 50 | +INI_FILE = BASE_DIR + "db_access_data.ini" |
| 51 | +FILE_ENDING_SEP = " " |
| 52 | +DB_PREFIX = "" |
| 53 | +not_found_text_token = "TEXT_NOT_FOUND" |
| 54 | +sleep_time_sec = 3 |
| 55 | + |
| 56 | +connection = None |
| 57 | +curs = None |
| 58 | + |
| 59 | +# Compress a string |
| 60 | +def compressBuf(buf): |
| 61 | + zbuf = cStringIO.StringIO() |
| 62 | + zfile = gzip.GzipFile(mode = 'wb', fileobj = zbuf, compresslevel = 6) |
| 63 | + zfile.write(buf) |
| 64 | + zfile.close() |
| 65 | + return zbuf.getvalue() |
| 66 | + |
| 67 | +# Start a persisent connection to the db |
| 68 | +def connect_db(): |
| 69 | + global connection |
| 70 | + global curs |
| 71 | + global DB_PREFIX |
| 72 | + |
| 73 | + ## parse the ini file |
| 74 | + ini_config = ConfigParser.ConfigParser() |
| 75 | + ini_config.readfp(open(INI_FILE)) |
| 76 | + |
| 77 | + ## init the DB |
| 78 | + connection = MySQLdb.connect(host=ini_config.get('db', 'host'), |
| 79 | + user=ini_config.get('db', 'user'), passwd=ini_config.get('db', 'pass') \ |
| 80 | + , db=ini_config.get('db', 'db') ) |
| 81 | + curs = connection.cursor() |
| 82 | + |
| 83 | + ## Prefix |
| 84 | + DB_PREFIX = ini_config.get('db', 'prefix') |
| 85 | + |
| 86 | +# add the revision to the queue for coloring |
| 87 | +def mark_for_coloring(rev_id, page_id, user_id, rev_time, page_title): |
| 88 | + global DB_PREFIX |
| 89 | + global curs |
| 90 | + |
| 91 | + sql = """INSERT INTO """+DB_PREFIX+"""wikitrust_missing_revs (revision_id, page_id, page_title, rev_time, user_id) VALUES (%(rid)s, %(pid)s, %(title)s, %(time)s, %(vid)s) ON DUPLICATE KEY UPDATE requested_on = now(), processed = false""" |
| 92 | + args = {'rid':rev_id, 'pid':page_id, 'title':page_title, |
| 93 | + 'time':rev_time, 'vid':user_id } |
| 94 | + |
| 95 | + curs.execute(sql, args) |
| 96 | + connection.commit() |
| 97 | + |
| 98 | +# Insert the vote into the db |
| 99 | +def handle_vote(req, rev_id, page_id, user_id, v_time, page_title): |
| 100 | + global DB_PREFIX |
| 101 | + global curs |
| 102 | + |
| 103 | + sql = """INSERT INTO """+DB_PREFIX+"""wikitrust_vote (revision_id, page_id, voter_id, voted_on) VALUES (%(rid)s, %(pid)s, %(vid)s, %(time)s) ON DUPLICATE KEY UPDATE voted_on = %(time)s""" |
| 104 | + args = {'rid':rev_id, 'pid':page_id, 'vid':user_id, 'time':v_time} |
| 105 | + |
| 106 | + curs.execute(sql, args) |
| 107 | + connection.commit() |
| 108 | + |
| 109 | + mark_for_coloring(rev_id, page_id, user_id, v_time, page_title) |
| 110 | + |
| 111 | + # token saying things are ok |
| 112 | + req.write("good") |
| 113 | + |
| 114 | +# Return colored text from the DB |
| 115 | +def fetch_colored_markup(rev_id, page_id, user_id, rev_time, page_title): |
| 116 | + global DB_PREFIX |
| 117 | + global curs |
| 118 | + global not_found_text_token |
| 119 | + |
| 120 | + sql = """SELECT revision_text,median FROM """ + DB_PREFIX + \ |
| 121 | + """wikitrust_colored_markup JOIN """+ DB_PREFIX + \ |
| 122 | + """wikitrust_global WHERE revision_id = %s""" |
| 123 | + args = (rev_id) |
| 124 | + numRows = curs.execute(sql, args) |
| 125 | + |
| 126 | + if (numRows > 0): |
| 127 | + dbRow = curs.fetchone() |
| 128 | + return "%f,%s" % (dbRow[1],dbRow[0]) |
| 129 | + return not_found_text_token |
| 130 | + |
| 131 | +# Return colored text if it exists |
| 132 | +def handle_text_request(req, rev_id, page_id, user_id, rev_time, page_title): |
| 133 | + global DB_PREFIX |
| 134 | + global sleep_time_sec |
| 135 | + global not_found_text_token |
| 136 | + |
| 137 | + res = fetch_colored_markup(rev_id, page_id, user_id, rev_time, page_title) |
| 138 | + if (res == not_found_text_token): |
| 139 | + mark_for_coloring(rev_id, page_id, user_id, rev_time, page_title) |
| 140 | + time.sleep(sleep_time_sec) |
| 141 | + |
| 142 | + res = fetch_colored_markup(rev_id, page_id, user_id, rev_time, page_title) |
| 143 | + if (res == not_found_text_token): |
| 144 | + req.write(not_found_text_token) |
| 145 | + else: |
| 146 | + compressed = compressBuf(res) |
| 147 | + |
| 148 | + req.content_type = "application/x-gzip" |
| 149 | + req.content_length = len (compressed) |
| 150 | + req.send_http_header() |
| 151 | + |
| 152 | + req.write(compressed) |
| 153 | + |
| 154 | +# Before we start, connect to the db |
| 155 | +connect_db() |
| 156 | + |
| 157 | +# Entry point for web request. |
| 158 | +def handler(req): |
| 159 | + |
| 160 | + ## Default mimetype |
| 161 | + req.content_type = "text/plain" |
| 162 | + |
| 163 | + # Restart the connection to the DB if its not good. |
| 164 | + if (not connection.ping()): |
| 165 | + connect_db() |
| 166 | + |
| 167 | + ## Parse the form inputs |
| 168 | + form = util.FieldStorage(req) |
| 169 | + page_id = form.getfirst("page", -1) |
| 170 | + rev_id = form.getfirst("rev", -1) |
| 171 | + page_title =form.getfirst("page_title", "") |
| 172 | + time_str = form.getfirst("time", "") |
| 173 | + user_id = form.getfirst("user", -1) |
| 174 | + is_vote = form.getfirst("vote", None) |
| 175 | + |
| 176 | + if (page_id < 0) or (rev_id < 0) or (page_title == "") or (time_str == "") \ |
| 177 | + or (user_id < 0): |
| 178 | + req.write("bad") |
| 179 | + else: |
| 180 | + if is_vote: |
| 181 | + handle_vote(req, rev_id, page_id, user_id, time_str, page_title) |
| 182 | + else: |
| 183 | + handle_text_request(req, rev_id, page_id, user_id, time_str, page_title) |
| 184 | + |
| 185 | + return apache.OK |
| 186 | + |
| 187 | + |
Index: trunk/extensions/WikiTrust/remote/analysis/server_coloring_dispatcher.ml |
— | — | @@ -0,0 +1,257 @@ |
| 2 | +(* |
| 3 | + |
| 4 | +Copyright (c) 2007-2008 The Regents of the University of California |
| 5 | +All rights reserved. |
| 6 | + |
| 7 | +Authors: Luca de Alfaro, Ian Pye |
| 8 | + |
| 9 | +Redistribution and use in source and binary forms, with or without |
| 10 | +modification, are permitted provided that the following conditions are met: |
| 11 | + |
| 12 | +1. Redistributions of source code must retain the above copyright notice, |
| 13 | +this list of conditions and the following disclaimer. |
| 14 | + |
| 15 | +2. Redistributions in binary form must reproduce the above copyright notice, |
| 16 | +this list of conditions and the following disclaimer in the documentation |
| 17 | +and/or other materials provided with the distribution. |
| 18 | + |
| 19 | +3. The names of the contributors may not be used to endorse or promote |
| 20 | +products derived from this software without specific prior written |
| 21 | +permission. |
| 22 | + |
| 23 | +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| 24 | +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 25 | +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 26 | +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
| 27 | +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 28 | +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 29 | +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| 30 | +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| 31 | +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 32 | +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 33 | +POSSIBILITY OF SUCH DAMAGE. |
| 34 | + |
| 35 | + *) |
| 36 | + |
| 37 | +(* Figures out which pages to update, and starts them going. *) |
| 38 | + |
| 39 | +open Printf |
| 40 | +open Mysql |
| 41 | +open Unix |
| 42 | +open Online_command_line |
| 43 | +open Wikipedia_api |
| 44 | +open Online_db |
| 45 | +open Online_types |
| 46 | + |
| 47 | +let max_concurrent_procs = 10 |
| 48 | +let sleep_time_sec = 1 |
| 49 | +let custom_line_format = [] @ command_line_format |
| 50 | + |
| 51 | +let _ = Arg.parse custom_line_format noop "Usage: dispatcher";; |
| 52 | + |
| 53 | +let working_children = Hashtbl.create max_concurrent_procs |
| 54 | + |
| 55 | +(* Prepares the database connection information *) |
| 56 | +let mediawiki_db = { |
| 57 | + dbhost = Some !mw_db_host; |
| 58 | + dbname = Some !mw_db_name; |
| 59 | + dbport = Some !mw_db_port; |
| 60 | + dbpwd = Some !mw_db_pass; |
| 61 | + dbuser = Some !mw_db_user; |
| 62 | +} |
| 63 | + |
| 64 | +(* Here begins the sequential code *) |
| 65 | +let db = new Online_db.db !db_prefix mediawiki_db None !dump_db_calls in |
| 66 | +let logger = new Online_log.logger !log_name !synch_log in |
| 67 | +let n_processed_events = ref 0 in |
| 68 | +let trust_coeff = Online_types.get_default_coeff in |
| 69 | + |
| 70 | +(* There are two types of throttle delay: a second each time we are multiples of an int, |
| 71 | + or a number of seconds before each revision. *) |
| 72 | +let each_event_delay = int_of_float !color_delay in |
| 73 | +let every_n_events_delay = |
| 74 | + let frac = !color_delay -. (floor !color_delay) in |
| 75 | + if frac > 0.001 |
| 76 | + then Some (max 1 (int_of_float (1. /. frac))) |
| 77 | + else None |
| 78 | +in |
| 79 | + |
| 80 | +(* Wait for the processes to stop before accepting more *) |
| 81 | +let clean_kids k v = ( |
| 82 | + let stat = Unix.waitpid [WNOHANG] v in |
| 83 | + match (stat) with |
| 84 | + | (0,_) -> () (* Process not yet done. *) |
| 85 | + | (_, WEXITED s) -> Hashtbl.remove working_children k (* Otherwise, remove the process. *) |
| 86 | + | (_, WSIGNALED s) -> Hashtbl.remove working_children k |
| 87 | + | (_, WSTOPPED s) -> Hashtbl.remove working_children k |
| 88 | +) in |
| 89 | + |
| 90 | +(* This is the function that evaluates a revision. |
| 91 | + The function is recursive, because if some past revision of the same page |
| 92 | + that falls within the analysis horizon is not yet evaluated and colored |
| 93 | + for trust, it evaluates and colors it first. |
| 94 | + *) |
| 95 | +let rec evaluate_revision (page_id: int) (rev_id: int): unit = |
| 96 | + if !n_processed_events < !max_events_to_process then |
| 97 | + begin |
| 98 | + begin (* try ... with ... *) |
| 99 | + try |
| 100 | + Printf.printf "Evaluating revision %d of page %d\n" rev_id page_id; |
| 101 | + let page = new Online_page.page db logger page_id rev_id trust_coeff !times_to_retry_trans in |
| 102 | + n_processed_events := !n_processed_events + 1; |
| 103 | + if page#eval then begin |
| 104 | + Printf.printf "Done revision %d of page %d\n" rev_id page_id; |
| 105 | + end else begin |
| 106 | + Printf.printf "Revision %d of page %d was already done\n" rev_id page_id; |
| 107 | + end; |
| 108 | + (* Waits, if so requested to throttle the computation. *) |
| 109 | + if each_event_delay > 0 then Unix.sleep (each_event_delay); |
| 110 | + begin |
| 111 | + match every_n_events_delay with |
| 112 | + Some d -> begin |
| 113 | + if (!n_processed_events mod d) = 0 then Unix.sleep (1); |
| 114 | + end |
| 115 | + | None -> () |
| 116 | + end; |
| 117 | + |
| 118 | + with Online_page.Missing_trust (page_id', rev_id') -> |
| 119 | + begin |
| 120 | + (* We need to evaluate page_id', rev_id' first *) |
| 121 | + (* This if is a basic sanity check only. It should always be true *) |
| 122 | + if rev_id' <> rev_id then |
| 123 | + begin |
| 124 | + Printf.printf "Missing trust info: we need first to evaluate revision %d of page %d\n" rev_id' page_id'; |
| 125 | + evaluate_revision page_id' rev_id'; |
| 126 | + evaluate_revision page_id rev_id |
| 127 | + end (* rev_id' <> rev_id *) |
| 128 | + end (* with: Was missing trust of a previous revision *) |
| 129 | + end (* End of try ... with ... *) |
| 130 | + end |
| 131 | +in |
| 132 | + |
| 133 | +(* This is the code that evaluates a vote *) |
| 134 | +let evaluate_vote (page_id: int) (revision_id: int) (voter_id: int) = |
| 135 | + if !n_processed_events < !max_events_to_process then |
| 136 | + begin |
| 137 | + Printf.printf "Evaluating vote by %d on revision %d of page %d\n" voter_id revision_id page_id; |
| 138 | + let page = new Online_page.page db logger page_id revision_id trust_coeff !times_to_retry_trans in |
| 139 | + if page#vote voter_id then begin |
| 140 | + n_processed_events := !n_processed_events + 1; |
| 141 | + Printf.printf "Done revision %d of page %d\n" revision_id page_id; |
| 142 | + end; |
| 143 | + (* Waits, if so requested to throttle the computation. *) |
| 144 | + if each_event_delay > 0 then Unix.sleep (each_event_delay); |
| 145 | + begin |
| 146 | + match every_n_events_delay with |
| 147 | + Some d -> begin |
| 148 | + if (!n_processed_events mod d) = 0 then Unix.sleep (1); |
| 149 | + end |
| 150 | + | None -> () |
| 151 | + end; |
| 152 | + end |
| 153 | +in |
| 154 | + |
| 155 | +(* |
| 156 | + Returns the user id of the user name if we have it, |
| 157 | + or asks a web service for it if we do not. |
| 158 | +*) |
| 159 | +let get_user_id u_name = |
| 160 | + try db # get_user_id u_name with DB_Not_Found -> get_user_id u_name |
| 161 | +in |
| 162 | + |
| 163 | +(* Color the asked for revision. *) |
| 164 | +let process_revs (page_id : int) (rev_ids : int list) (page_title : string) |
| 165 | + (rev_timestamp : string) (user_id : int) = |
| 166 | + let rec do_processing (rev_id : int) = |
| 167 | + (* I assume that a user cannot vote on an unprocessed revision here. *) |
| 168 | + if (db # revision_needs_coloring rev_id) then ( |
| 169 | + (* Grab the text and color it. *) |
| 170 | + let last_colored_timestamp = try db # get_latest_colored_rev_timestamp |
| 171 | + page_id with DB_Not_Found -> "19700201000000" in |
| 172 | + let (wpage, wrevs) = fetch_page_and_revs_after page_title last_colored_timestamp in |
| 173 | + match wpage with |
| 174 | + | None -> Printf.printf "Failed for page %s\n" page_title |
| 175 | + | Some pp -> ( |
| 176 | + Printf.printf "Got page titled %s\n" pp.page_title; |
| 177 | + db # write_page pp |
| 178 | + ); |
| 179 | + let update_and_write_rev rev = |
| 180 | + rev.revision_page <- page_id; |
| 181 | + rev.revision_user <- (get_user_id rev.revision_user_text); |
| 182 | + db # write_revision rev |
| 183 | + in |
| 184 | + List.iter update_and_write_rev wrevs; |
| 185 | + let f rev = |
| 186 | + evaluate_revision page_id rev.revision_id |
| 187 | + in |
| 188 | + List.iter f wrevs; |
| 189 | + Unix.sleep sleep_time_sec; |
| 190 | + if !synch_log then flush Pervasives.stdout; |
| 191 | + if (db # revision_needs_coloring rev_id) then ( |
| 192 | + do_processing rev_id |
| 193 | + ) |
| 194 | + else () |
| 195 | + ) else ( (* Vote! *) |
| 196 | + let process_vote v = ( |
| 197 | + if v.vote_page_id == page_id then |
| 198 | + evaluate_vote page_id rev_id v.vote_voter_id |
| 199 | + ) in |
| 200 | + let votes = db # fetch_unprocessed_votes !max_events_to_process in |
| 201 | + List.iter process_vote votes |
| 202 | + ) |
| 203 | + in |
| 204 | + List.iter do_processing rev_ids; |
| 205 | + Printf.printf "Finished processing page %s\n" page_title; |
| 206 | + exit 0 (* No more work to do, stop this process. *) |
| 207 | +in |
| 208 | + |
| 209 | +(* Start a new process going which actually processes the missing page. *) |
| 210 | +let dispatch_page rev_pages = |
| 211 | + let new_pages = Hashtbl.create (List.length rev_pages) in |
| 212 | + let is_new_page p = |
| 213 | + try ignore (Hashtbl.find working_children p); false with Not_found -> true |
| 214 | + in |
| 215 | + let set_revs_to_get (r,p,title,time,uid) = |
| 216 | + Printf.printf "page %d\n" p; |
| 217 | + if (is_new_page p) then ( |
| 218 | + ( |
| 219 | + let current_revs = try Hashtbl.find new_pages p with |
| 220 | + Not_found -> ([],title,time,uid) in |
| 221 | + (Hashtbl.replace new_pages p ((r::(let x,_,_,_ = |
| 222 | + current_revs in x)), |
| 223 | + title,time,uid)) |
| 224 | + ) |
| 225 | + ) else () |
| 226 | + in |
| 227 | + let launch_processing p (r,t,rt,uid) = ( |
| 228 | + let new_pid = Unix.fork () in |
| 229 | + match new_pid with |
| 230 | + | 0 -> ( |
| 231 | + Printf.printf "I'm the child\n Running on page %d rev %d\n" p |
| 232 | + (List.hd r); |
| 233 | + process_revs p r t rt uid |
| 234 | + ) |
| 235 | + | _ -> (Printf.printf "Parent of pid %d\n" new_pid; |
| 236 | + Hashtbl.add working_children p (new_pid) |
| 237 | + ) |
| 238 | + ) in |
| 239 | + Hashtbl.iter clean_kids working_children; |
| 240 | + List.iter set_revs_to_get rev_pages; |
| 241 | + Hashtbl.iter launch_processing new_pages |
| 242 | +in |
| 243 | + |
| 244 | +(* Poll to see if there is any more work to be done. *) |
| 245 | +let rec main_loop () = |
| 246 | + if (Hashtbl.length working_children) >= max_concurrent_procs then ( |
| 247 | + Hashtbl.iter clean_kids working_children |
| 248 | + ) else ( |
| 249 | + let revs_to_process = db # fetch_next_to_color |
| 250 | + (max (max_concurrent_procs - Hashtbl.length working_children) 0) in |
| 251 | + dispatch_page revs_to_process |
| 252 | + ); |
| 253 | + Unix.sleep sleep_time_sec; |
| 254 | + if !synch_log then flush Pervasives.stdout; |
| 255 | + main_loop () |
| 256 | +in |
| 257 | + |
| 258 | +main_loop () |
Property changes on: trunk/extensions/WikiTrust/remote/analysis/server_coloring_dispatcher.ml |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 259 | + native |
Index: trunk/extensions/WikiTrust/remote/analysis/tmpfile.mli |
— | — | @@ -0,0 +1,25 @@ |
| 2 | +(***********************************************************************) |
| 3 | +(* *) |
| 4 | +(* Objective Caml *) |
| 5 | +(* *) |
| 6 | +(* Fran�ois Pessaux, projet Cristal, INRIA Rocquencourt *) |
| 7 | +(* Pierre Weis, projet Cristal, INRIA Rocquencourt *) |
| 8 | +(* Jun Furuse, projet Cristal, INRIA Rocquencourt *) |
| 9 | +(* *) |
| 10 | +(* Copyright 1999 - 2003 *) |
| 11 | +(* Institut National de Recherche en Informatique et en Automatique. *) |
| 12 | +(* Distributed only by permission. *) |
| 13 | +(* *) |
| 14 | +(***********************************************************************) |
| 15 | + |
| 16 | +val tmp_dir : string ref |
| 17 | +(* swap file directory: the default is /tmp, but note that it is often |
| 18 | + the case that /tmp is not large enough for some huge images!! *) |
| 19 | + |
| 20 | +val new_tmp_file_name : string -> string |
| 21 | +(* [new_swap_file_name prefix] returns a new swap file name with |
| 22 | + prefix [prefix]. *) |
| 23 | + |
| 24 | +val remove_tmp_file : string -> unit |
| 25 | +(* [remove_tmp_file fname] removes [fname] if it can; nothing |
| 26 | + happens if [fname] cannot be removed. *) |
Property changes on: trunk/extensions/WikiTrust/remote/analysis/tmpfile.mli |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 27 | + native |
Index: trunk/extensions/WikiTrust/remote/analysis/wikipedia_api.ml |
— | — | @@ -0,0 +1,193 @@ |
| 2 | +(* |
| 3 | + |
| 4 | +Copyright (c) 2007-2008 The Regents of the University of California |
| 5 | +All rights reserved. |
| 6 | + |
| 7 | +Authors: Luca de Alfaro, Ian Pye |
| 8 | + |
| 9 | +Redistribution and use in source and binary forms, with or without |
| 10 | +modification, are permitted provided that the following conditions are met: |
| 11 | + |
| 12 | +1. Redistributions of source code must retain the above copyright notice, |
| 13 | +this list of conditions and the following disclaimer. |
| 14 | + |
| 15 | +2. Redistributions in binary form must reproduce the above copyright notice, |
| 16 | +this list of conditions and the following disclaimer in the documentation |
| 17 | +and/or other materials provided with the distribution. |
| 18 | + |
| 19 | +3. The names of the contributors may not be used to endorse or promote |
| 20 | +products derived from this software without specific prior written |
| 21 | +permission. |
| 22 | + |
| 23 | +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| 24 | +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 25 | +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 26 | +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
| 27 | +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 28 | +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 29 | +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| 30 | +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| 31 | +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 32 | +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 33 | +POSSIBILITY OF SUCH DAMAGE. |
| 34 | + |
| 35 | + *) |
| 36 | + |
| 37 | +(* Using the wikipedia API, retrieves information about pages and revisions *) |
| 38 | + |
| 39 | +open Http_client;; |
| 40 | +open ExtLib;; |
| 41 | +open Gzip;; |
| 42 | +open Xml;; |
| 43 | +open Online_types;; |
| 44 | +open Str;; |
| 45 | + |
| 46 | +exception Http_client_error |
| 47 | + |
| 48 | +Random.self_init () |
| 49 | + |
| 50 | +let pipeline = new pipeline |
| 51 | +let buf_len = 8192 |
| 52 | +let requested_encoding_type = "gzip" |
| 53 | +let tmp_prefix = "wiki" |
| 54 | +let rev_lim = "50" |
| 55 | +let api_tz_re = Str.regexp "\\([0-9][0-9][0-9][0-9]\\)-\\([0-9][0-9]\\)-\\([0-9][0-9]\\)T\\([0-9][0-9]\\):\\([0-9][0-9]\\):\\([0-9][0-9]\\)Z" |
| 56 | + |
| 57 | +(* Maps the Wikipedias api timestamp to our internal one. *) |
| 58 | +let api_ts2mw_ts s = |
| 59 | + let ts = if string_match api_tz_re s 0 then |
| 60 | + (matched_group 1 s) ^ (matched_group 2 s) ^ (matched_group 3 s) |
| 61 | + ^ (matched_group 4 s) ^ (matched_group 5 s) ^ (matched_group 6 s) |
| 62 | + else "19700201000000" in |
| 63 | + ts |
| 64 | + |
| 65 | +(* Given an input channel, return a string representing all there is |
| 66 | + to be read of this channel. *) |
| 67 | +let input_all ic = |
| 68 | + let rec loop acc total buf ofs = |
| 69 | + let n = input ic buf ofs (buf_len - ofs) in |
| 70 | + if n = 0 then |
| 71 | + let res = String.create total in |
| 72 | + let pos = total - ofs in |
| 73 | + let _ = String.blit buf 0 res pos ofs in |
| 74 | + let coll pos buf = |
| 75 | + let new_pos = pos - buf_len in |
| 76 | + String.blit buf 0 res new_pos buf_len; |
| 77 | + new_pos in |
| 78 | + let _ = List.fold_left coll pos acc in |
| 79 | + res |
| 80 | + else |
| 81 | + let new_ofs = ofs + n in |
| 82 | + let new_total = total + n in |
| 83 | + if new_ofs = buf_len then |
| 84 | + loop (buf :: acc) new_total (String.create buf_len) 0 |
| 85 | + else loop acc new_total buf new_ofs in |
| 86 | + loop [] 0 (String.create buf_len) 0 |
| 87 | + |
| 88 | +(* |
| 89 | + Given a string url, make a get call and return the response as a string. |
| 90 | +*) |
| 91 | +let run_call url = |
| 92 | + let call = new get url in |
| 93 | + let request_header = call # request_header `Base in |
| 94 | + (* Accept gziped format *) |
| 95 | + request_header # update_field "Accept-encoding" requested_encoding_type; |
| 96 | + call # set_request_header request_header; |
| 97 | + pipeline # add call; |
| 98 | + pipeline # run(); |
| 99 | + match call # status with |
| 100 | + | `Successful -> ( |
| 101 | + let body = call # response_body # value in |
| 102 | + let repsponse_header = call # response_header in |
| 103 | + Printf.printf "content_type: %s\n" |
| 104 | + (let cnt,_ = (repsponse_header # content_type ()) in cnt); |
| 105 | + match (repsponse_header # content_type ()) with |
| 106 | + | ("text/xml",_) -> ( |
| 107 | + let tmp_file = Tmpfile.new_tmp_file_name tmp_prefix in |
| 108 | + Std.output_file ~filename:tmp_file ~text:body; |
| 109 | + let in_chan = Gzip.open_in tmp_file in |
| 110 | + let decoded_body = input_all in_chan in |
| 111 | + Gzip.close_in in_chan; |
| 112 | + Tmpfile.remove_tmp_file tmp_file; |
| 113 | + decoded_body |
| 114 | + ) |
| 115 | + | _ -> body |
| 116 | + ) |
| 117 | + | _ -> raise Http_client_error |
| 118 | +;; |
| 119 | + |
| 120 | +(* |
| 121 | + Internal xml processing for the api |
| 122 | +*) |
| 123 | +let process_rev (rev : xml) : wiki_revision = |
| 124 | + let w_rev = { |
| 125 | + revision_id = int_of_string (Xml.attrib rev "revid"); |
| 126 | + revision_page = 0; |
| 127 | + revision_text_id = int_of_string (Xml.attrib rev "revid"); |
| 128 | + revision_comment = (try (Xml.attrib rev "comment") |
| 129 | + with Xml.No_attribute e -> ""); |
| 130 | + revision_user = -1; |
| 131 | + revision_user_text = (Xml.attrib rev "user"); |
| 132 | + revision_timestamp = api_ts2mw_ts (Xml.attrib rev "timestamp"); |
| 133 | + revision_minor_edit = (try ignore(Xml.attrib rev "minor"); true |
| 134 | + with Xml.No_attribute e -> false); |
| 135 | + revision_deleted = false; |
| 136 | + revision_len = (try int_of_string (Xml.attrib rev "size") with Xml.No_attribute e -> 0); |
| 137 | + revision_parent_id = 0; |
| 138 | + revision_content = (Netencoding.Html.decode ~in_enc:`Enc_utf8 |
| 139 | + ~out_enc:`Enc_utf8 () |
| 140 | + (Xml.to_string (List.hd (Xml.children rev)))); |
| 141 | + } in |
| 142 | + w_rev |
| 143 | + |
| 144 | +(* |
| 145 | + Internal xml processing for the api |
| 146 | +*) |
| 147 | +let process_page (page : xml) : (wiki_page option * wiki_revision list) = |
| 148 | + let w_page = { |
| 149 | + page_id = int_of_string (Xml.attrib page "pageid"); |
| 150 | + page_namespace = (int_of_string (Xml.attrib page "ns")); |
| 151 | + page_title = (Xml.attrib page "title"); |
| 152 | + page_restrictions = ""; |
| 153 | + page_counter = int_of_string (Xml.attrib page "counter"); |
| 154 | + page_is_redirect = (try ignore(Xml.attrib page "redirect"); true |
| 155 | + with Xml.No_attribute e -> false); |
| 156 | + page_is_new = false; |
| 157 | + page_random = (Random.float 1.0); |
| 158 | + page_touched = api_ts2mw_ts (Xml.attrib page "touched"); |
| 159 | + page_latest = int_of_string (Xml.attrib page "lastrevid"); |
| 160 | + page_len = int_of_string (Xml.attrib page "length") |
| 161 | + } in |
| 162 | + let revs = Xml.children page in |
| 163 | + (Some w_page, (Xml.map process_rev (List.hd revs))) |
| 164 | + |
| 165 | +(* |
| 166 | + Given a page and date to start with, returns the next n revs for this page. |
| 167 | +*) |
| 168 | +let fetch_page_and_revs_after (page_title : string) (rev_date : string) : (wiki_page option * wiki_revision list) = |
| 169 | + let url = !Online_command_line.target_wikimedia |
| 170 | + ^ "?action=query&prop=revisions|" |
| 171 | + ^ "info&format=xml&inprop=&rvprop=ids|flags|timestamp|user|size|comment|" |
| 172 | + ^ "content&rvstart=" ^ rev_date ^ "&rvlimit=" ^ rev_lim |
| 173 | + ^ "&rvdir=newer&titles=" ^ page_title in |
| 174 | + if !Online_command_line.dump_db_calls then Printf.printf "%s\n" url; |
| 175 | + let res = run_call url in |
| 176 | + let api = Xml.parse_string res in |
| 177 | + let query = Xml.children (api) in |
| 178 | + let poss_pages = Xml.children (List.hd query) in |
| 179 | + let pick_page acc page = |
| 180 | + if (Xml.tag page = "pages") then |
| 181 | + process_page (List.hd (Xml.children page)) |
| 182 | + else acc |
| 183 | + in |
| 184 | + List.fold_left pick_page (None,[]) poss_pages |
| 185 | +;; |
| 186 | + |
| 187 | +(* Given a user_name, returns the corresponding user_id *) |
| 188 | +let get_user_id (user_name : string) : int = |
| 189 | + let url = !Online_command_line.user_id_server ^ "?n=" ^ user_name in |
| 190 | + if !Online_command_line.dump_db_calls then Printf.printf "%s\n" url; |
| 191 | + let uids = ExtString.String.nsplit (run_call url) "`" in |
| 192 | + let uid = List.nth uids 1 in |
| 193 | + try int_of_string uid with int_of_string -> 0 in |
| 194 | +;; |
Property changes on: trunk/extensions/WikiTrust/remote/analysis/wikipedia_api.ml |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 195 | + native |
Index: trunk/extensions/WikiTrust/remote/analysis/tmpfile.ml |
— | — | @@ -0,0 +1,37 @@ |
| 2 | +(***********************************************************************) |
| 3 | +(* *) |
| 4 | +(* Objective Caml *) |
| 5 | +(* *) |
| 6 | +(* Fran�ois Pessaux, projet Cristal, INRIA Rocquencourt *) |
| 7 | +(* Pierre Weis, projet Cristal, INRIA Rocquencourt *) |
| 8 | +(* Jun Furuse, projet Cristal, INRIA Rocquencourt *) |
| 9 | +(* *) |
| 10 | +(* Copyright 1999 - 2003 *) |
| 11 | +(* Institut National de Recherche en Informatique et en Automatique. *) |
| 12 | +(* Distributed only by permission. *) |
| 13 | +(* *) |
| 14 | +(***********************************************************************) |
| 15 | + |
| 16 | +(* temporary directory *) |
| 17 | +let tmp_dir = ref (try Sys.getenv "CAMLTMPDIR" with Not_found -> "/tmp");; |
| 18 | + |
| 19 | +let cnter = ref 0;; |
| 20 | + |
| 21 | +let rec new_tmp_name prefx = |
| 22 | + incr cnter; |
| 23 | + let name = |
| 24 | + Filename.concat !tmp_dir |
| 25 | + (Printf.sprintf "camltmp-%s-%d" prefx !cnter) in |
| 26 | + if not (Sys.file_exists name) then name else begin |
| 27 | + prerr_endline ("Warning: tmp file " ^ name ^ " already exists"); |
| 28 | + new_tmp_name prefx |
| 29 | + end;; |
| 30 | + |
| 31 | +let remove_tmp_file tmpfile = try Sys.remove tmpfile with _ -> ();; |
| 32 | + |
| 33 | +let new_tmp_file_name prefx = |
| 34 | + if not (Sys.file_exists !tmp_dir) then |
| 35 | + failwith ("Temporary directory " ^ !tmp_dir ^ " does not exist") else |
| 36 | + let f = new_tmp_name prefx in |
| 37 | + at_exit (fun () -> remove_tmp_file f); |
| 38 | + f;; |
Property changes on: trunk/extensions/WikiTrust/remote/analysis/tmpfile.ml |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 39 | + native |
Index: trunk/extensions/WikiTrust/remote/mediawiki/extensions/Trust/RemoteTrust.php |
— | — | @@ -0,0 +1,163 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +# Copyright (c) 2007,2008 Luca de Alfaro |
| 5 | +# Copyright (c) 2007,2008 Ian Pye |
| 6 | +# Copyright (c) 2007 Jason Benterou |
| 7 | +# |
| 8 | +# This program is free software; you can redistribute it and/or |
| 9 | +# modify it under the terms of the GNU General Public License as |
| 10 | +# published by the Free Software Foundation; either version 2 of the |
| 11 | +# License, or (at your option) any later version. |
| 12 | + |
| 13 | +# This program is distributed in the hope that it will be useful, but |
| 14 | +# WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 16 | +# General Public License for more details. |
| 17 | + |
| 18 | +# You should have received a copy of the GNU General Public License |
| 19 | +# along with this program; if not, write to the Free Software |
| 20 | +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
| 21 | +# USA |
| 22 | + |
| 23 | +## MW extension |
| 24 | +# This defines a custom MW function to map trust values to HTML markup |
| 25 | +# |
| 26 | +# Uses Tool Tip JS library under the LGPL. |
| 27 | +# http://www.walterzorn.com/tooltip/tooltip_e.htm |
| 28 | + |
| 29 | +$dir = dirname(__FILE__) . '/'; |
| 30 | + |
| 31 | +$wgExtensionMessagesFiles['RemoteTrust'] = $dir.'/RemoteTrust.i18n.php'; |
| 32 | + |
| 33 | +# Credits |
| 34 | +$wgExtensionCredits['other'][] = array( |
| 35 | + 'name' => |
| 36 | + 'Text Attribution and Trust', |
| 37 | + 'author' => |
| 38 | + 'Ian Pye, Luca de Alfaro', |
| 39 | + 'url' => |
| 40 | + 'http://trust.cse.ucsc.edu', |
| 41 | + 'description' => |
| 42 | + 'Text is colored according to how much it has been revised. An orange background indicates new, unrevised, text; white is for text that has been revised by many reputed authors. If you click on a word, you will be redirected to the diff corresponding to the edit where the word was introduced. If you hover over a word, a pop-up displays the word author.' |
| 43 | + ); |
| 44 | + |
| 45 | +$wgAutoloadClasses['TextTrustImpl'] = $dir . 'RemoteTrustImpl.php'; |
| 46 | +$wgAutoloadClasses['TextTrustUpdate'] = $dir . 'RemoteTrustUpdate.php'; |
| 47 | +$wgExtensionFunctions[] = 'TextTrust::init'; |
| 48 | + |
| 49 | +class TextTrust { |
| 50 | + |
| 51 | + // Instance of our TrustImpl class |
| 52 | + private static $trust; |
| 53 | + |
| 54 | + /** |
| 55 | + * Initializes and configures the extension. |
| 56 | + */ |
| 57 | + public static function init() { |
| 58 | + global $wgHooks, $wgParser, $wgRequest, $wgUseAjax, $wgAjaxExportList, |
| 59 | + $wgUser, $wgOut, $wgScriptPath, $wgExtensionMessagesFiles, |
| 60 | + $wgShowVoteButton; |
| 61 | + |
| 62 | + // ParserFirstCallInit was introduced in modern (1.12+) MW versions so as to |
| 63 | + // avoid unstubbing $wgParser on setHook() too early, as per r35980 |
| 64 | + if (!defined( 'MW_SUPPORTS_PARSERFIRSTCALLINIT' )) { |
| 65 | + global $wgParser; |
| 66 | + wfRunHooks( 'ParserFirstCallInit', $wgParser ); |
| 67 | + } |
| 68 | + |
| 69 | +# Updater fired when updating to a new version of MW. |
| 70 | + $wgHooks['LoadExtensionSchemaUpdates'][] = 'TextTrustUpdate::updateDB'; |
| 71 | + |
| 72 | +# And add and extra tab. |
| 73 | + $wgHooks['SkinTemplateTabs'][] = 'TextTrust::ucscTrustTemplate'; |
| 74 | + |
| 75 | + // Is the user opting to use wikitrust? |
| 76 | + $tname = "gadget-WikiTrust"; |
| 77 | + if (!$wgUser->getOption( $tname ) ) { |
| 78 | + return; |
| 79 | + } |
| 80 | + |
| 81 | + // Return if trust is not selected. |
| 82 | + if(!$wgRequest->getVal('trust') || $wgRequest->getVal('action')){ |
| 83 | + return; |
| 84 | + } |
| 85 | + |
| 86 | +# Code which takes the "I vote" action. |
| 87 | + if($wgUseAjax && $wgShowVoteButton){ |
| 88 | + $wgAjaxExportList[] = "TextTrustImpl::handleVote"; |
| 89 | + } |
| 90 | + |
| 91 | +# Add trust CSS and JS |
| 92 | + $wgHooks['OutputPageBeforeHTML'][] ='TextTrust::ucscColorTrust_OP'; |
| 93 | + |
| 94 | +# Add a hook to initialise the magic words |
| 95 | + $wgHooks['LanguageGetMagic'][] = 'TextTrust::ucscColorTrust_Magic'; |
| 96 | + |
| 97 | +# Set a function hook associating the blame and trust words with a callback function |
| 98 | + $wgParser->setFunctionHook( 't', 'TextTrust::ucscColorTrust_Render'); |
| 99 | + |
| 100 | +# After everything, make the blame info work |
| 101 | + $wgHooks['ParserAfterTidy'][] = 'TextTrust::ucscOrigin_Finalize'; |
| 102 | + } |
| 103 | + |
| 104 | + private static function getTrustObj(){ |
| 105 | + if (!self::$trust){ |
| 106 | + self::$trust = new TextTrustImpl(); |
| 107 | + } |
| 108 | + } |
| 109 | + |
| 110 | + // Handle trust tab. |
| 111 | + // This is here because we use it all the time. |
| 112 | + public static function ucscTrustTemplate($skin, &$content_actions){ |
| 113 | + |
| 114 | + global $wgRequest; |
| 115 | + wfLoadExtensionMessages('RemoteTrust'); |
| 116 | + |
| 117 | + if ($wgRequest->getVal('action') || $wgRequest->getVal('diff')){ |
| 118 | + // we don't want trust for actions or diffs. |
| 119 | + return true; |
| 120 | + } |
| 121 | + |
| 122 | + $trust_qs = $_SERVER['QUERY_STRING']; |
| 123 | + if($trust_qs){ |
| 124 | + $trust_qs = "?" . $trust_qs . "&trust=t"; |
| 125 | + } else { |
| 126 | + $trust_qs .= "?trust=t"; |
| 127 | + } |
| 128 | + |
| 129 | + $content_actions['trust'] = array ( 'class' => '', |
| 130 | + 'text' => |
| 131 | + wfMsgNoTrans("wgTrustTabText"), |
| 132 | + 'href' => |
| 133 | + $_SERVER['PHP_SELF'] . $trust_qs ); |
| 134 | + |
| 135 | + if($wgRequest->getVal('trust')){ |
| 136 | + $content_actions['trust']['class'] = 'selected'; |
| 137 | + $content_actions['nstab-main']['class'] = ''; |
| 138 | + $content_actions['nstab-main']['href'] .= ''; |
| 139 | + } else { |
| 140 | + $content_actions['trust']['href'] .= ''; |
| 141 | + } |
| 142 | + return true; |
| 143 | + } |
| 144 | + |
| 145 | + public static function ucscColorTrust_OP(&$out, &$text){ |
| 146 | + self::getTrustObj(); |
| 147 | + return self::$trust->ucscColorTrust_OP($out, $text); |
| 148 | + } |
| 149 | + public static function ucscColorTrust_Magic(&$magicWords, $langCode){ |
| 150 | + self::getTrustObj(); |
| 151 | + return self::$trust->ucscColorTrust_Magic($magicWords, $langCode); |
| 152 | + } |
| 153 | + public static function ucscColorTrust_Render(&$parser, |
| 154 | + $combinedValue = "0,0,0"){ |
| 155 | + self::getTrustObj(); |
| 156 | + return self::$trust->ucscColorTrust_Render($parser, $combinedValue); |
| 157 | + } |
| 158 | + public static function ucscOrigin_Finalize(&$parser, &$text){ |
| 159 | + self::getTrustObj(); |
| 160 | + return self::$trust->ucscOrigin_Finalize($parser, $text); |
| 161 | + } |
| 162 | +} |
| 163 | + |
| 164 | +?> |
Index: trunk/extensions/WikiTrust/remote/mediawiki/extensions/Trust/RemoteTrustImpl.php |
— | — | @@ -0,0 +1,390 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class TextTrustImpl { |
| 5 | + |
| 6 | + ## Types of analysis to perform. |
| 7 | + const TRUST_EVAL_VOTE = 0; |
| 8 | + const TRUST_EVAL_EDIT = 10; |
| 9 | + const TRUST_EVAL_MISSING = 15; |
| 10 | + |
| 11 | + ## the css tag to use |
| 12 | + const TRUST_CSS_TAG = "background-color"; ## color the background |
| 13 | + #$TRUST_CSS_TAG = "color"; ## color just the text |
| 14 | + |
| 15 | + ## ColorText is called multiple times, but we only want to color true text. |
| 16 | + const DIFF_TOKEN_TO_COLOR = "Lin"; |
| 17 | + |
| 18 | + ## Trust normalization values; |
| 19 | + const MAX_TRUST_VALUE = 9; |
| 20 | + const MIN_TRUST_VALUE = 0; |
| 21 | + const TRUST_MULTIPLIER = 10; |
| 22 | + |
| 23 | + ## Token to split trust and origin values on |
| 24 | + const TRUST_SPLIT_TOKEN = ','; |
| 25 | + |
| 26 | + ## Token to be replaed with < |
| 27 | + const TRUST_OPEN_TOKEN = "QQampo:"; |
| 28 | + |
| 29 | + ## Token to be replaed with > |
| 30 | + const TRUST_CLOSE_TOKEN = ":ampc:"; |
| 31 | + |
| 32 | + ## Server forms |
| 33 | + const NOT_FOUND_TEXT_TOKEN = "TEXT_NOT_FOUND"; |
| 34 | + const TRUST_COLOR_TOKEN = "<!--trust-->"; |
| 35 | + |
| 36 | + ## Context for communicating with the trust server |
| 37 | + const TRUST_TIMEOUT = 10; |
| 38 | + |
| 39 | + ## Median Value of Trust |
| 40 | + var $median = 1.0; |
| 41 | + |
| 42 | + ## Number of times a revision is looked at. |
| 43 | + var $times_rev_loaded = 0; |
| 44 | + |
| 45 | + ## Load the article we are talking about |
| 46 | + var $title; |
| 47 | + |
| 48 | + ## Only color the text once. |
| 49 | + var $colored = false; |
| 50 | + |
| 51 | + ## Don't close the first opening span tag |
| 52 | + var $first_span = true; |
| 53 | + |
| 54 | + ## And the same for origin tags |
| 55 | + var $first_origin = true; |
| 56 | + |
| 57 | + ## And the last revision of the title |
| 58 | + var $current_rev; |
| 59 | + |
| 60 | + ## Only add the scripts once. |
| 61 | + var $scripts_added = false; |
| 62 | + |
| 63 | + ## map trust values to html color codes |
| 64 | + var $COLORS = array( |
| 65 | + "trust0", |
| 66 | + "trust1", |
| 67 | + "trust2", |
| 68 | + "trust3", |
| 69 | + "trust4", |
| 70 | + "trust5", |
| 71 | + "trust6", |
| 72 | + "trust7", |
| 73 | + "trust9", |
| 74 | + "trust10", |
| 75 | + ); |
| 76 | + |
| 77 | + ## default values for variables found from LocalSettings.php |
| 78 | + var $DEFAULTS = array( |
| 79 | + 'wgShowVoteButton' => false, |
| 80 | + 'wgTrustCmd' => "eval_online_wiki", |
| 81 | + 'wgTrustLog' => "/dev/null", |
| 82 | + 'wgTrustDebugLog' => "/dev/null", |
| 83 | + 'wgRepSpeed' => 1.0, |
| 84 | + 'wgContentServerURL' => "http://localhost:10302/?", |
| 85 | + ); |
| 86 | + |
| 87 | + ## Only write a new trust tag when the trust changes. |
| 88 | + var $current_trust = "trust0"; |
| 89 | + |
| 90 | + public function TextTrustImpl(){ |
| 91 | + global $wgShowVoteButton, $wgTrustCmd, $wgTrustLog, |
| 92 | + $wgTrustDebugLog, $wgContentServerURL, $wgRepSpeed; |
| 93 | + |
| 94 | + # Add localized messages. |
| 95 | + wfLoadExtensionMessages('RemoteTrust'); |
| 96 | + |
| 97 | + //Add default values if globals not set. |
| 98 | + if(!$wgShowVoteButton) |
| 99 | + $wgShowVoteButton = $this->DEFAULTS['wgShowVoteButton']; |
| 100 | + if(!$wgTrustCmd) |
| 101 | + $wgTrustCmd = $this->DEFAULTS['wgTrustCmd' ]; |
| 102 | + if(!$wgTrustLog) |
| 103 | + $wgTrustLog = $this->DEFAULTS['wgTrustLog']; |
| 104 | + if(!$wgTrustDebugLog) |
| 105 | + $wgTrustDebugLog = $this->DEFAULTS['wgTrustDebugLog']; |
| 106 | + if(!$wgRepSpeed) |
| 107 | + $wgRepSpeed = $this->DEFAULTS['wgRepSpeed']; |
| 108 | + if(!$wgContentServerURL) |
| 109 | + $wgContentServerURL = $this->DEFAULTS['wgContentServerURL']; |
| 110 | + } |
| 111 | + |
| 112 | + /** |
| 113 | + Records the vote. |
| 114 | + Called via ajax, so this must be static. |
| 115 | + */ |
| 116 | + static function handleVote($user_name_raw, $page_id_raw = 0, |
| 117 | + $rev_id_raw = 0, $page_title = ""){ |
| 118 | + |
| 119 | + global $wgContentServerURL; |
| 120 | + $response = new AjaxResponse("0"); |
| 121 | + |
| 122 | + $dbr =& wfGetDB( DB_SLAVE ); |
| 123 | + |
| 124 | + $userName = $dbr->strencode($user_name_raw, $dbr); |
| 125 | + $page_id = $dbr->strencode($page_id_raw, $dbr); |
| 126 | + $rev_id = $dbr->strencode($rev_id_raw, $dbr); |
| 127 | + |
| 128 | + if($page_id){ |
| 129 | + // First, look up the id numbers from the page and user strings |
| 130 | + $res = $dbr->select('user', array('user_id'), |
| 131 | + array('user_name' => $userName), array()); |
| 132 | + if ($res){ |
| 133 | + $row = $dbr->fetchRow($res); |
| 134 | + $user_id = $row['user_id']; |
| 135 | + if (!$user_id) { |
| 136 | + $user_id = 0; |
| 137 | + } |
| 138 | + } |
| 139 | + $dbr->freeResult( $res ); |
| 140 | + |
| 141 | + $ctx = stream_context_create( |
| 142 | + array('http' => array( |
| 143 | + 'timeout' => |
| 144 | + self::TRUST_TIMEOUT |
| 145 | + ) |
| 146 | + ) |
| 147 | + ); |
| 148 | + |
| 149 | + $vote_str = ("Voting at " . $wgContentServerURL . "vote=1&rev=$rev_id&page=$page_id&user=$user_id&page_title=$page_title&time=" . wfTimestampNow()); |
| 150 | + $colored_text = file_get_contents($wgContentServerURL . "vote=1&rev=".urlencode($rev_id)."&page=".urlencode($page_id)."&user=".urlencode($user_id)."&page_title=".urlencode($page_title)."&time=" . urlencode(wfTimestampNow()), 0, $ctx); |
| 151 | + $response = new AjaxResponse($vote_str); |
| 152 | + } |
| 153 | + return $response; |
| 154 | + } |
| 155 | + |
| 156 | + /** |
| 157 | + Called just before rendering HTML. |
| 158 | + We add the coloring scripts here. |
| 159 | + */ |
| 160 | + function ucscColorTrust_OP(&$out, &$text){ |
| 161 | + global $wgScriptPath; |
| 162 | + |
| 163 | + if (!$this->scripts_added){ // Only add the scripts once. |
| 164 | + $out->addScript("<script type=\"text/javascript\" src=\"".$wgScriptPath."/extensions/Trust/js/trust.js\"></script>\n"); |
| 165 | + $out->addScript("<link rel=\"stylesheet\" type=\"text/css\" href=\"".$wgScriptPath."/extensions/Trust/css/trust.css\" />\n"); |
| 166 | + $this->scripts_added = true; |
| 167 | + } |
| 168 | + return true; |
| 169 | + } |
| 170 | + |
| 171 | + /** |
| 172 | + If colored text exists, use it instead of the normal text, |
| 173 | + but only if the trust tab is selected. |
| 174 | + */ |
| 175 | + function ucscSeeIfColored(&$parser, &$text, &$strip_state = Null) { |
| 176 | + global $wgRequest, $wgUseAjax, $wgShowVoteButton, $wgDBprefix, |
| 177 | + $wgContentServerURL; |
| 178 | + |
| 179 | + // Get the db. |
| 180 | + $dbr =& wfGetDB( DB_SLAVE ); |
| 181 | + |
| 182 | + // Do we use a DB prefix? |
| 183 | + $prefix = ($wgDBprefix)? "-db_prefix " . $dbr->strencode($wgDBprefix): ""; |
| 184 | + |
| 185 | + // Text for showing the "I like it" button |
| 186 | + $voteitText = ""; |
| 187 | + if ($wgUseAjax && $wgShowVoteButton){ |
| 188 | + $voteitText = " |
| 189 | +".self::TRUST_OPEN_TOKEN."div id='vote-button'".self::TRUST_CLOSE_TOKEN."".self::TRUST_OPEN_TOKEN."input type='button' name='vote' value='" . wfMsgNoTrans("wgVoteText") . "' onclick='startVote()' /".self::TRUST_CLOSE_TOKEN."".self::TRUST_OPEN_TOKEN."/div".self::TRUST_CLOSE_TOKEN." |
| 190 | +".self::TRUST_OPEN_TOKEN."div id='vote-button-done'".self::TRUST_CLOSE_TOKEN . wfMsgNoTrans("wgThankYouForVoting") . self::TRUST_OPEN_TOKEN."/div".self::TRUST_CLOSE_TOKEN." |
| 191 | +"; |
| 192 | + } |
| 193 | + |
| 194 | + // Return if trust is not selected. |
| 195 | + if(!$wgRequest->getVal('trust') || $wgRequest->getVal('action')){ |
| 196 | + return true; |
| 197 | + } |
| 198 | + |
| 199 | + // Save the title object, if it is not already present |
| 200 | + if (!$this->title){ |
| 201 | + $this->title = $parser->getTitle(); |
| 202 | + } |
| 203 | + |
| 204 | + // count the number of times we load this text |
| 205 | + $this->times_rev_loaded++; |
| 206 | + |
| 207 | + // Load the current revision id. |
| 208 | + if (!$this->current_rev){ |
| 209 | + if ($parser->mRevisionId){ |
| 210 | + $this->current_rev = $parser->mRevisionId; |
| 211 | + } else { |
| 212 | + // Sometimes the revisionId field is not filled in. |
| 213 | + $this->current_rev = $this->title->getPreviousRevisionID( PHP_INT_MAX ); |
| 214 | + } |
| 215 | + } |
| 216 | + |
| 217 | + /** |
| 218 | + This method is being called multiple times for each page. |
| 219 | + We only pull the colored text for the first time through. |
| 220 | + */ |
| 221 | + if ($this->colored){ |
| 222 | + return true; |
| 223 | + } |
| 224 | + |
| 225 | + if ($wgRequest->getVal('diff')){ |
| 226 | + // For diffs, look for the absence of the diff token instead of counting |
| 227 | + if(substr($text,0,3) == self::DIFF_TOKEN_TO_COLOR){ |
| 228 | + return true; |
| 229 | + } |
| 230 | + } |
| 231 | + |
| 232 | + // if we made it here, we are going to color some text |
| 233 | + $this->colored = true; |
| 234 | + |
| 235 | + // Check to see if this page is part of the coloring project. |
| 236 | + // Disabled for now. |
| 237 | + //if (!strstr($text, self::TRUST_COLOR_TOKEN)){ |
| 238 | + // $text = $wgNotPartExplanation . "\n" . $text; |
| 239 | + // return true; |
| 240 | + //} |
| 241 | + |
| 242 | + // Get the page id and other data |
| 243 | + $colored_text=""; |
| 244 | + $page_id=0; |
| 245 | + $rev_timestamp=""; |
| 246 | + $rev_user=0; |
| 247 | + $res = $dbr->select('revision', array('rev_page', 'rev_timestamp', |
| 248 | + 'rev_user'), |
| 249 | + array('rev_id' => $this->current_rev), array()); |
| 250 | + if ($res){ |
| 251 | + $row = $dbr->fetchRow($res); |
| 252 | + $page_id = $row['rev_page']; |
| 253 | + $rev_user = $row['rev_user']; |
| 254 | + $rev_timestamp = $row['rev_timestamp']; |
| 255 | + if (!$page_id) { |
| 256 | + $page_id = 0; |
| 257 | + } |
| 258 | + } |
| 259 | + $dbr->freeResult( $res ); |
| 260 | + |
| 261 | + $page_title = $_GET['title']; |
| 262 | + $ctx = stream_context_create( |
| 263 | + array('http' => array( |
| 264 | + 'timeout' => |
| 265 | + self::TRUST_TIMEOUT |
| 266 | + ) |
| 267 | + ) |
| 268 | + ); |
| 269 | + |
| 270 | + // Should we do doing this via HTTPS? |
| 271 | + $colored_raw = (file_get_contents($wgContentServerURL . "rev=" . urlencode($this->current_rev) . "&page=".urlencode($page_id)."&page_title=".urlencode($page_title)."&time=".urlencode($rev_timestamp)."&user=".urlencode($rev_user)."", 0, $ctx)); |
| 272 | + |
| 273 | + if ($colored_raw && $colored_raw != self::NOT_FOUND_TEXT_TOKEN){ |
| 274 | + |
| 275 | + // Inflate. Pick off the first 10 bytes for python-php conversion. |
| 276 | + $colored_raw = gzinflate(substr($colored_raw, 10)); |
| 277 | + |
| 278 | + // Pick off the median value first. |
| 279 | + $colored_data = explode(",", $colored_raw, 2); |
| 280 | + $colored_text = $colored_data[1]; |
| 281 | + if (preg_match("/^[+-]?(([0-9]+)|([0-9]*\.[0-9]+|[0-9]+\.[0-9]*)| |
| 282 | + (([0-9]+|([0-9]*\.[0-9]+|[0-9]+\.[0-9]*))[eE][+-]?[0-9]+))$/", $colored_data[0])){ |
| 283 | + $this->median = $colored_data[0]; |
| 284 | + } |
| 285 | + |
| 286 | + // First, make sure that there are not any instances of our tokens in the colored_text |
| 287 | + $colored_text = str_replace(self::TRUST_OPEN_TOKEN, "", $colored_text); |
| 288 | + $colored_text = str_replace(self::TRUST_CLOSE_TOKEN, "", $colored_text); |
| 289 | + |
| 290 | + $colored_text = preg_replace("/'/", "'", $colored_text, -1); |
| 291 | + |
| 292 | + $colored_text = preg_replace("/&/", "&", $colored_text, -1); |
| 293 | + |
| 294 | + $colored_text = preg_replace("/</", self::TRUST_OPEN_TOKEN, $colored_text, -1); |
| 295 | + $colored_text = preg_replace("/>/", self::TRUST_CLOSE_TOKEN, $colored_text, -1); |
| 296 | + |
| 297 | + // Now update the text. |
| 298 | + $text = $voteitText . $colored_text . "\n" . |
| 299 | + wfMsgNoTrans("wgTrustExplanation"); |
| 300 | + } else { |
| 301 | + // Return a message about the missing text. |
| 302 | + $text = $parser->recursiveTagParse(wfMsgNoTrans("wgNoTrustExplanation")) . "\n" . $text; |
| 303 | + return false; |
| 304 | + } |
| 305 | + |
| 306 | + return true; |
| 307 | + } |
| 308 | + |
| 309 | + /* Register the tags we are intersted in expanding. */ |
| 310 | + function ucscColorTrust_Magic( &$magicWords, $langCode ) { |
| 311 | + $magicWords[ 't' ] = array( 0, 't' ); |
| 312 | + return true; |
| 313 | + } |
| 314 | + |
| 315 | + /* Pull in any colored text. Also handle closing tags. */ |
| 316 | + function ucscOrigin_Finalize(&$parser, &$text) { |
| 317 | + global $wgScriptPath, $IP, $wgOut; |
| 318 | + |
| 319 | + if(!$this->colored){ |
| 320 | + // This is to handle caching problems. |
| 321 | + if (!strstr($text, "This page has been accessed")){ |
| 322 | + $colored_text = $text; |
| 323 | + if ($this->ucscSeeIfColored($parser, $colored_text)){ |
| 324 | + $text = $wgOut->parse( $colored_text ); |
| 325 | + } else { |
| 326 | + $text = $colored_text; |
| 327 | + } |
| 328 | + } else { |
| 329 | + $colored_text = $text; |
| 330 | + if ($this->ucscSeeIfColored($parser, $colored_text)){ |
| 331 | + $wgOut->mBodytext = $wgOut->parse( $colored_text ); |
| 332 | + } else { |
| 333 | + $wgOut->mBodytext = $colored_text; |
| 334 | + } |
| 335 | + } |
| 336 | + } |
| 337 | + |
| 338 | + $count = 0; |
| 339 | + $text = '<script type="text/javascript" src="'.$wgScriptPath.'/extensions/Trust/js/wz_tooltip.js"></script>' . $text; |
| 340 | + $text = preg_replace('/' . self::TRUST_OPEN_TOKEN . '/', "<", $text, -1, $count); |
| 341 | + $text = preg_replace('/' . self::TRUST_CLOSE_TOKEN .'/', ">", $text, -1, $count); |
| 342 | + $text = preg_replace('/<\/p>/', "</span></p>", $text, -1, $count); |
| 343 | + $text = preg_replace('/<p><\/span>/', "<p>", $text, -1, $count); |
| 344 | + $text = preg_replace('/<li><\/span>/', "<li>", $text, -1, $count); |
| 345 | + |
| 346 | + return true; |
| 347 | + } |
| 348 | + |
| 349 | + /* Text Trust */ |
| 350 | + function ucscColorTrust_Render( &$parser, $combinedValue = "0,0,0" ) { |
| 351 | + |
| 352 | + // Split the value into trust and origin information. |
| 353 | + // 0 = trust |
| 354 | + // 1 = origin |
| 355 | + // 2 = contributing author |
| 356 | + $splitVals = explode(self::TRUST_SPLIT_TOKEN, $combinedValue); |
| 357 | + |
| 358 | + $class = $this->computeColorFromFloat($splitVals[0]); |
| 359 | + $output = self::TRUST_OPEN_TOKEN . "span class=\"$class\"" |
| 360 | + . "onmouseover=\"Tip('".$splitVals[2]."')\" onmouseout=\"UnTip()\"" |
| 361 | + . "onclick=\"showOrigin(" |
| 362 | + . $splitVals[1] . ")\"" . self::TRUST_CLOSE_TOKEN; |
| 363 | + |
| 364 | + $this->current_trust = $class; |
| 365 | + if ($this->first_span){ |
| 366 | + $this->first_span = false; |
| 367 | + } else { |
| 368 | + $output = self::TRUST_OPEN_TOKEN . "/span" . self::TRUST_CLOSE_TOKEN . $output; |
| 369 | + } |
| 370 | + |
| 371 | + return array ( $output, "noparse" => false, "isHTML" => false ); |
| 372 | + } |
| 373 | + |
| 374 | + /** |
| 375 | + Maps from the online trust values to the css trust values. |
| 376 | + Normalize the value for growing wikis. |
| 377 | + */ |
| 378 | + function computeColorFromFloat($trust){ |
| 379 | + $normalized_value = min(self::MAX_TRUST_VALUE, max(self::MIN_TRUST_VALUE, |
| 380 | + (($trust + .5) * self::TRUST_MULTIPLIER) |
| 381 | + / $this->median)); |
| 382 | + return $this->computeColor3($normalized_value); |
| 383 | + } |
| 384 | + |
| 385 | + /* Maps a trust value to a HTML color representing the trust value. */ |
| 386 | + function computeColor3($fTrustValue){ |
| 387 | + return $this->COLORS[$fTrustValue]; |
| 388 | + } |
| 389 | +} |
| 390 | + |
| 391 | +?> |
\ No newline at end of file |
Index: trunk/extensions/WikiTrust/remote/mediawiki/extensions/Trust/RemoteTrustUpdate.php |
— | — | @@ -0,0 +1,29 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class TextTrustUpdate{ |
| 5 | + |
| 6 | + /** |
| 7 | + * Update the DB when MW is updated. |
| 8 | + * This assums that the db has permissions to create tables. |
| 9 | + */ |
| 10 | + public static function updateDB(){ |
| 11 | + |
| 12 | + require_once(dirname(__FILE__) . '/' . "TrustUpdateScripts.inc"); |
| 13 | + $db =& wfGetDB( DB_MASTER ); |
| 14 | + |
| 15 | + // First check to see what tables have already been created. |
| 16 | + $res = $db->query("show tables"); |
| 17 | + while ($row = $db->fetchRow($res)){ |
| 18 | + $db_tables[$row[0]] = True; |
| 19 | + } |
| 20 | + |
| 21 | + foreach ($create_scripts as $table => $scripts) { |
| 22 | + if (!$db_tables[$table]){ |
| 23 | + foreach ($scripts as $script){ |
| 24 | + $db->query($script); |
| 25 | + } |
| 26 | + } |
| 27 | + } |
| 28 | + } |
| 29 | +} |
| 30 | +?> |
\ No newline at end of file |
Index: trunk/extensions/WikiTrust/remote/mediawiki/extensions/Trust/RemoteTrust.i18n.php |
— | — | @@ -0,0 +1,27 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +$messages = array(); |
| 5 | +$messages['en'] = array ( |
| 6 | + 'wgVoteText' => |
| 7 | + "I believe this information is correct", |
| 8 | + 'wgThankYouForVoting' => "Thank you for your vote", |
| 9 | + 'wgTrustTabText' => "check text", |
| 10 | + 'wgTrustExplanation' => |
| 11 | + '{| border="1" cellpadding="5" cellspacing="0" style="background:lightgreen; color:black" |
| 12 | + |- |
| 13 | + | The above text is colored according to how much it has been revised. An orange background indicates new, unrevised, text; white is for text that has been revised by many reputed authors. If you click on a word, you will be redirected to the diff corresponding to the edit where the word was introduced. If you hover over a word, a pop-up displays the word author. |
| 14 | + |- |
| 15 | + | The text color and origin are computed by [http://trust.cse.ucsc.edu/WikiTrust WikiTrust]; if you notice problems, you can submit a bug report [http://code.google.com/p/wikitrust/issues here]. |
| 16 | + |}', |
| 17 | + 'wgNoTrustExplanation' => |
| 18 | + '{| border="1" cellpadding="5" cellspacing="0" style="background:lightgreen; color:black" |
| 19 | + |- |
| 20 | + | There is no trust information available for this text yet. |
| 21 | + |}', |
| 22 | + 'wgNotPartExplanation' => |
| 23 | + '{| border="1" cellpadding="5" cellspacing="0" style="background:lightgreen; color:black" |
| 24 | + |- |
| 25 | + | This page is not part of the trust experement yet. |
| 26 | + |}', |
| 27 | + ); |
| 28 | +?> |
Index: trunk/extensions/WikiTrust/remote/README |
— | — | @@ -0,0 +1,185 @@ |
| 2 | +Remote wiki processing. |
| 3 | + |
| 4 | +The code in this directory (/remote) is desinged to allow the |
| 5 | +processing of wiki reputation on a different server and/or network |
| 6 | +than the MediaWiki servers which host the actual wiki. |
| 7 | + |
| 8 | +====Directory Structure==== |
| 9 | + |
| 10 | +analysis/ |
| 11 | + |
| 12 | +This directory contains the ocaml source code which does the wiki |
| 13 | +processing. |
| 14 | +It also has a mod_python implementation for communicating with the |
| 15 | +MediaWiki server. |
| 16 | + |
| 17 | +It has the following source files: |
| 18 | + |
| 19 | +* server.py |
| 20 | + |
| 21 | +A mod_python web-server, it returns colored markup on request. It also |
| 22 | +records votes. |
| 23 | + |
| 24 | +* server.ml |
| 25 | + |
| 26 | +A depricated implementation of the wikitrust server. It is a |
| 27 | +standalone server, and does not require Apache. |
| 28 | + |
| 29 | +* server_coloring_dispatcher.ml |
| 30 | + |
| 31 | +This is the top-level file for processing wikitext and votes. |
| 32 | + |
| 33 | +* tmpfile.ml |
| 34 | + |
| 35 | +Very basic code which create a unique temp file. |
| 36 | + |
| 37 | +* wikipedia_api.ml |
| 38 | + |
| 39 | +A library which communicated with a mediawiki api. It also talks to a |
| 40 | +user-id mapping program, currently running on the toolserver. |
| 41 | + |
| 42 | +* mediawiki/extensions/Trust/ |
| 43 | + |
| 44 | +All of the PHP code for the revised remote trust extension. |
| 45 | + |
| 46 | +===Setup=== |
| 47 | + |
| 48 | +On Ubuntu, |
| 49 | + |
| 50 | +apt-get install libapache2-mod-python |
| 51 | + |
| 52 | +Link or copy server.py to an Apache directory. |
| 53 | +Enable mod_python for this site with |
| 54 | + |
| 55 | +SetHandler python-program |
| 56 | +PythonHandler server |
| 57 | +# Turn of for production |
| 58 | +PythonDebug On |
| 59 | +# adjust for your installation. |
| 60 | +PythonPath "['/var/www/wikis/coloring'] + sys.path" |
| 61 | + |
| 62 | +Replace /var/www/wikis/coloring with the path to your server.py |
| 63 | + |
| 64 | +Test that everything is working by going to |
| 65 | +http://192.168.135.130:10302/ |
| 66 | + |
| 67 | +(replace 192.168.135.130:10302 with your ip address and port). |
| 68 | + |
| 69 | +You should see the text "bad". |
| 70 | + |
| 71 | +Now, you need to install these ocaml packages: |
| 72 | +netsys,netclient,camlzip |
| 73 | + |
| 74 | +apt-get install libzip-ocaml-dev |
| 75 | + |
| 76 | +For netsys and netclient however, it is needed to install from source |
| 77 | +(this one source tarball does both packages): |
| 78 | + |
| 79 | +wget http://download.camlcity.org/download/ocamlnet-2.2.9.tar.gz |
| 80 | +tar -zxf ocamlnet-2.2.9.tar.gz |
| 81 | +cd ocamlnet-2.2.9/ |
| 82 | +./configure -with-nethttpd |
| 83 | +make all |
| 84 | +make opt |
| 85 | +make install |
| 86 | + |
| 87 | +Now, try compiling the ocaml files. |
| 88 | + |
| 89 | +make all |
| 90 | +make allopt |
| 91 | + |
| 92 | +At this point, the following binay programs should be created: |
| 93 | + |
| 94 | +server -- Depricated in faivor of server.py |
| 95 | +dispatcher -- Actually processes edits and votes |
| 96 | + |
| 97 | +Remote Trust requires a seperate MediaWiki type database in which to |
| 98 | +run. The easiest way to get this is to set up a dumy MW instalation, |
| 99 | +using the web-based form to create the initial db, |
| 100 | +and then run the sql/create_db.php script. The arguments for this are: |
| 101 | +sql/create_db.php path_to_mw_instalation db_root_user_name [remove] |
| 102 | + |
| 103 | +Now, setup the php component. |
| 104 | + |
| 105 | +In your mediawiki instalation, link the following files into |
| 106 | +wikitrust/mediawiki/extensions/Trust: |
| 107 | + |
| 108 | +RemoteTrust.i18n.php -> ../../../remote/mediawiki/extensions/Trust/RemoteTrust.i18n.php |
| 109 | +RemoteTrustImpl.php -> ../../../remote/mediawiki/extensions/Trust/RemoteTrustImpl.php |
| 110 | +RemoteTrust.php -> ../../../remote/mediawiki/extensions/Trust/RemoteTrust.php |
| 111 | +RemoteTrustUpdate.php -> ../../../remote/mediawiki/extensions/Trust/RemoteTrustUpdate.php |
| 112 | + |
| 113 | +Update LocalSettings.php, replacing ``all" old trust values with these values: |
| 114 | + |
| 115 | +# Trust extension |
| 116 | +$wgUseTidy = true; |
| 117 | +$wgUseAjax = true; |
| 118 | +$wgShowVoteButton = true; // If true, the vote button is shown. |
| 119 | +$wgTrustCmd = $IP . "/eval_online_wiki"; |
| 120 | +$wgTrustLog = "/tmp/{$wgDBname}-trust.log"; |
| 121 | +$wgTrustDebugLog = "/tmp/{$wgDBname}-trust-debug.log"; |
| 122 | +$wgRepSpeed = 1.0; |
| 123 | +$wgContentServerURL = "http://localhost:10302/?"; |
| 124 | + |
| 125 | +require_once( $IP . "/extensions/Gadgets/Gadgets.php" ); |
| 126 | +require_once( $IP . "/extensions/Trust/RemoteTrust.php" ); |
| 127 | + |
| 128 | +Update wgContentServerURL to point to the web server you set up for |
| 129 | +mod_python earlier. |
| 130 | + |
| 131 | +Lastly, add the Gadgets widget to your installation. Instructions are |
| 132 | +provided here: |
| 133 | +http://www.mediawiki.org/wiki/Extension:Gadgets |
| 134 | + |
| 135 | +Configure WikiTrust to run via Gadgets. |
| 136 | +Go here: |
| 137 | +http://192.168.135.130/testwiki/index.php/MediaWiki:Gadgets-definition |
| 138 | + |
| 139 | +And set the text to be: |
| 140 | +* WikiTrust|wikitrust.js |
| 141 | + |
| 142 | +You must be logged in as the WikiSysop admin user to do this. |
| 143 | + |
| 144 | +Now, log in as a regular user. Click on "my preferences", "Gadgets". |
| 145 | +Check the box for WikiTrust. |
| 146 | + |
| 147 | +===Running=== |
| 148 | + |
| 149 | +You are now ready to try running the system. |
| 150 | +Click on a check-trust tab. You should get a message stating that |
| 151 | +trust for this page is not availible. |
| 152 | + |
| 153 | +Laucnch the dispatcher program to color the requested page. |
| 154 | +In remote/analysis, do: |
| 155 | + |
| 156 | +./dispatcher --help |
| 157 | + |
| 158 | +This shows all of the availible options. |
| 159 | + |
| 160 | +For general purpose, do: |
| 161 | + |
| 162 | +./dispatcher -db_user wikiuser -db_name wikidb -db_pass password |
| 163 | +-db_host localhost -db_port 3306 -wiki_api |
| 164 | +http://192.168.135.130/testwiki/api.php -user_id_api |
| 165 | +http://toolserver.org/~Ipye/UserName2UserId.php |
| 166 | + |
| 167 | +Update -wiki_api to point to the api.php page you want to target for |
| 168 | +requests for wiki-text. -user_id_api is a small program which returns |
| 169 | +the Wikipedia UserID for a username, because it is not exposed via the |
| 170 | +API currently. |
| 171 | + |
| 172 | +Run this in the forground for debugging, and in general as a deamon process. |
| 173 | + |
| 174 | +It prints out information about the edits and votes processed. |
| 175 | +With dispatcher running, the wikitrust extension should work exactly |
| 176 | +as before. |
| 177 | + |
| 178 | + |
| 179 | + |
| 180 | + |
| 181 | + |
| 182 | + |
| 183 | + |
| 184 | + |
| 185 | + |
| 186 | +===Run=== |
\ No newline at end of file |