OSDN Git Service

editlogの日時がズレることがあったので1秒以内のログは同じ履歴とみなすようにしています。
[fswiki/fswiki.git] / plugin / core / Diff.pm
1 ###############################################################################
2
3 # º¹Ê¬¤òɽ¼¨¤¹¤ë¥×¥é¥°¥¤¥ó
4
5 ###############################################################################
6 package plugin::core::Diff;
7 use Algorithm::Diff qw(traverse_sequences);
8 use strict;
9
10 #==============================================================================
11 # ¥³¥ó¥¹¥È¥é¥¯¥¿
12 #==============================================================================
13 sub new {
14         my $class = shift;
15         my $self = {};
16         
17         return bless $self,$class;
18 }
19
20 #==============================================================================
21 # ¥¢¥¯¥·¥ç¥ó¤Î¼Â¹Ô
22 #==============================================================================
23 sub do_action {
24         my $self = shift;
25         my $wiki = shift;
26         my $cgi = $wiki->get_CGI;
27         
28         my $pagename = $cgi->param("page");
29         if($pagename eq ""){
30                 $pagename = $wiki->config("frontpage");
31         }
32         unless($wiki->can_show($pagename)){
33                 return $wiki->error("»²¾È¸¢¸Â¤¬¤¢¤ê¤Þ¤»¤ó¡£");
34         }
35         if($cgi->param('rollback') ne ''){
36                 return $self->rollback($wiki, $pagename, $cgi->param('rollback'));
37                 
38         } elsif($wiki->{storage}->backup_type eq 'all'){
39                 if($cgi->param('generation') eq '' && $cgi->param('diff') eq ''){
40                         return $self->show_history($wiki, $pagename);
41                         
42                 } else {
43                         if($cgi->param('generation') ne ''){
44                                 return $self->show_diff($wiki, $pagename, '', $cgi->param('generation'));
45                         }
46                         return $self->show_diff($wiki, $pagename, $cgi->param('from'), $cgi->param('to'));
47                 }
48         } else {
49                 return $self->show_diff($wiki, $pagename, '', 0);
50         }
51 }
52
53 #==============================================================================
54 # ÍúÎò¤«¤é¥Ú¡¼¥¸¤òÉü¸µ
55 #==============================================================================
56 sub rollback {
57         my $self = shift;
58         my $wiki = shift;
59         my $page = shift;
60         my $gen  = shift;
61         unless($wiki->can_modify_page($page)){
62                 return $wiki->error("¹¹¿·¸¢¸Â¤¬¤¢¤ê¤Þ¤»¤ó¡£");
63         }
64         my $source = $wiki->get_backup($page,$gen);
65         $wiki->save_page($page, $source);
66         return $wiki->redirect($page);
67 }
68
69 #==============================================================================
70 # ÍúÎò¤Î°ìÍ÷¤òɽ¼¨
71 # ¥¹¥È¥ì¡¼¥¸¤Îbackup_type=all¤Î¤È¤­
72 #==============================================================================
73 sub show_history {
74         my $self = shift;
75         my $wiki = shift;
76         my $page = shift;
77         
78         $wiki->set_title("$page¤ÎÊѹ¹ÍúÎò");
79         my $buf   = "<form><ul>\n";
80         my $count = 0;
81         my @list  = $wiki->{storage}->get_backup_list($page);
82         
83         if($#list == -1){
84                 return "ÍúÎò¤Ï¤¢¤ê¤Þ¤»¤ó¡£";
85         }
86         
87         # editlog¥×¥é¥°¥¤¥ó¤Î¥í¥°¤«¤éÊÔ½¸¼Ô¤Î¥æ¡¼¥¶Ì¾¤ò¼èÆÀ
88         # ¡Êeditlog¤ÎÆüÉÕ¤¬¥º¥ì¤ë¤³¤È¤¬¤¢¤Ã¤¿¤Î¤Ç1ÉðÊÆâ¤Î¹¹¿·¤ÏƱ¤¸ÍúÎò¤È¤ß¤Ê¤¹¤è¤¦¤Ë¤·¤Æ¤Þ¤¹¡Ë
89         my $editlog = {};
90         if($wiki->config('log_dir') ne "" && -e $wiki->config('log_dir')."/useredit.log"){
91                 open(DATA,$wiki->config('log_dir')."/useredit.log") or die $!;
92                 while(<DATA>){
93                         my($date, $time, $unixtime, $action, $subject, $id) = split(" ",$_);
94                         if($subject eq $page){
95                                 if($id eq ''){
96                                         $editlog->{substr($unixtime, 0, length($unixtime) - 4)} = 'anonymous';
97                                 } else {
98                                         $editlog->{substr($unixtime, 0, length($unixtime) - 4)} = $id;
99                                 }
100                         }
101                 }
102                 close(DATA);
103         }
104         
105         foreach my $time (@list){
106                 $buf .= "<li>";
107                 if($count == 0){
108                         $buf .= "<input type=\"radio\" name=\"from\" value=\"\" checked>".
109                                 "<input type=\"radio\" name=\"to\" value=\"\" checked>";
110                 } else {
111                         $buf .= "<input type=\"radio\" name=\"from\" value=\"".($#list-$count+1)."\">".
112                                 "<input type=\"radio\" name=\"to\" value=\"".($#list-$count+1)."\">";
113                 }
114                 $buf .= "<a href=\"".$wiki->create_url({ action=>"DIFF",page=>$page,generation=>($#list-$count) })."\">".&Util::format_date($time).
115                         "</a> <a href=\"".$wiki->create_url({ action=>"SOURCE",page=>$page,generation=>($#list-$count) })."\">¥½¡¼¥¹</a>";
116                         
117                 if(defined($editlog->{substr($time, 0, length($time) - 4)})){
118                         $buf .= " by ".$editlog->{substr($time, 0, length($time) - 4)};
119                 }
120                 
121                 $buf .=  "</li>\n";
122                 $count++;
123         }
124         return $buf."</ul>".
125         "<input type=\"hidden\" name=\"page\" value=\"".Util::escapeHTML($page)."\">".
126         "<input type=\"hidden\" name=\"action\" value=\"DIFF\">".
127         "<input type=\"submit\" name=\"diff\" value=\"ÁªÂò¤·¤¿¥ê¥Ó¥¸¥ç¥ó´Ö¤Îº¹Ê¬¤òɽ¼¨\"></form>\n";
128 }
129
130 #==============================================================================
131 # º¹Ê¬¤òɽ¼¨
132 #==============================================================================
133 sub show_diff {
134         my $self = shift;
135         my $wiki = shift;
136         my $page = shift;
137         my $from = shift;
138         my $to   = shift;
139         
140         $wiki->set_title("$page¤ÎÊѹ¹ÅÀ");
141         my ($diff, $rollback) = $self->get_diff_html($wiki,$page, $from, $to);
142         
143         $diff =~ s/\n/<br>/g;
144         
145         my $buf = qq|
146                 <ul>
147                   <li>Äɲ䵤줿Éôʬ¤Ï<ins class="diff">¤³¤Î¤è¤¦¤Ë</ins>ɽ¼¨¤µ¤ì¤Þ¤¹¡£</li>
148                   <li>ºï½ü¤µ¤ì¤¿Éôʬ¤Ï<del class="diff">¤³¤Î¤è¤¦¤Ë</del>ɽ¼¨¤µ¤ì¤Þ¤¹¡£</li>
149                 </ul>
150                 <div class="diff">$diff</div>
151         |;
152         
153         if($wiki->can_modify_page($page) && $rollback && $wiki->get_CGI->param('diff') eq ''){
154                 $buf .= qq|
155                         <form action="@{[$wiki->create_url()]}" method="POST">
156                                 <input type="submit" value="¤³¤Î¥Ð¡¼¥¸¥ç¥ó¤ËÌ᤹"/>
157                                 <input type="hidden" name="action" value="DIFF"/>
158                                 <input type="hidden" name="page" value="@{[Util::escapeHTML($page)]}"/>
159                                 <input type="hidden" name="rollback" value="@{[Util::escapeHTML($from)]}"/>
160                         </form>
161                 |;
162         }
163         
164         return $buf;
165 }
166
167 #==============================================================================
168 # º¹Ê¬Ê¸»úÎó¤ò¼èÆÀ
169 #==============================================================================
170 sub get_diff_text {
171         my $self = shift;
172         my $wiki = shift;
173         my $page = shift;
174         my $gen  = shift;
175         
176         my $source1 = $wiki->get_page($page);
177         my $source2 = $wiki->get_backup($page, $gen);
178         my $format  = $wiki->get_edit_format();
179         
180         $source1 = $wiki->convert_from_fswiki($source1, $format);
181         $source2 = $wiki->convert_from_fswiki($source2, $format);
182         
183         my $diff_text = "";
184         my @msg1 = split(/\n/,$source1);
185         my @msg2 = split(/\n/,$source2);
186         my $msgrefA = \@msg2;
187         my $msgrefB = \@msg1;
188         
189         traverse_sequences($msgrefA, $msgrefB,
190                 {
191                         MATCH => sub {},
192                         DISCARD_A => sub {
193                                 my ($a, $b) = @_;
194                                 $diff_text .= "-".$msgrefA->[$a]."\n";
195                         },
196                         DISCARD_B => sub {
197                                 my ($a, $b) = @_;
198                                 $diff_text .= "+".$msgrefB->[$b]."\n";
199                         }
200                 });
201         
202         return $diff_text;
203 }
204
205 #==============================================================================
206 # º¹Ê¬Ê¸»úÎó¤òɽ¼¨ÍÑHTML¤È¤·¤Æ¼èÆÀ
207 #==============================================================================
208 sub get_diff_html {
209         my $self = shift;
210         my $wiki = shift;
211         my $page = shift;
212         my $from = shift;
213         my $to   = shift;
214         
215         my $source1 = '';
216         if($from ne ''){
217                 $source1 = $wiki->get_backup($page, $from);
218         } else {
219                 $source1 = $wiki->get_page($page);
220         }
221         if($wiki->config('diff_max') ne '' && $wiki->config('diff_max') > 0){
222                 if(length($source1) > $wiki->config('diff_max')){
223                         return ('¥Ú¡¼¥¸¥µ¥¤¥º¤¬Â礭¤¤¤¿¤áº¹Ê¬¤òɽ¼¨¤Ç¤­¤Þ¤»¤ó¡£', 0);
224                 }
225         }
226         
227         my $source2 = '';
228         if($to ne ''){
229                 $source2 = $wiki->get_backup($page, $to);
230         } else {
231                 $source2 = $wiki->get_page($page);
232         }
233         if($wiki->config('diff_max') ne '' && $wiki->config('diff_max') > 0){
234                 if(length($source2) > $wiki->config('diff_max')){
235                         return ('¥Ú¡¼¥¸¥µ¥¤¥º¤¬Â礭¤¤¤¿¤áº¹Ê¬¤òɽ¼¨¤Ç¤­¤Þ¤»¤ó¡£', 0);
236                 }
237         }
238         
239         my $format  = $wiki->get_edit_format();
240         
241         $source1 = $wiki->convert_from_fswiki($source1, $format);
242         $source2 = $wiki->convert_from_fswiki($source2, $format);
243         
244         return (&_get_diff_html($source1, $source2), $source2 ne "");
245 }
246
247 #==============================================================================
248 # º¹Ê¬HTML¤òÀ¸À®¤¹¤ë´Ø¿ô
249 #==============================================================================
250 sub _get_diff_html {
251         my $source1 = shift;
252         my $source2 = shift;
253         
254         my @lines1 = split(/\n/,$source1);
255         my @lines2 = split(/\n/,$source2);
256         my $linesrefA = \@lines2;
257         my $linesrefB = \@lines1;
258         
259         my $diff_text = "";
260         my $del_buffer = "";
261         
262         traverse_sequences($linesrefA, $linesrefB, {
263                 MATCH => sub {
264                         my ($a, $b) = @_;
265                         if($del_buffer ne ''){
266                                 $diff_text .= "<del class=\"diff\">".Util::escapeHTML($del_buffer)."</del>\n";
267                                 $del_buffer = '';
268                         }
269                         $diff_text .= Util::escapeHTML($linesrefA->[$a])."\n";
270                 },
271                 DISCARD_A => sub {
272                         my ($a, $b) = @_;
273                         $del_buffer .= $linesrefA->[$a]."\n";
274                 },
275                 DISCARD_B => sub {
276                         my ($a, $b) = @_;
277                         if($del_buffer eq ''){
278                                 $diff_text .= "<ins class=\"diff\">".Util::escapeHTML($linesrefB->[$b])."</ins>\n";
279                                 
280                         } else {
281                                 my @msg1 = _str_jfold($linesrefB->[$b]."\n", 1);
282                                 my @msg2 = _str_jfold($del_buffer, 1);
283                                 my $msgrefA = \@msg2;
284                                 my $msgrefB = \@msg1;
285                                 
286                                 traverse_sequences($msgrefA, $msgrefB, {
287                                         MATCH => sub {
288                                                 my ($a, $b) = @_;
289                                                 $diff_text .= Util::escapeHTML($msgrefA->[$a]);
290                                         },
291                                         DISCARD_A => sub {
292                                                 my ($a, $b) = @_;
293                                                 $diff_text .= "<del class=\"diff\">".Util::escapeHTML($msgrefA->[$a])."</del><wbr>";
294                                         },
295                                         DISCARD_B => sub {
296                                                 my ($a, $b) = @_;
297                                                 $diff_text .= "<ins class=\"diff\">".Util::escapeHTML($msgrefB->[$b])."</ins><wbr>";
298                                         }
299                                 });
300                                 
301                                 $del_buffer = '';
302                         }
303                 }
304         });
305                 
306         if($del_buffer ne ''){
307                 $diff_text .= "<del class=\"diff\">".Util::escapeHTML($del_buffer)."</del>\n";
308                 $del_buffer = '';
309         }
310         
311         return $diff_text;
312 }
313
314 #==============================================================================
315 # Ê¸»úÎó¤ò»ØÄêʸ»ú¿ô¤òʬ³ä
316 #==============================================================================
317 sub _str_jfold {\r
318   my $str    = shift;       #»ØÄêʸ»úÎó\r
319   my $byte   = shift;       #»ØÄê¥Ð¥¤¥È\r
320   my $j      = new Jcode($str);\r
321   my @result = ();\r
322 \r
323   foreach my $buff ( $j->jfold($byte) ){\r
324     push(@result, $buff);\r
325   }\r
326 \r
327   return(@result);\r
328 }
329
330 #==============================================================================
331 # ¥Ú¡¼¥¸É½¼¨»þ¤Î¥Õ¥Ã¥¯¥á¥½¥Ã¥É
332 # ¡Öº¹Ê¬¡×¥á¥Ë¥å¡¼¤òÍ­¸ú¤Ë¤·¤Þ¤¹
333 #==============================================================================
334 sub hook {
335         my $self = shift;
336         my $wiki = shift;
337         my $cgi  = $wiki->get_CGI;
338         my $page = $cgi->param("page");
339         if($wiki->{storage}->backup_type eq 'all'){
340                 $wiki->add_menu("ÍúÎò",$wiki->create_url({ action=>"DIFF",page=>$page }));
341         } else {
342                 $wiki->add_menu("º¹Ê¬",$wiki->create_url({ action=>"DIFF",page=>$page }));
343         }
344 }
345
346 1;