📄 comments.pm
字号:
# Copyright 2001-2005 Six Apart.# SCRiPTMAFiA 2005 - THE DiRTY HANDS ON YOUR SCRiPTS## $Id: Comments.pm 10599 2005-03-22 20:39:23Z bchoate $package MT::App::Comments;use strict;use MT::App;@MT::App::Comments::ISA = qw( MT::App );use MT::Comment;use MT::Util qw( remove_html encode_html decode_url );use MT::Entry qw(:constants);use MT::Author qw(:constants);my $COMMENTER_COOKIE_NAME = "tk_commenter";sub init { my $app = shift; $app->SUPER::init(@_) or return; $app->add_methods( preview => \&preview, post => \&post, view => \&view, handle_sign_in => \&handle_sign_in, cmtr_name_js => \&commenter_name_js, red => \&do_red, ); $app->{default_mode} = 'view'; $app->{charset} = $app->{cfg}->PublishCharset; my $q = $app->{query}; ## We don't really have a __mode parameter, because we have to ## use named submit buttons for Preview and Post. So we hack it. if ($q->param('post')) { $q->param('__mode', 'post'); } elsif ($q->param('preview')) { $q->param('__mode', 'preview'); } $app;}## $app->_get_commenter_session()## Creates a commenter record based on the cookies in the $app, if# one already exists corresponding to the browser's session.## Returns a pair ($session_key, $commenter) where $session_key is the# key to the MT::Session object (as well as the cookie value) and# $commenter is an MT::Author record. Both values are undef when no# session is active.#sub _get_commenter_session { my $app = shift; my $q = $app->{query}; my $session_key; my %cookies = $app->cookies(); if (!$cookies{$COMMENTER_COOKIE_NAME}) { return (undef, undef); } $session_key = $cookies{$COMMENTER_COOKIE_NAME}->value() || ""; $session_key =~ y/+/ /; require MT::Session; my $sess_obj = MT::Session->load({ id => $session_key }); my $timeout = $app->{cfg}->CommentSessionTimeout; if (!$sess_obj || ($sess_obj->start() + $timeout < time)) { $session_key = undef; # blotto the cookie my %dead_kookee = (-name => $COMMENTER_COOKIE_NAME, -value => '', -path => '/', -expires => '-10y'); $app->bake_cookie(%dead_kookee); my %dead_name_kookee = (-name => "commenter_name", -value => '', -path => '/', -expires => '-10y'); $app->bake_cookie(%dead_name_kookee); $sess_obj->remove() if ($sess_obj); $sess_obj = undef; return (undef, undef); } else { # session is valid! return ($session_key, MT::Author->load({name => $sess_obj->name, type=>MT::Author::COMMENTER})); }}sub do_red { my $app = shift; my $q = $app->{query}; my $id = $q->param('id') or return $app->error("No id"); my $comment = MT::Comment->load($id) or return $app->error("No such comment"); my $uri = encode_html($comment->url); return <<HTML;<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html><head><title>Redirecting...</title><meta name="robots" content="noindex, nofollow"><script type="text/javascript">window.onload = function() { document.location = '$uri'; };</script></head><body><p><a href="$uri">Click here</a> if you are not redirected</p></body></html>HTML}# _builtin_throttle is the builtin throttling code# others can be added by plugins# a filtering callback must return true or false; true# means OK, false means filter it out.sub _builtin_throttle { my $eh = shift; my $app = shift; my ($entry) = @_; my $throttle_period = $app->{cfg}->ThrottleSeconds; my $user_ip = $app->remote_ip; return 1 if ($throttle_period <= 0); # Disabled by ThrottleSeconds 0 require MT::Util; my @ts = MT::Util::offset_time_list(time - $throttle_period, $entry->blog_id); my $from = sprintf("%04d%02d%02d%02d%02d%02d", $ts[5]+1900, $ts[4]+1, @ts[3,2,1,0]); require MT::Comment; if (MT::Comment->count({ ip => $user_ip, created_on => [$from], blog_id => $entry->blog_id}, {range => {created_on => 1} })) { return 0; # Put a collar on that puppy. } @ts = MT::Util::offset_time_list(time - $throttle_period * 10 - 1, $entry->blog_id); $from = sprintf("%04d%02d%02d%02d%02d%02d", $ts[5]+1900, $ts[4]+1, @ts[3,2,1,0]); my $count = MT::Comment->count({ ip => $user_ip, created_on => [$from], blog_id => $entry->blog_id }, { range => {created_on => 1} }); if ($count >= 8) { require MT::IPBanList; my $ipban = MT::IPBanList->new(); $ipban->blog_id($entry->blog_id); $ipban->ip($user_ip); $ipban->save(); $ipban->commit(); $app->log("IP $user_ip banned because comment rate " . "exceeded 8 comments in " . 10 * $throttle_period . " seconds.\n"); require MT::Mail; my $author = $entry->author; $app->set_language($author->preferred_language) if $author && $author->preferred_language; my $blog = MT::Blog->load($entry->blog_id); if ($author && $author->email) { my %head = ( To => $author->email, From => $app->{cfg}->EmailAddressMain, Subject => '[' . $blog->name . '] ' . $app->translate("IP Banned Due to Excessive Comments")); my $charset = $app->{cfg}->PublishCharset || 'iso-8859-1'; $head{'Content-Type'} = qq(text/plain; charset="$charset"); my $body = $app->translate('_THROTTLED_COMMENT_EMAIL', $blog->name, 10 * $throttle_period, $user_ip, $user_ip); require Text::Wrap; $Text::Wrap::cols = 72; $body = Text::Wrap::wrap('', '', $body); MT::Mail->send(\%head, $body); } return 0; } return 1;}sub post { my $app = shift; my $q = $app->{query}; return do_preview($app, $q, @_) if $app->request_method() ne 'POST'; my $entry_id = $q->param('entry_id') or return $app->error("No entry_id"); require MT::Entry; my $entry = MT::Entry->load($entry_id) or return $app->error($app->translate( "No such entry '[_1]'.", scalar $q->param('entry_id'))); return $app->error($app->translate( "No such entry '[_1]'.", scalar $q->param('entry_id'))) if $entry->status != RELEASE; require MT::IPBanList; my $iter = MT::IPBanList->load_iter({ blog_id => $entry->blog_id }); while (my $ban = $iter->()) { my $banned_ip = $ban->ip; if ($app->remote_ip =~ /$banned_ip/) { return $app->handle_error($app->translate( "You are not allowed to post comments.")); } } MT->add_callback('CommentThrottleFilter', 1, undef, \&MT::App::Comments::_builtin_throttle); # Run all the Comment-throttling callbacks my $passed_filter = MT->run_callbacks('CommentThrottleFilter', $app, $entry); $passed_filter || return $app->handle_error($app->translate("_THROTTLED_COMMENT"), "403 Throttled"); if (my $state = $q->param('comment_state')) { require MT::Serialize; my $ser = MT::Serialize->new($app->{cfg}->Serializer); $state = $ser->unserialize(pack 'H*', $state); $state = $$state; for my $f (keys %$state) { $q->param($f, $state->{$f}); } } unless ($entry->allow_comments eq '1') { return $app->handle_error($app->translate( "Comments are not allowed on this entry.")); } require MT::Blog; my $blog = MT::Blog->load($entry->blog_id); if (!$q->param('text')) { return $app->handle_error($app->translate("Comment text is required.")); } my ($comment, $commenter) = _make_comment($app, $entry); if (!$blog->allow_unreg_comments) { if (!$commenter) { return $app->handle_error($app->translate( "Registration is required.")) } } if (!$blog->allow_anon_comments && (!$comment->author || !$comment->email)) { return $app->handle_error($app->translate( "Name and email address are required.")); } if ($blog->allow_unreg_comments()) { $comment->email($q->param('email')) unless $comment->email(); } if ($comment->email) { require MT::Util; if (my $fixed = MT::Util::is_valid_email($comment->email)) { $comment->email($fixed); } elsif ($comment->email =~ /^[0-9A-F]{40}$/i) { # It's a FOAF-style mbox hash; accept it if blog config says to. return $app->handle_error("A real email address is required") if ($blog->require_comment_emails()); } else { return $app->handle_error($app->translate( "Invalid email address '[_1]'", $comment->email)); } } if ($comment->url) { require MT::Util; if (my $fixed = MT::Util::is_valid_url($comment->url, 'stringent')) { $comment->url($fixed); } else { return $app->handle_error($app->translate( "Invalid URL '[_1]'", $comment->url)); } } return $app->handle_error($app->errstr()) unless $comment; ## Here comes the fancy logic for deciding whether or not the ## comment appears. if ($commenter) { # First, auto-approve if necessary. if (!$blog->manual_approve_commenters && ($commenter->status($entry->blog_id) == PENDING)) { $commenter->approve($entry->blog_id); } # If the commenter is approved, publish the comment. if ($commenter->status($blog->id) == APPROVED) { $comment->visible(1); } } else { # We don't have a commenter object, but the user wasn't booted # so unless moderation is on, we can publish the comment. unless ($blog->moderate_unreg_comments) { $comment->visible(1); } } # Form a link to the comment my $comment_link; if (!$q->param('static')) { my $url = $app->base . $app->uri; $url .= '?entry_id=' . $q->param('entry_id'); $url .= '&static=0&arch=1' if ($q->param('arch')); $comment_link = $url; } else { my $static = $q->param('static'); if ($static eq '1') { # I think what we really want is the individual archive. $comment_link = $entry->permalink; } else { $comment_link = $static . '#' . $comment->id; } } my $not_declined = 1; if (!$commenter || $commenter->status($blog->id) != BLOCKED) { # Before saving this comment, check whether this commenter has # placed any other comments on the entry's author's other entries. # (on any other entries by the same author as this one) my $commenter_has_comment = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -