OSDN Git Service

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