X-Git-Url: http://www.wagner.pp.ru/gitweb/?a=blobdiff_plain;f=forum%2Fforum;h=8c966e93bec89259db459e407268233edc289762;hb=577989dad1f989210c7b3a7a6917c08ae3b95c8b;hp=bc685450577ae4cfd35d1e81175f1304172b3af6;hpb=d0acd3927cbe4e0f7e4faccca7ef6dd68911ecd5;p=oss%2Fstilllife.git diff --git a/forum/forum b/forum/forum index bc68545..8c966e9 100755 --- a/forum/forum +++ b/forum/forum @@ -28,103 +28,48 @@ use Net::OpenID::Consumer; # Набор поддерживаемых действий. Хэш вида # "имя поля в запросе" => "функция обработчик" # -my %actions = ( - reply => \&reply, - edit => \&edit_comment, - delete => \&delete_item, - move => \&move_comment, - newtopic=> \&new_topic, - newforum=> \&new_forum, - login => \&login, - register=>\®ister, - profile=>\&profile, - setrights=>\&set_rights, - openidlogin=>\&openid_login, - openidvfy =>\&openid_verify +my @actions = ( + {name=>"openidvfy",GET=>\&openid_verify,POST=>\&openid_verify}, + {name=>"logout",GET=>\&logout,POST=>\&logout}, + {name=>"reply", POST => \&reply, GET=>\&show_template,rights=>"login"}, + {name=>"edit", POST => \&edit_item, GET=>\&show_editable,rights=>"author"}, + {name=>"delete",POST => \&delete_item, GET=>\&delete_item,rights=>"author"}, + {name=>"move",POST => \&move_item, GET=>\&show_move_dest,rights=>"moderator"}, + {name=>"newtopic",POST=> \&new_topic,GET=>\&show_template,rights=>"normal"}, + {name=>"newforum",POST=> \&new_forum,GET=>\&show_template,rights=>"moderator"}, + {name=>"login",POST => \&login,GET=>\&show_template}, + {name=>"register",POST=>\®ister,GET=>\&show_template}, + {name=>"profile",POST=>\&profile,GET=>\&show_profile,rights=>"normal"}, + {name=>"setrights",POST=>\&set_rights,GET=>\&show_rights,rights=>"admin"}, + {name=>"reapply",POST=>\&apply_templates,GET=>\&apply_templates,rights=>"admin"} ); # -# Уровень прав, которые необходимо иметь пользователю для совершения -# определенного действия -# иерархия вида undef < banned < normal < author < moderator "login", - edit => "author", - delete => "author", - newtopic => "normal", - move => "moderator", - newforum => "moderator", - profile => "normal", - setrights => "admin", -); our $path_translated; # Untainted value of PATH_TRANSLATED env var my $cgi = new CGI; print STDERR "--------------------\n"; my $forum=get_forum_config(); authorize_user($cgi,$forum); -if ($cgi->request_method ne "POST") { -# Запрос к скрипту методом GET. Надо показать форму, если только это не -# редирект от OpenId-сервера - if ($cgi->param('openidvfy')) { - openid_verify($cgi,$forum); - } elsif ($cgi->param("logout")) { - logout('logout',$cgi,$forum); - } elsif ($cgi->param("profile")) { - show_profile("profile",$cgi,$forum); - } elsif ($cgi->param('delete')) { - delete_item("delete",$cgi,$forum); - } else { - for my $param ($cgi->param) { -# Среди параметров, указанных в URL ищем тот, который задает -# действие - if (exists $actions{$param}) { -# Мы, конечно уже проверили, что в названии параметра -# нехороших символов нет, но чтобы perl в taint mode не -# ругался... - if (allow_operation($param,$cgi,$forum)) { - print STDERR "Allow_operation completed\n"; - show_template($1,$cgi,$forum) if $param=~/^(\w+)$/; - exit; - } else { - if (!$forum->{"authenticated"}) { - $cgi->param("returnto",$cgi->url(-full=>1)); - show_template("login",$cgi,$forum); - exit; - - } else { - show_error($forum,"У Вас нет прав на выполнение этой - операции") - } - } - } - } - if (index($path_translated,$forum->{userdir})==0) { - show_user_page($cgi,$forum); - } - show_error($forum,"Некорректный вызов скрипта. Отсутствует параметр - действия"); - } -} else { - # Запрос методом POST. Вызываем обработчик - for my $param ($cgi->param) { - if (exists $actions{$param}) { - if (allow_operation($param,$cgi,$forum)) { - $actions{$param}->($param,$cgi,$forum); - exit; - } else { - show_error($forum,"У Вас нет прав на выполнение этой - операции") - } - +my $method = $cgi->request_method; +$method = "GET" if ($method eq "HEAD"); +for my $action (@actions) { + if ($cgi->param($action->{name})) { + if (allow_operation($action,$cgi,$forum)) { + $action->{$method}->($action->{name},$cgi,$forum); + } elsif (!$forum->{"authenticated"}) { + $cgi->param("returnto",$cgi->url(-full=>1)); + show_template("login",$cgi,$forum); + } else { + show_error($forum,"У Вас нет прав на выполнение этой операции") } } - print STDERR "Получены параметры ",join(" ",$cgi->param),"\n"; - show_error($forum,"Некорректный вызов скрипта. Отсутствует параметр действия"); } +if (index($path_translated,$forum->{userdir})==0) { + show_user_page($cgi,$forum); +} +show_error($forum,"Некорректный вызов скрипта. Отсутствует параметр + действия"); + #-------------------------------------------------------------- #-------- Чтение конфигурационного файла и связанные с этим действия @@ -284,6 +229,7 @@ sub send_to_user { print $cgi->header(-type=>"text/html",-charset=>"utf-8",($forum->{cookies}?(-cookie=>$forum->{cookies}):())), output_html($tree); + exit; } sub prepare_template { my ($form,$cgi,$forum) = @_; @@ -451,6 +397,19 @@ sub fix_forum_links { $element->attr($attr,$link); } } +sub makeuserlink { + my ($forum,$tree,$linkclass,$userinfo) = @_; + + my $userpage; + if ($userinfo->{"openiduser"}) { + $userpage = "http://".$userinfo->{"user"}; + } else { + $userpage = + $cgi->url(-absolute=>1).$forum->{"userurl"}."/".$cgi->escape($userinfo->{"user"}); + } + substinfo($tree,["_tag"=>"a","class"=>$linkclass], + href=>$userpage,_content=>$userinfo->{"user"}); +} # # Подставляет в заданное поддерево информацию о пользователе # @@ -469,15 +428,7 @@ if (defined $user) { # # Специально обрабатываем поля user (должна быть ссылка) и avatar # (должен быть img). - my $userpage; - if ($userinfo{"openiduser"}) { - $userpage = "http://".$userinfo{"user"}; - } else { - $userpage = - $cgi->url(-absolute=>1).$forum->{"userurl"}."/".$cgi->escape($userinfo{"user"}); - } - substinfo($tree,["_tag"=>"a","class"=>"author"], - href=>$userpage,_content=>$userinfo{"user"}); + makeuserlink($forum,$tree,"author",\%userinfo); delete $userinfo{"user"}; if (ref $userinfo{"avatar"} eq "HASH") { substinfo($tree,["_tag"=>"img","class"=>"avatar"], @@ -521,7 +472,7 @@ if (defined $user) { # sub authorize_user { - ($cgi,$forum) = @_; + my ($cgi,$forum) = @_; if (my $session=$cgi->cookie("slsession")) { # Пользователь имеет куку my %sessbase; @@ -701,7 +652,13 @@ sub show_profile { $userinfo->{user}=$user; while(my ($field,$value) = each %$userinfo) { $value = $value->{src} if ($field eq 'avatar' && ref($value)); - $cgi->param($field,$value); + if ($value =~/^<(div|p)\b/) { + my $tree = str2tree($value); + tree2input($cgi,$field,$tree); + $tree->delete; + } else { + $cgi->param($field,$value); + } } my $tree = prepare_template(@_); # Запрещаем редактирование полей, входящих в restricted_user_info @@ -867,19 +824,10 @@ sub make_profile { $cgi->delete("pass1"); $cgi->delete("pass2"); if ($cgi->param("avatarfile" )) { - my $f = $cgi->upload("avatarfile"); - binmode $f,":bytes"; - my $out; - my $filename = $1 if $cgi->param("avatarfile")=~/([^\/\\]+)$/; - my $path = $forum->{"userdir"}."/".$userprefix."_".$filename; - open $out,">",$path; - binmode $out,":bytes"; - my $buffer; - while (my $bytes = read($f,$buffer,4096)) { - print $out $buffer; - } - close $f; - close $out; + my $filename = + (save_attached_images($cgi,$forum,$forum->{userdir},"${userprefix}_%f", + "avatarfile"))[1]; + my $path = $forum->{"userdir"}."/".$filename; my ($w,$h) = imgsize($path); $userinfo->{'avatar'}= {src=>$forum->{"userurl"}."/".$userprefix."_".$filename, width=>$w,height=>$h}; @@ -901,8 +849,12 @@ sub make_profile { next if $param =~ /_format$/; if (defined $cgi->param("${param}_format")) { my $tree = input2tree($cgi,$forum,$param); - $userinfo->{$param} = tree2str($tree); - $tree->delete(); + if ($tree) { + $userinfo->{$param} = tree2str($tree); + $tree->delete(); + } else { + delete $userinfo->{$param}; + } } else { $userinfo->{$param} = $cgi->param($param); } @@ -1023,16 +975,16 @@ sub logout { } sub allow_operation { my ($operation,$cgi,$forum) = @_; - return 1 if (!exists($permissions{$operation})); + return 1 if (!exists($operation->{rights})); if (!$forum->{authenticated}) { - return 1 if ($permissions{$operation} eq "login"); + return 1 if ($operation->{rights} eq "login"); return 0; } my $user = $forum->{authenticated}{user} ; my $accesslevel=getrights($cgi,$forum); return 1 if ($accesslevel eq "admin"); - return 0 if ($permissions{$operation} eq "admin"); + return 0 if ($operation->{rights} eq "admin"); return 1 if ($accesslevel eq "moderator"); return 0 if $accesslevel eq "banned"; return 1; @@ -1051,7 +1003,6 @@ sub reply { if (!$newmsg) { show_error($forum,"Шаблон темы не содержит элемента с классом message"); - exit; } # @@ -1066,25 +1017,8 @@ sub reply { my $dir = $path_translated; $dir=~ s/[^\/]+$// if (-f $dir); - my %attached; - for (my $i=1;$cgi->param("image$i"); $i++) { - my $userpath=$cgi->param("image$i"); - my $filename=lc($1) if $userpath =~ /([^\/\\]+)$/; - $attached{$filename} = $id."_".$filename; - my $in = $cgi->upload("image$i"); - if (!$in) { - show_error($forum,"Ошибка при загрузке картинки $filename"); - exit; - } - my $out; - open $out,">$dir/$attached{$filename}"; - binmode $out,":bytes"; - local $/=undef; - my $data = <$in>; - print $out $data; - close $in; - close $out; - } + my %attached=save_attached_images($cgi,$forum,$dir,"${id}_%f", + grep(/^image\d+/,$cgi->param)); # # Преобразуем текст записи в html и чистим его # @@ -1093,15 +1027,7 @@ sub reply { # Находим в тексте URL на приаттаченные картинки и меняем на те # имена, под которыми мы их сохранили. # - for my $image ($txtree->find_by_tag_name("img")) { - my $file=lc($image->attr("src")); - if ( exists $attached{$file}) { - $image->attr("src" => $attached{$file}); - my ($width,$height) = imgsize($dir ."/".$attached{$file}); - $image->attr("width" =>$width); - $image->attr("height" => $height); - } - } + fix_image_links($txtree,\%attached,$dir); # # Подставляем данные сообщения # @@ -1167,6 +1093,46 @@ sub reply { update_topic_list($forum,$path_translated,$msgcount,$posted); forum_redirect($cgi,$forum,$cgi->path_info."#$id"); } +sub fix_image_links { + my ($txtree,$attached,$dir) =@_; + for my $image ($txtree->find_by_tag_name("img")) { + my $file=lc($image->attr("src")); + if ( exists $attached->{$file}) { + $image->attr("src" => $attached->{$file}); + my ($width,$height) = imgsize($dir ."/".$attached->{$file}); + $image->attr("width" =>$width); + $image->attr("height" => $height); + } + } +} +sub save_attached_images { + my ($cgi,$forum,$dir,$nametemplate,@params) = @_; + my %attached; + for my $param (@params) { + my $userpath=$cgi->param($param); + next unless $userpath; + my $filename=lc($1) if $userpath =~ /([^\/\\]+)$/; + my $ext = $1 if $filename =~/([^.]+)$/; + my %subst=(f=>$filename,e=>$ext); + $attached{$filename} = $nametemplate; + $attached{$filename}=~s/\%([fe])/$subst{$1}/eg; + my $in = $cgi->upload($param); + if (!$in) { + show_error($forum,"Ошибка при загрузке картинки $filename"); + exit; + } + my $out; + open $out,">$dir/$attached{$filename}"; + binmode $out,":bytes"; + local $/=undef; + my $data = <$in>; + print $out $data; + close $in; + close $out; + } + return %attached; + +} sub update_topic_list { my ($forum,$topic,$count,$date) = @_; my ($tree,$lockfd,$block,$index); @@ -1193,22 +1159,132 @@ sub record_as_recent { my ($tree,$lockfd) = gettree($forum->{forumroot}."/recent.html"); my $msglist = $tree->look_down("class"=>"messagelist"); if ($msglist) { - my $style = $msglist->attr("style"); - if ($style && $style =~ s/display: none;//) { - $msglist->attr("style",$style); - $msglist->look_down(class=>"message")->replace_with($msg); + my $old_copy = $msglist->look_down(id=>$msg->attr("id")); + if ($old_copy) { + $old_copy->replace_with($msg)->delete; } else { - my @msgs = $msglist->look_down("class"=>"message"); - if (@msgs >= $forum->{replies_per_page}) { - for (my $i=$#msgs;$i>=$forum->{replies_per_page}-1;$i--) { - $msgs[$i]->delete; - } - } - $msgs[0]->preinsert($msg); + my $style = $msglist->attr("style"); + if ($style && $style =~ s/display: none;//) { + $msglist->attr("style",$style); + $msglist->look_down(class=>"message")->replace_with($msg); + } else { + my @msgs = $msglist->look_down("class"=>"message"); + if (@msgs >= $forum->{replies_per_page}) { + for (my $i=$#msgs;$i>=$forum->{replies_per_page}-1;$i--) { + $msgs[$i]->delete; + } + } + $msgs[0]->preinsert($msg); + } } } savetree($forum->{forumroot}."/recent.html",$tree,$lockfd); } +sub getperms { + my $dir = shift; + local $_; + my $key; + my %users=(admins=>"",moderators=>"",banned=>""); + if (open F,"<",$dir."/perms.txt") { + while () { + next if /^\s*$/; + next if /^\s*#/; + if (/^\s*\[\s*(\w+)\s*\]\s*$/) { + $key = $1; + } else { + $users{$key} .= $_ if ($key); + } + } + close F; + } + return %users; +} +# +# Извлекает из указанного html файла содержимое тэга title +# +sub gettitle { +our $gettitle_flag=0; +our $gettitle_text=""; + + open F,"<",shift or return undef; + my $parser = HTML::Parser->new(api_version=>3, + text_h=>[sub { $gettitle_text .= + shift if $gettitle_flag;}, "dtext"], + start_h=>[sub { $gettitle_flag =1 if $_[0] eq 'title'}, "tagname" ], + end_h => [sub { $_[1]->eof if $_[0] eq 'title'}, "tagname, self" ]); + while (!eof F) { + my $data; + read F,$data,4096; + $parser->parse($data) or last; + } + return $gettitle_text; +} + +# +# Показ формы реактирования прав +# + +sub show_rights { + my ($form,$cgi,$forum) = @_; + # Получаем текущие права доступа + my %users=getperms($path_translated); + while (my($key,$val) = each %users) { + $cgi->param($key,$val); + } + + my $tree = prepare_template(@_); + # Пробегаемся вверх по дереву + + hide_list($tree,"dirlist"); + if ($path_translated ne $forum->{forumroot}) { + my $d = $path_translated; + my @dirs; + while ($d) { + # и получаем список файлов perms.txt + $d=~s/\/[^\/]+$//; + unshift @dirs,$d if -f "$d/perms.txt"; + last if $d eq $forum->{forumroot}; + + } + # Подставляем их куда надо + for $d (@dirs) { + my %users = getperms($d); + my $title=gettitle($d."/".$forum->{indexfile}); + my $item = newlistelement($tree,"dir","dirlist"); + substinfo($item,[_tag => 'a',class=>'dirlink'], + href=>$d,_content=>$title); + + substinfo($item,[_tag=>'a',class=>'rights'], + href=>$cgi->url(-absolute=>1,-path_info=>0).dir2url($cgi,$d)."?setrights=1"); + while (my ($key,$val) = each %users) { + my @data = map {$_=>new HTML::Element("br")} split /\r?\n/, $val; + substinfo($item,[class=>$key],_content=>\@data); + } + } + } + my $f = $tree->look_down(_tag=>'form',name=>'setrights'); + substinfo($f,[_tag=>'a',class=>'dirlink'], + href=>$cgi->path_info, + _content=>gettitle($path_translated."/".$forum->{indexfile})); + # Отдаем юзеру. + send_to_user($tree,@_); +} + +sub set_rights { + my ($form,$cgi,$forum) = @_; + my $newperm = ""; + for my $section ('admins','moderators','banned') { + my $data = $cgi->param($section); + $data=~s/\r?\n/\n/gs; + $data.="\n" unless $data =~/\n$/s; + $newperm .= "[ $section ]\n$data"; + } + if (replacefile($path_translated."/perms.txt",$newperm)) { + set_error($forum,"Списки модераторов раздела обновлены"); + } + show_rights(@_); +} + # # Обработка операции создания новой темы. # @@ -1328,21 +1404,7 @@ sub new_forum { # my ($logo_name,$logo_width,$logo_height); if ($cgi->param("logo")) { - my $userpath = $cgi->param("logo"); - $logo_name="logo.".lc($1) if $userpath=~/\.([^.]+)$/; - my $in = $cgi->upload("logo"); - if (!$in) { - show_error($forum,"Ошибка при загрузке картинки $userpath"); - exit; - } - my $out; - open $out,">$newname/$logo_name"; - binmode $out,":bytes"; - local $/=undef; - my $data = <$in>; - print $out $data; - close $in; - close $out; + $logo_name=(save_attached_images($cgi,$forum,$newname,"logo.%e","logo"))[1]; ($logo_width,$logo_height) = imgsize("$newname/$logo_name"); } else { $logo_name = $forum->{"templatesurl"}."/1x1.gif"; @@ -1433,10 +1495,34 @@ sub new_forum { forum_redirect($cgi,$forum,$cgi->url(-base=>1).$url); } - # -# Обработка операции удаления всего на свете +# Обработка операций, которые вызываются одинаково, +# но выполняются по-разному для разных типов объектов # +# Параметры $cgi,$forum, тип => ссылка на функцию ... +# где тип - message, topic или forum. Определяет обрабатываемый объект +# и вызывает соответствующую фунцкию. Ожидает что функция завершится +#вызовом exit. +sub dispatch_objtype { + my $cgi=shift; + my $forum = shift; + my %actions=@_; + if (-f $path_translated) { + if ($cgi->param("id")) { + $actions{"message"}->($cgi,$forum,$path_translated,$cgi->param("id")) + if exists($actions{'message'}); + } else { + $actions{topic}->($cgi,$forum,$path_translated) + if exists($actions{'topic'}); + } + } elsif (-d $path_translated && -f $path_translated ."/". $forum->{indexfile}) { + $actions{'forum'}->($cgi,$forum,$path_translated) + if exists($actions{'forum'}); + + } + return undef; +} +#Удаление sub delete_item { my ($formname,$cgi,$forum) = @_; # @@ -1444,18 +1530,42 @@ sub delete_item { # if ($cgi->param("user")) { delete_user($cgi,$forum,$cgi->param("user")); - } elsif (-f $path_translated) { - if ($cgi->param("id")) { - delete_comment($cgi,$forum,$path_translated,$cgi->param("id")); - } else { - delete_topic($cgi,$forum,$path_translated); - } - } elsif (-d $path_translated && -f $path_translated ."/". $forum->{indexfile}) { - delete_forum($cgi,$forum,$path_translated); - } else { - show_error($forum,"Невозможно удалить неопознанный объект"); - } + } + dispatch_objtype($cgi,$forum,topic=>\&delete_topic, + message=>\&delete_comment, + forum=>\&delete_forum); + show_error($forum,"Невозможно удалить неопознанный объект"); } +# Показ формы редактирования +sub show_editable { + my ($formname,$cgi,$forum) = @_; + dispatch_objtype($cgi,$forum,"message"=>\&show_messageedit, + topic=>\&show_topicedit, + forum=>\&show_forumedit); + show_error($forum,"Невозможно редактировать неопознанный объект"); +} +# Применение результатов редактирования +sub edit_item { + my ($formname,$cgi,$forum) = @_; + dispatch_objtype($cgi,$forum,"message"=>\&messageedit, + topic=>\&topicedit, + forum=>\&forumedit); + show_error($forum,"Невозможно редактировать неопознанный объект"); +} +sub move_item { + my ($formname,$cgi,$forum) = @_; + dispatch_objtype($cgi,$forum,"message"=>\&move_message, + topic=>\&move_topic, + forum=>\&move_forum); + show_error($forum,"Невозможно переместить неопознанный объект"); +} +sub show_move_dest { + my ($formname,$cgi,$forum) = @_; + dispatch_objtype($cgi,$forum,"message"=>\&show_move_message, + topic=>\&show_move_topic, + forum=>\&show_move_forum); + show_error($forum,"Невозможно переместить неопознанный объект"); +} # # Удаление пользователя # @@ -1472,6 +1582,20 @@ sub delete_user { dbmclose %base; forum_redirect($cgi,$forum,$forum->{forumtop}); } +# Проверка прав на изменение реплики +sub moderator_or_author { + my ($cgi,$forum,$msg)=@_; + return 1 if getrights($cgi,$forum) eq "moderator" + || getrights($cgi,$forum) eq "admin"; + my $author= $msg->look_down(_tag=>"input",name=>"author"); + if ($author) { + return $author->attr("value") eq $forum->{authenticated}{user}; + } elsif ($author = $msg->look_down(class=>"author",_tag=>"a")) { + return $author->as_text eq $forum->{authenticated}{user}; + } else { + return undef; + } +} # # Удаление реплики # @@ -1480,13 +1604,8 @@ sub delete_comment { my ($tree,$lockfd) = gettree($topic); my ($msg) = $tree->look_down(id => $id); show_error($forum,"В данной теме нет реплики с id=$id") if (!$msg); - if (getrights($cgi,$forum) ne "moderator" - && getrights($cgi,$forum) ne "admin") { - my $author= $msg->look_down(_tag=>"input",name=>"author"); - if ($author->attr("value") ne $forum->{authenticated}{user}) { - show_error($forum,"У вас нет прав на удаление этого сообщения"); - } - } + show_error($forum,"У вас нет прав на удаление этого сообщения") + unless moderator_or_author($cgi,$forum,$msg); delete_from_list($tree,"messagelist","message",$msg); savetree($topic,$tree,$lockfd); $tree->delete; @@ -1529,7 +1648,7 @@ sub delete_topic { } # FIXME при удалении непустой темы модератором почистить recent.html my ($tree,$lockfd) = gettree($dir . "/".$forum->{indexfile}); delete_from_list($tree,"topiclist","topic",$id); - savetree($tree,$dir ."/".$forum->{indexfile}); + savetree($dir ."/".$forum->{indexfile},$tree); unlink $topic; my $redirect_url = $cgi->path_info; $redirect_url =~ s/\/[^\/]*$//; @@ -1555,7 +1674,7 @@ sub delete_forum { $count ++; } closedir DIR; - show_error("Нельзя удалять непустой форум") if $count; + show_error($forum,"Нельзя удалять непустой форум") if $count; # Находим родительский форум my $upper = $dir; $upper=~s/([\/]+)$/$forum->{indexfile}/; @@ -1575,6 +1694,237 @@ sub delete_forum { $redirect_url =~ s/\/[^\/]*$//; forum_redirect($cgi,$forum,$redirect_url); } +# Показ сообщения для редактирования +sub show_messageedit { + my ($cgi,$forum,$path,$id)=@_; + my ($tree,$lockfd) = gettree($path); + my $dirname = $path; + $dirname =~ s/\/[^\/]+$//; + my ($msg) = $tree->look_down(id => $id); + show_error($forum,"В данной теме нет реплики с id=$id") if (!$msg); + show_error($forum,"У вас нет прав на редактированиее этого сообщения") + unless moderator_or_author($cgi,$forum,$msg); + # Выбираем данные сообщения + my ($text) = $msg->look_down(class=>"mtext")->content_list; + my ($subject) = $msg->look_down(class=>"subject"); + tree2input($cgi,"text",$text); + $cgi->param("subject"=> $subject->as_text); + discardtree($tree,$lockfd); + # Подготавливаем шаблон + my $form = prepare_template("edit_message",$cgi,$forum); + # Подставляем информацию о картинках. + opendir D,$dirname; + while ( my $filename=readdir D) { + next unless $filename =~/^${id}_/; + my $pic = "$dirname/$filename"; + my $picitem = newlistelement($form,"picture","picturelist"); + my ($w,$h) = imgsize($pic); + substinfo($picitem,[_tag=>"img", class=>"msgpicture"], + src=>dir2url($cgi,$pic),width=>$w,height=>$h); + substinfo($picitem,[_tag=>"input",name=>"delpicture"], + value=>$filename); + substinfo($picitem,[class=>"filename"],_content =>$filename); + } + closedir D; + send_to_user($form,"edit_message",$cgi,$forum); +} +# Показ темы для редактирования +sub show_topicedit { + my ($cgi,$forum,$path)=@_; + my ($tree,$lockfd) = gettree($path); + my $dirname = $path; + $dirname =~ s/\/([^\/]+).html$//; + my $urlname=$1; + my $topic = $tree->look_down("class"=>"topic"); + show_error($forum,"У вас нет прав на редактированиее этой темы") + unless moderator_or_author($cgi,$forum,$topic); + # Выбираем данные сообщения + my ($text) = $topic->look_down(class=>"abstract")->content_list; + my ($subject) = $topic->look_down(class=>"title"); + tree2input($cgi,"abstract",$text); + $cgi->param("title"=> $subject->as_text); + discardtree($tree,$lockfd); + # Подготавливаем шаблон + my $form = prepare_template("edit_topic",$cgi,$forum); + # Подставляем информацию об URL. + substinfo($form,[class=>"urlname"],_content=>$urlname); + send_to_user($form,"edit_topic",$cgi,$form); +} +# Показ форума для редактирования +sub show_forumedit { + my ($cgi,$forum,$path) = @_; + show_error($forum,"У вас нет прав на редактированиее этого форума") + unless (getrights($cgi,$forum) eq 'moderator' || getrights($cgi,$forum) eq + 'admin'); + + my ($tree,$lockfd) = gettree($path."/".$forum->{indexfile}); + my $dirname = $path; + $dirname =~ s/\/([^\/]+)$//; + my $urlname=$1; + my $anno = $tree->look_down("class"=>"annotation"); + # Выбираем данные сообщения + my ($text) = $anno->look_down(class=>"abstract")->content_list; + my ($subject) = $anno->look_down(class=>"title"); + tree2input($cgi,"abstract",$text); + $cgi->param("title"=> $subject->as_text); + discardtree($tree,$lockfd); + # Подготавливаем шаблон + my $form = prepare_template("edit_forum",$cgi,$forum); + # Подставляем информацию об URL. + substinfo($form,[class=>"urlname"],_content=>$urlname); + # Подставляем логотип + opendir D,$path; + my $logo=0; + while (my $file = readdir(D)) { + next unless $file =~ /^logo.\w+$/; + my ($w,$h) = imgsize($path."/".$file); + substinfo ($form,[_tag =>"img",class=>"logo"], + src=>$cgi->path_info."/".$file, + width=>$w, + height=>$h); + substinfo($form,[_tag=>"input", + name=>"delpicture"],value=>$file); + $logo=1; + last; + } + closedir D; + unless ($logo) { + substinfo($form,[class=>"picture"], + style=>"display: none;"); + } + send_to_user($form,"edit_forum",$cgi,$form); +} + +sub messageedit { + my ($cgi,$forum,$topic,$id) = @_; + my ($tree,$lockfd) = gettree($path_translated); + my ($msg) = $tree->look_down(id=>$id); + show_error($forum,"В данной теме нет реплики с id=$id") if (!$msg); + show_error($forum,"У вас нет прав на редактированиее этого сообщения") + unless moderator_or_author($cgi,$forum,$msg); + # Обработка картинок + my ($dirname,$topic_id)=($1,$2) if $path_translated=~/(.+)\/([^\/]+).html/; + # 1. Удаляем помеченные как таковые + for my $file ($cgi->param("delpictire")) { + unlink $dirname."/".$file; + } + # 2. Сохраняем свежеприаттаченные + my %attached=save_attached_images($cgi,$forum,$dirname,"${id}_%f",grep(/^image\d+/,$cgi->param)); + + # Преобразуем текст в html + my $txtree = input2tree($cgi,$forum,"text"); + fix_image_links($txtree,\%attached,$dirname); + my $edited = strftime("%d.%m.%Y %H:%M",localtime()); + substinfo($msg,[class=>"subject"],_content=>$cgi->param("subject")); + substinfo($msg,[class=>"editdate"],_content=>$edited); + makeuserlink($forum,$msg,"editor",$forum->{authenticated}); + unhide_list($msg,"edited"); + my $textnode = $msg->look_down(class=>"mtext"); + my ($old_text)=$textnode->splice_content(0,1,$txtree); + $old_text->delete; + $msg = $msg->clone; + my @msgs = $tree->look_down(class=>"message"); + my $msgcount=@msgs; + savetree($path_translated,$tree,$lockfd); + record_as_recent($forum,$msg); + update_topic_list($forum,$path_translated,$msgcount,$edited); + forum_redirect($cgi,$forum,$cgi->url(-base=>1).$cgi->path_info()."#$id"); +} + + +sub topicedit { + my ($cgi,$forum,$topic) = @_; + show_error($forum,"Нет такой темы ".$cgi->path_info) + if (!-f $path_translated); + show_error($forum,"У вас нет прав на редактированиее этой темы") + unless moderator_or_author($cgi,$forum,$topic); + form_error("edit_topic",$cgi,$forum,"Тема должна иметь непустое название") + if (!$cgi->param("title")); + my $abstract = input2tree($cgi,$forum,"abstract"); + my ($tree,$lockfd) = gettree($path_translated); + my $subtree = $tree->look_down("class"=>"topic"); + if ($subtree) { + substinfo($subtree,["class"=>"title"], + _content=>$cgi->param("title")); + # Вставляем в страницу КОПИЮ аннотации, поскольку аннотация + # нам еще понадобится в списке тем. + substinfo($subtree,["class"=>"abstract"],_content=>$abstract->clone); + } else { + substinfo($tree,["class"=>"title"], + _content=>$cgi->param("title")); + } + savetree($path_translated,$tree,$lockfd); + $tree->destroy; + my ($dir,$id) = ($1,$2) if $path_translated=~/^(.*)\/([^\/]+).html$/; + ($tree,$lockfd) = gettree($dir."/".$forum->{indexfile}); + my $item = $tree->look_down(id=>$id); + substinfo($item,[_tag=>"a","class"=>"title"], + _content=>$cgi->param("title")); + substinfo($item,["class"=>"abstract"],_content=>$abstract); + savetree($dir."/".$forum->{"indexfile"},$tree,$lockfd); + forum_redirect($cgi,$forum); +} + +sub forumedit { + my ($cgi,$forum,$dir) = @_; + show_error($forum,"У вас нет прав на редактированиее этого форума") + unless (getrights($cgi,$forum) eq 'moderator' || getrights($cgi,$forum) eq + 'admin'); + + if (!-d $path_translated) { + show_error($forum,"Операция редактирования форумаможет быть вызвана только со + страницы форума"); + } + if (!$cgi->param("title")) { + form_error("edit_forum",$cgi,$forum,"Форум должен иметь непустое название"); + } + my ($logo_name,$logo_width,$logo_height); + if ($cgi->param("delpicture")) { + # Удаляем старый логотип + unlink $path_translated ."/".$cgi->param("delpicture"); + $logo_name = $forum->{"templatesurl"}."/1x1.gif"; + $logo_width = 1; + $logo_height=1; + } + if ($cgi->param("logo")) { + # Удаляем все, что похоже на логотип + opendir D, $path_translated; + for my $f (readdir(D)) { + next unless -f $path_translated."/".$f && $f=~/^logo\.\w+$/; + unlink $path_translated."/".$f; + } + closedir D; + $logo_name=(save_attached_images($cgi,$forum,$path_translated,"logo.%e","logo"))[1]; + ($logo_width,$logo_height) = imgsize("$path_translated/$logo_name"); + } + my ($tree,$lockfd) = gettree($path_translated . "/".$forum->{indexfile}); + my $abstract = input2tree($cgi,$forum,"abstract"); + substinfo($tree,[_tag=>"meta","name"=>"description"],content=>$abstract->as_trimmed_text); + substinfo($tree,[_tag=>"title"],_content=>$cgi->param("title")); + my $subtree = $tree->look_down("class"=>"annotation"); + substinfo($subtree,["class"=>"title"], + _content=>$cgi->param("title")); + # Вставляем в страницу КОПИЮ аннотации, поскольку аннотация + # нам еще понадобится в списке тем. + substinfo($subtree,["class"=>"abstract"],_content=>$abstract->clone); + substinfo($subtree,[_tag=>"img","class"=>"logo"], + src=> $logo_name, width=>$logo_width, height=>$logo_height) + if defined($logo_name); + savetree($path_translated ."/".$forum->{indexfile},$tree,$lockfd); + $tree->destroy; + if ($path_translated ne $forum->{forumroot}) { + my ($updir,$id) = ($1,$2) if $path_translated=~/^(.*)\/([^\/]+)$/; + ($tree,$lockfd) = gettree($updir . "/".$forum->{indexfile}); + my $item = $tree->look_down(id=>$id); + substinfo($item,[_tag=>"a","class"=>"title"], + _content=>$cgi->param("title")); + substinfo($item,["class"=>"abstract"],_content=>$abstract); + substinfo($item,[_tag=>"img","class"=>"logo"],src=>"$id/$logo_name", + width=>$logo_width,height=>$logo_height) if $logo_name; + savetree($updir."/".$forum->{"indexfile"},$tree,$lockfd); + } + forum_redirect($cgi,$forum); +} #---------------------------------------------------------- # База пользователей и права доступа @@ -1659,23 +2009,26 @@ sub gettree { open $f,"<",$filename or return undef; flock $f, LOCK_EX; my $tree = treefromfile($f); - $tree->parse_file($f); return ($tree,$f); } # # Сохранить дерево и закрыть lockfd. # # - -sub savetree { - my ($filename,$tree,$lockfd) = @_; - my $f; +sub replacefile { + my $filename = shift; + my $content = shift; + my $f; open $f,">",$filename . ".new" or return undef; - print $f output_html($tree); + print $f $content; close $f; # FIXME - только для POSIX. unlink $filename; rename $filename.".new",$filename; +} +sub savetree { + my ($filename,$tree,$lockfd) = @_; + replacefile($filename,output_html($tree)); close $lockfd if defined($lockfd); } @@ -1798,7 +2151,7 @@ sub openidstart { # реплики) # sub openid_verify { - my ($cgi,$forum) = @_; + my ($action,$cgi,$forum) = @_; my $csr = create_openid_consumer($cgi,$forum); if (my $setup_url = $csr->user_setup_url) { print $cgi->redirect(-location=>$setup_url); @@ -1904,13 +2257,15 @@ sub input2tree { my ($cgi,$forum,$field_name) = @_; my $format = $cgi->param($field_name."_format"); my $text = $cgi->param($field_name); + return "" if (!$text); if ($format eq "bbcode") { my $parser = HTML::BBReverse->new(); $text="
".$parser->parse($text)."
"; } elsif ($format eq "text") { - $text=~s/\r?\n\r?\n/<\/p>

/; - $text=~s/\r?\n/
/; - $text = "

".escapeHTML($text)."

"; + $text = escapeHTML($text); + $text=~s/\r?\n\r?\n/<\/p>

/sg; + $text=~s/\r?\n/
/sg; + $text = "

$text

"; } my $txtree = str2tree($text); for my $badtag @@ -1925,6 +2280,11 @@ sub input2tree { } +sub tree2input { + my ($cgi,$field_name,$tree) = @_; + $cgi->param($field_name=>$tree->as_HTML('<>&"')); + $cgi->param("${field_name}_format"=>"html"); +} sub str2tree { my ($data)=@_; @@ -2032,7 +2392,11 @@ sub substinfo { my $value = shift @attrs; if ($attr eq "_content") { $element->delete_content; + if (ref($value) eq 'ARRAY') { + $element->push_content(@$value) ; + } else { $element->push_content($value); + } } else { $element->attr($attr,$value); }