OSDN Git Service

ソフト404等のレスポンスエラーコード対応
[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 use HTTP::Status;
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(RC_FORBIDDEN, "»²¾È¸¢¸Â¤¬¤¢¤ê¤Þ¤»¤ó¡£");
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(RC_FORBIDDEN, "¹¹¿·¸¢¸Â¤¬¤¢¤ê¤Þ¤»¤ó¡£");
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                         $subject = Util::url_decode($subject);
115                         if($subject eq $page){
116                                 $id = 'anonymous' if ($id eq '');
117                                 if (!defined($editlog->{$unixtime})) {
118                                         $editlog->{$unixtime} = $id;
119                                 } elsif (!defined($editlog->{$unixtime -1})) {
120                                         $editlog->{$unixtime} = $id;
121                                 } elsif (!defined($editlog->{$unixtime +1})) {
122                                         $editlog->{$unixtime} = $id;
123                                 }
124                         }
125                 }
126                 close(DATA);
127         }
128         
129         foreach my $time (@list){
130                 $buf .= "<li>";
131                 if($count == 0){
132                         $buf .= "<input type=\"radio\" name=\"from\" value=\"".($#list-$count)."\" checked>".
133                                 "<input type=\"radio\" name=\"to\" value=\"".($#list-$count)."\" checked>";
134                 } else {
135                         $buf .= "<input type=\"radio\" name=\"from\" value=\"".($#list-$count)."\">".
136                                 "<input type=\"radio\" name=\"to\" value=\"".($#list-$count)."\">";
137                 }
138                 $buf .= "<a href=\"".$wiki->create_url({ action=>"DIFF",page=>$page,generation=>($#list-$count) })."\">".&Util::format_date($time).
139                         "</a> <a href=\"".$wiki->create_url({ action=>"SOURCE",page=>$page,generation=>($#list-$count) })."\">¥½¡¼¥¹</a>";
140                         
141                 if ($editlog->{$time} || $editlog->{$time-1} || $editlog->{$time+1}) {
142                         $buf .= " by ".( $editlog->{$time} || $editlog->{$time-1} || $editlog->{$time+1} );
143                 }
144                 
145                 $buf .=  "</li>\n";
146                 $count++;
147         }
148         
149         $buf .= "</ul>".
150                 "<input type=\"hidden\" name=\"page\" value=\"".Util::escapeHTML($page)."\">".
151                 "<input type=\"hidden\" name=\"action\" value=\"DIFF\">".
152                 "<input type=\"submit\" name=\"diff\" value=\"ÁªÂò¤·¤¿¥ê¥Ó¥¸¥ç¥ó´Ö¤Îº¹Ê¬¤òɽ¼¨\">\n";
153         
154         my $login = $wiki->get_login_info();
155         if(defined($login) && $login->{'type'} == 0){
156                 $buf .= "<input type=\"submit\" name=\"clear\" value=\"ÍúÎò¤ò¤¹¤Ù¤Æºï½ü\">\n";
157         }
158         return $buf."</form>\n";
159 }
160
161 #==============================================================================
162 # º¹Ê¬¤òɽ¼¨
163 #==============================================================================
164 sub show_diff {
165         my $self = shift;
166         my $wiki = shift;
167         my $page = shift;
168         my $from = shift;
169         my $to   = shift;
170         
171         $wiki->set_title("$page¤ÎÊѹ¹ÅÀ");
172         my ($source1, $source2) = $self->get_diff_sources($wiki, $page, $from, $to);
173         
174         my $theme_uri = $wiki->config('theme_uri');
175         my $buf = _get_diff_html($wiki, $source1, $source2);
176
177         if($wiki->can_modify_page($page) && $wiki->get_CGI->param('diff') eq ''){
178                 $buf .= qq|
179                         <form action="@{[$wiki->create_url()]}" method="POST">
180                                 <input type="submit" value="¤³¤Î¥Ð¡¼¥¸¥ç¥ó¤ËÌ᤹"/>
181                                 <input type="hidden" name="action" value="DIFF"/>
182                                 <input type="hidden" name="page" value="@{[Util::escapeHTML($page)]}"/>
183                                 <input type="hidden" name="rollback" value="@{[Util::escapeHTML($to)]}"/>
184                         </form>
185                 |;
186         }
187         
188         return $buf;
189 }
190
191 #==============================================================================
192 # jsdifflib¤ò»È¤Ã¤Æº¹Ê¬¤Îɽ¼¨¤ò¹Ô¤¦HTML¤ò¼èÆÀ
193 #==============================================================================
194 sub _get_diff_html {
195         my $wiki = shift;
196         my $source1 = shift;
197         my $source2 = shift;
198
199         my $theme_uri = $wiki->config('theme_uri');
200         my $buf = qq|
201 <script type="text/javascript" src="${theme_uri}/resources/jsdifflib/difflib.js"></script>
202 <script type="text/javascript" src="${theme_uri}/resources/jsdifflib/diffview.js"></script>
203 <link href="${theme_uri}/resources/jsdifflib/diffview.css" type="text/css" rel="stylesheet" />
204 <script type="text/javascript">
205 function diffUsingJS(type) {
206     // get the baseText and newText values from the two textboxes, and split them into lines
207     var base   = difflib.stringAsLines(document.getElementById("baseText").value);
208     var newtxt = difflib.stringAsLines(document.getElementById("newText").value);
209
210     // create a SequenceMatcher instance that diffs the two sets of lines
211     var sm = new difflib.SequenceMatcher(base, newtxt);
212
213     // get the opcodes from the SequenceMatcher instance
214     // opcodes is a list of 3-tuples describing what changes should be made to the base text
215     // in order to yield the new text
216     var opcodes = sm.get_opcodes();
217     var diffoutputdiv = document.getElementById("diffoutputdiv")
218     while (diffoutputdiv.firstChild) diffoutputdiv.removeChild(diffoutputdiv.firstChild);
219
220     // build the diff view and add it to the current DOM
221     diffoutputdiv.appendChild(diffview.buildView({
222         baseTextLines: base,
223         newTextLines: newtxt,
224         opcodes: opcodes,
225         // set the display titles for each resource
226         baseTextName: "Base Text",
227         newTextName: "New Text",
228         contextSize: null,
229         viewType: type // 1 or 0
230     }));
231 }
232 </script>
233 <input id="newText"  type="hidden" value="@{[Util::escapeHTML($source1)]}">
234 <input id="baseText" type="hidden" value="@{[Util::escapeHTML($source2)]}">
235 <input type="checkbox" id="viewtype" onclick="diffUsingJS(this.checked ? 0 : 1)"><label for="viewtype">¥µ¥¤¥É¥Ð¥¤¥µ¥¤¥É¤Çɽ¼¨</label>
236 <div id="diffoutputdiv"></div>
237 <script type="text/javascript">
238   diffUsingJS(1);
239 </script>
240         |;
241         
242         return $buf;
243 }
244
245 #==============================================================================
246 # º¹Ê¬Ê¸»úÎó¤ò¼èÆÀ
247 #==============================================================================
248 sub get_diff_text {
249         my $self = shift;
250         my $wiki = shift;
251         my $page = shift;
252         my $gen  = shift;
253         
254         my $source1 = $wiki->get_page($page);
255         my $source2 = $wiki->get_backup($page, $gen);
256         my $format  = $wiki->get_edit_format();
257         
258         $source1 = $wiki->convert_from_fswiki($source1, $format);
259         $source2 = $wiki->convert_from_fswiki($source2, $format);
260         
261         my $diff_text = "";
262         my @msg1 = split(/\n/,$source1);
263         my @msg2 = split(/\n/,$source2);
264         my $msgrefA = \@msg2;
265         my $msgrefB = \@msg1;
266         
267         traverse_sequences($msgrefA, $msgrefB,
268                 {
269                         MATCH => sub {},
270                         DISCARD_A => sub {
271                                 my ($a, $b) = @_;
272                                 $diff_text .= "-".$msgrefA->[$a]."\n";
273                         },
274                         DISCARD_B => sub {
275                                 my ($a, $b) = @_;
276                                 $diff_text .= "+".$msgrefB->[$b]."\n";
277                         }
278                 });
279         
280         return $diff_text;
281 }
282
283 #==============================================================================
284 # º¹Ê¬É½¼¨ÍѤΥ½¡¼¥¹¤ò¼èÆÀ
285 #==============================================================================
286 sub get_diff_sources {
287         my $self = shift;
288         my $wiki = shift;
289         my $page = shift;
290         my $from = shift;
291         my $to   = shift;
292         
293         my $source1 = '';
294         if($from ne ''){
295                 $source1 = $wiki->get_backup($page, $from);
296         } else {
297                 $source1 = $wiki->get_page($page);
298         }
299         
300         my $source2 = '';
301         if($to ne ''){
302                 $source2 = $wiki->get_backup($page, $to);
303         } else {
304                 $source2 = $wiki->get_page($page);
305         }
306         my $format  = $wiki->get_edit_format();
307         
308         $source1 = $wiki->convert_from_fswiki($source1, $format);
309         $source2 = $wiki->convert_from_fswiki($source2, $format);
310         
311         return ($source1, $source2);
312 }
313
314 #==============================================================================
315 # ¥Ú¡¼¥¸É½¼¨»þ¤Î¥Õ¥Ã¥¯¥á¥½¥Ã¥É
316 # ¡Öº¹Ê¬¡×¥á¥Ë¥å¡¼¤òÍ­¸ú¤Ë¤·¤Þ¤¹
317 #==============================================================================
318 sub hook {
319         my $self = shift;
320         my $wiki = shift;
321         my $cgi  = $wiki->get_CGI;
322         my $page = $cgi->param("page");
323         if($wiki->{storage}->backup_type eq 'all'){
324                 $wiki->add_menu("ÍúÎò",$wiki->create_url({ action=>"DIFF",page=>$page }));
325         } else {
326                 $wiki->add_menu("º¹Ê¬",$wiki->create_url({ action=>"DIFF",page=>$page }));
327         }
328 }
329
330 1;