Jifty-Plugin-Comment-1.00/0000755000175000017500000000000011221075700015562 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/t/0000755000175000017500000000000011221075700016025 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/t/TestApp-Plugin-Comments/0000755000175000017500000000000011221075700022424 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/t/TestApp-Plugin-Comments/etc/0000755000175000017500000000000011221075700023177 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/t/TestApp-Plugin-Comments/etc/config.yml0000644000175000017500000000222211155144775025204 0ustar agostiniagostini--- framework: AdminMode: 1 ApplicationClass: TestApp::Plugin::Comments ApplicationName: TestApp::Plugin::Comments ApplicationUUID: E6A5E652-A2D2-11DC-B489-8901F3F60BF3 ConfigFileVersion: 2 Database: AutoUpgrade: 1 CheckSchema: 1 Database: testapp::plugin::comments Driver: SQLite Host: localhost Password: '' RecordBaseClass: Jifty::DBI::Record::Cachable RecordUUIDs: active User: '' Version: 0.0.1 DevelMode: 1 L10N: PoDir: share/po LogLevel: INFO Mailer: Sendmail MailerArgs: [] Plugins: - LetMe: {} - SkeletonApp: {} - REST: {} - Halo: {} - ErrorTemplates: {} - OnlineDocs: {} - CompressedCSSandJS: {} - AdminUI: {} - Comment: {} PubSub: Backend: Memcached Enable: ~ SkipAccessControl: 0 TemplateClass: TestApp::Plugin::Comments::View Web: BaseURL: http://localhost DataDir: var/mason Globals: [] MasonConfig: autoflush: 0 default_escape_flags: h error_format: text error_mode: fatal Port: 8888 ServeStaticFiles: 1 StaticRoot: share/web/static TemplateRoot: share/web/templates Jifty-Plugin-Comment-1.00/t/TestApp-Plugin-Comments/t/0000755000175000017500000000000011221075700022667 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/t/TestApp-Plugin-Comments/t/00-model-BlogPost.t0000644000175000017500000000444011155144775026141 0ustar agostiniagostini#!/usr/bin/env perl use warnings; use strict; =head1 DESCRIPTION A basic test harness for the BlogPost model. =cut use Test::More; BEGIN { if (eval { require HTML::Scrubber; require MIME::Base64::URLSafe; require Regexp::Common::Email::Address; 1 }) { plan tests => 16; } else { plan skip_all => 'A requirement of the Comment plugin is not installed.'; } } use Jifty::Test::Dist; # Make sure we can load the model use_ok('TestApp::Plugin::Comments::Model::BlogPost'); # Grab a system user my $system_user = TestApp::Plugin::Comments::CurrentUser->superuser; ok($system_user, "Found a system user"); # Try testing a create my $o = TestApp::Plugin::Comments::Model::BlogPost->new(current_user => $system_user); my ($id) = $o->create(); ok($id, "BlogPost create returned success"); ok($o->id, "New BlogPost has valid id set"); is($o->id, $id, "Create returned the right id"); my $c_list = $o->comments; is($c_list->count, 0, 'We have zippo comments'); # Add a comment my $c = TestApp::Plugin::Comments::Model::Comment->new(current_user => $system_user); $c->create( title => 'Jifty is da bomb', body => 'And other overused clichés...', created_on => DateTime->now, your_name => 'Sterling', ); ok($c->id, 'Created a comment'); my $bpc = TestApp::Plugin::Comments::Model::BlogPostComment->new(current_user => $system_user); $bpc->create( commented_upon => $o->id, the_comment => $c->id, ); ok($bpc->id, 'Created a comment link'); $c_list->redo_search; is($c_list->count, 1, 'We have a comment!'); is($c_list->count_all, 1, 'We have a comment somewhere!'); # And another $o->create(); ok($o->id, "BlogPost create returned another value"); isnt($o->id, $id, "And it is different from the previous one"); # Searches in general my $collection = TestApp::Plugin::Comments::Model::BlogPostCollection->new(current_user => $system_user); $collection->unlimit; is($collection->count, 2, "Finds two records"); # Searches in specific $collection->limit(column => 'id', value => $o->id); is($collection->count, 1, "Finds one record with specific id"); # Delete one of them $o->delete; $collection->redo_search; is($collection->count, 0, "Deleted row is gone"); # And the other one is still there $collection->unlimit; is($collection->count, 1, "Still one left"); Jifty-Plugin-Comment-1.00/t/TestApp-Plugin-Comments/Makefile.PL0000644000175000017500000000020511155144775024412 0ustar agostiniagostiniuse inc::Module::Install; name 'TestApp::Plugin::Comments'; version '0.01'; requires 'Jifty' => '0.71129'; WriteAll; Jifty-Plugin-Comment-1.00/t/TestApp-Plugin-Comments/bin/0000755000175000017500000000000011221075700023174 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/t/TestApp-Plugin-Comments/bin/jifty0000755000175000017500000000032511155144775024266 0ustar agostiniagostini#!/usr/bin/env perl use warnings; use strict; use File::Basename qw(dirname); use UNIVERSAL::require; use Jifty; use Jifty::Script; local $SIG{INT} = sub { warn "Stopped\n"; exit; }; Jifty::Script->dispatch(); Jifty-Plugin-Comment-1.00/t/TestApp-Plugin-Comments/lib/0000755000175000017500000000000011221075700023172 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/t/TestApp-Plugin-Comments/lib/TestApp/0000755000175000017500000000000011221075700024552 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/t/TestApp-Plugin-Comments/lib/TestApp/Plugin/0000755000175000017500000000000011221075700026010 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/t/TestApp-Plugin-Comments/lib/TestApp/Plugin/Comments/0000755000175000017500000000000011221075700027575 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/t/TestApp-Plugin-Comments/lib/TestApp/Plugin/Comments/View.pm0000644000175000017500000000140711155144775031066 0ustar agostiniagostiniuse strict; use warnings; package TestApp::Plugin::Comments::View; use Jifty::View::Declare -base; template 'post' => page { { title is 'New Post' } form { my $post_blog = new_action class => 'CreateBlogPost'; render_action $post_blog; form_submit label => _('Post'), submit => $post_blog; }; }; template 'view' => page { my $blog = get 'blog'; { title is $blog->title } p { _('By %1', $blog->author) }; p { $blog->body }; hr { }; render_region name => 'comments', path => '/__comment/list', arguments => { collapsed => 1, parent_class => Jifty->app_class('Model', 'BlogPost'), parent_id => $blog->id, }, ; }; 1; Jifty-Plugin-Comment-1.00/t/TestApp-Plugin-Comments/lib/TestApp/Plugin/Comments/Model/0000755000175000017500000000000011221075700030635 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/t/TestApp-Plugin-Comments/lib/TestApp/Plugin/Comments/Model/BlogPost.pm0000644000175000017500000000072211155144775032744 0ustar agostiniagostiniuse strict; use warnings; package TestApp::Plugin::Comments::Model::BlogPost; use Jifty::DBI::Schema; use constant CLASS_UUID => '21EC717C-A2D3-11DC-BDD3-A201F3F60BF3'; use TestApp::Plugin::Comments::Record schema { column title => type is 'text'; column body => type is 'text'; column author => type is 'text'; column posted => type is 'text'; }; use Jifty::Plugin::Comment::Mixin::Model::Commented; # Your model-specific methods go here. 1; Jifty-Plugin-Comment-1.00/t/TestApp-Plugin-Comments/lib/TestApp/Plugin/Comments/Dispatcher.pm0000644000175000017500000000040211155144775032234 0ustar agostiniagostiniuse strict; use warnings; package TestApp::Plugin::Comments::Dispatcher; use Jifty::Dispatcher -base; on 'view/#' => run { my $blog = TestApp::Plugin::Comments::Model::BlogPost->new; $blog->load($1); set blog => $blog; show 'view'; }; 1; Jifty-Plugin-Comment-1.00/t/00-load.t0000644000175000017500000000015511155144775017366 0ustar agostiniagostini#!/usr/bin/env perl use warnings; use strict; use Test::More tests => 1; use_ok('Jifty::Plugin::Comment'); Jifty-Plugin-Comment-1.00/Makefile.PL0000644000175000017500000000061111221075355017540 0ustar agostiniagostiniuse inc::Module::Install; name('Jifty-Plugin-Comment'); all_from('lib/Jifty/Plugin/Comment.pm'); requires('Jifty' => '0.90409'); requires('HTML::Scrubber'); requires('MIME::Base64::URLSafe'); requires('Regexp::Common'); requires('Regexp::Common::URI'); requires('Regexp::Common::Email::Address'); requires('CGI::Cookie'); auto_install(); tests('t/*.t t/*/t/*.t'); install_share; WriteAll; Jifty-Plugin-Comment-1.00/README0000644000175000017500000001135411213660404016450 0ustar agostiniagostiniNAME Jifty::Plugin::Comment - Add comments to any record SYNOPSIS Setup the config.yml Plugins: - Comment: # Set this if you want spam checking by Net::Akismet Akismet: Key: 1234567890a Url: http://example.com # Set this if you want to customize the HTML scrubbing of comments Scrubber: message: "Comments may only contain , , and tags." allow: - strong - em - a default: - 0 - '*': 0 href: !!perl/regexp: REGEXP: '^(?!(?:java)?script)' MODIFIERS: i Setup a model that has comments: package App::Model::Fooble; use Jifty::DBI::Schema; use App::Record schema { column scribble => type is 'text'; column wobble => type is 'int'; }; use Jifty::Plugin::Comment::Mixin::Model::Commented; sub allow_owner_update_delete { my $self = shift; my ($right, %args) = @_; if ($right eq 'create') { return 'allow' ;#if $self->current_user->id; } if ($right eq 'update' || $right eq 'delete') { return 'allow' if $self->current_user->id; } if ($right eq 'read') { return 'allow'; } return 'deny'; }; App::Model::FoobleComment->add_trigger( name => 'before_access', callback => \&allow_owner_update_delete); App::Model::Comment->add_trigger( name => 'before_access', callback => \&allow_owner_update_delete); Setup a view for creating, viewing, and managing the comments: # assuming $fooble here isa App::Action::UpdateFooble object template 'fooble/view' => page { my $fooble = get 'fooble'; render_action $fooble, undef, { render_mode => 'read' }; render_region name => 'fooble-comments', path => '__comment/list_and_add', defaults => { comment_upon => $fooble->record->for_commenting, initial_title => 'Re: '.substr($fooble->scribble, 0, 20).'...', }, ; }; DESCRIPTION This plugin allows you to attach comments to any model. You do this using the three steps listed in the synopsis. For variations on these steps, see the other classes that handle the individual parts. COMMENTED RECORDS To set up a commented model, you will need to do the following: 1 Add ths plugin to your project by modifying your config.yml. 1 Add the Jifty::Plugin::Comment::Mixin::Model::Commented mixin to the model or models that you want to have comments attached to. See that class for details on how it works. You may also want to examine Jifty::Plugin::Comment::Model::Comment on how to customize that class for your application. 1 Create a view that appends a comment editor to your edit form (or on a separate page or wherever you feel like comments work best in your application). You should be able to use these views from either Template::Declare or HTML::Mason templates. See Jifty::Plugin::Comment::View for additional details on what views are available. METHODS init Called during initialization. This will setup the Net::Akismet object if it is configured and available. akismet This returns an instance of Net::Akismet that is used to check to see if a new comment posted contains spam. No such checking is performed if this returns "undef", which indicates that "Net::Akismet" is unavailable, wasn't configured, or there was an error configuring it (e.g., the Akismet server was unavailable during Jifty startup). scrubber This returns an instance of HTML::Scrubber that is used to clean up HTML submitted in comments. TO DO Right now the module depends directly upon HTML::Scrubber to do the work of cleaning up the text. You might want to use something else to do this. It also provides no mechanism for customizing any other aspect of the formatting. For example, your application might want to use Markdown, or BBCode, or just turn line breaks in the BR-tags, or anything else to format the comment text. In the future, I'd like to consider something like Text::Pipe or a similar API to allow these formats to be customized more easily. SEE ALSO Net::Akismet, HTML::Scrubber AUTHOR Andrew Sterling Hanenkamp, "" COPYRIGHT AND LICENSE Copyright 2007 Boomer Consulting, Inc. All Rights Reserved. This program is free software and may be modified and distributed under the same terms as Perl itself. Jifty-Plugin-Comment-1.00/lib/0000755000175000017500000000000011221075700016330 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/lib/Jifty/0000755000175000017500000000000011221075700017415 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/lib/Jifty/Plugin/0000755000175000017500000000000011221075700020653 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/lib/Jifty/Plugin/Comment.pm0000644000175000017500000001465511221065771022635 0ustar agostiniagostiniuse strict; use warnings; package Jifty::Plugin::Comment; use base qw/ Jifty::Plugin /; our $VERSION = '1.00'; __PACKAGE__->mk_accessors( qw/ akismet scrubber scrub_message / ); use HTML::Scrubber; =head1 NAME Jifty::Plugin::Comment - Add comments to any record =head1 SYNOPSIS Setup the F Plugins: - Comment: # Set this if you want spam checking by Net::Akismet Akismet: Key: 1234567890a Url: http://example.com # Set this if you want to customize the HTML scrubbing of comments Scrubber: message: "Comments may only contain , , and tags." allow: - strong - em - a default: - 0 - '*': 0 href: !!perl/regexp: REGEXP: '^(?!(?:java)?script)' MODIFIERS: i Setup a model that has comments: package App::Model::Fooble; use Jifty::DBI::Schema; use App::Record schema { column scribble => type is 'text'; column wobble => type is 'int'; }; use Jifty::Plugin::Comment::Mixin::Model::Commented; sub allow_owner_update_delete { my $self = shift; my ($right, %args) = @_; if ($right eq 'create') { return 'allow' ;#if $self->current_user->id; } if ($right eq 'update' || $right eq 'delete') { return 'allow' if $self->current_user->id; } if ($right eq 'read') { return 'allow'; } return 'deny'; }; App::Model::FoobleComment->add_trigger( name => 'before_access', callback => \&allow_owner_update_delete); App::Model::Comment->add_trigger( name => 'before_access', callback => \&allow_owner_update_delete); Setup a view for creating, viewing, and managing the comments: # assuming $fooble here isa App::Action::UpdateFooble object template 'fooble/view' => page { my $fooble = get 'fooble'; render_action $fooble, undef, { render_mode => 'read' }; render_region name => 'fooble-comments', path => '__comment/list_and_add', defaults => { comment_upon => $fooble->record->for_commenting, initial_title => 'Re: '.substr($fooble->scribble, 0, 20).'...', }, ; }; =head1 DESCRIPTION This plugin allows you to attach comments to any model. You do this using the three steps listed in the synopsis. For variations on these steps, see the other classes that handle the individual parts. =head1 COMMENTED RECORDS To set up a commented model, you will need to do the following: =over =item 1 Add ths plugin to your project by modifying your F. =item 1 Add the L mixin to the model or models that you want to have comments attached to. See that class for details on how it works. You may also want to examine L on how to customize that class for your application. =item 1 Create a view that appends a comment editor to your edit form (or on a separate page or wherever you feel like comments work best in your application). You should be able to use these views from either L or L templates. See L for additional details on what views are available. =back =head1 METHODS =head2 init Called during initialization. This will setup the L object if it is configured and available. =cut sub init { my $self = shift; $self->_init_akismet(@_); $self->_init_scrubber(@_); } sub _init_akismet { my $self = shift; my %args = @_; # Stop now if we don't have the Akismet thing return unless defined $args{Akismet}; # Check for the Akismet options my $key = $args{Akismet}{Key}; my $url = $args{Akismet}{Url}; # Don't go forward unless we have a key and a URL configured return unless $key and $url; # Try to load Akismet first... eval "use Net::Akismet"; if ($@) { Jifty->log->error("Failed to load Net::Akismet. Your comments will not be checked for link spam and the like. $@"); return; } # Now get our object my $akismet = Net::Akismet->new( KEY => $key, URL => $url ); unless ($akismet) { Jifty->log->error("Failed to verify your Akismet key. Your comments will not be checked for link spam and the like."); return; } $self->akismet($akismet); } sub _init_scrubber { my $self = shift; my %args = @_; my $scrubber_args = $args{Scrubber}; if (not defined $scrubber_args) { $scrubber_args = { message => 'Comments may only contain , , and tags.' .' Anything else will be removed.', allow => [ qw/ strong em a / ], default => [ 0, { '*' => 0, 'href' => qr{^(?!(?:java)?script)}i } ], }; } my $scrub_message = delete $scrubber_args->{message}; $scrub_message = 'The text you have given will be cleaned up.' unless $scrub_message; $self->scrub_message($scrub_message); my $scrubber = HTML::Scrubber->new( %$scrubber_args ); $self->scrubber($scrubber); } =head2 akismet This returns an instance of L that is used to check to see if a new comment posted contains spam. No such checking is performed if this returns C, which indicates that C is unavailable, wasn't configured, or there was an error configuring it (e.g., the Akismet server was unavailable during Jifty startup). =head2 scrubber This returns an instance of L that is used to clean up HTML submitted in comments. =head1 TO DO Right now the module depends directly upon L to do the work of cleaning up the text. You might want to use something else to do this. It also provides no mechanism for customizing any other aspect of the formatting. For example, your application might want to use Markdown, or BBCode, or just turn line breaks in the BR-tags, or anything else to format the comment text. In the future, I'd like to consider something like L or a similar API to allow these formats to be customized more easily. =head1 SEE ALSO L, L =head1 AUTHOR Andrew Sterling Hanenkamp, C<< >> =head1 COPYRIGHT AND LICENSE Copyright 2007 Boomer Consulting, Inc. All Rights Reserved. This program is free software and may be modified and distributed under the same terms as Perl itself. =cut 1; Jifty-Plugin-Comment-1.00/lib/Jifty/Plugin/Comment/0000755000175000017500000000000011221075700022255 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/lib/Jifty/Plugin/Comment/Notification/0000755000175000017500000000000011221075700024703 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/lib/Jifty/Plugin/Comment/Notification/CommentNeedsModeration.pm0000644000175000017500000000632411155144775031670 0ustar agostiniagostiniuse strict; use warnings; package Jifty::Plugin::Comment::Notification::CommentNeedsModeration; use base qw/ Jifty::Notification /; __PACKAGE__->mk_accessors(qw/ comment parent /); =head1 NAME Jifty::Plugin::Comment::Notification::CommentNeedsModeration - new comments made, but not published =head1 SYNOPSIS To activate this notification, you must override the notification in your application. use strict; use warnings; package MyApp::Notification::CommentNeedsModeration; use base qw/ Jifty::Plugin::Comment::Notification::CommentNeedsModeration /; sub setup { my $self = shift; # Limit to users that have a "moderator" column set to 1 my $users = MyApp::Model::UserCollection->new; $users->limit( column => 'moderator', value => 1 ); $self->to_list(@{ $users->items_array_ref }); $self->SUPER::setup(@_); } sub url { my $self = shift; return Jifty->config->framework('Web')->{'BaseURL'} . $self->parent->permalink . '#comment-'.$self->comment->id; } 1; =head1 DESCRIPTION This notificaiton (when properly configured) is sent out to any who need to know when a comment has been created, but not published because L has marked it as spam. =head1 METHODS =head2 setup This method sets up the notification. This method should be overridden to setup L to select who will receive this message. See the L. =cut sub setup { my $self = shift; my $appname = Jifty->config->framework('ApplicationName'); my $comment = $self->comment; my $from = $comment->your_name || 'Anonymous Coward'; $from .= ' <'.$comment->email.'>' if $comment->email; $from .= ' ('.$comment->web_site.')' if $comment->web_site; my $url = $self->url; $self->subject(_("[%1] Moderate comment: %2", $appname, $comment->title)); $self->body(_(q{ The following comment has not been published. If you would like to publish it, please visit the link below and click on the "publish" link. If it has been marked as spam and should not have been you should also click on the "mark as ham" link. View Comment: %1 On Post: %2 Subject: %3 From: %4 Date: %5 %6 }, $url, $self->parent->title, $comment->title, $from, $comment->created_on->strftime('%A, %B %d, %Y @ %H:%M%P'), $comment->body )); } =head2 comment This will contain the L that has been published. =head2 parent This will contain the object that the comment has been attached to. =head2 url THis returns the URL that the message will link to. This should be overridden to provide application-specific URLs. The default implementation returns the BaseURL setting for the application. =cut sub url { my $self = shift; return Jifty->config->framework('Web')->{'BaseURL'}; } =head1 SEE ALSO L, L =head1 AUTHOR Andrew Sterling Hanenkamp, C<< >> =head1 COPYRIGHT AND LICENSE Copyright 2008 Boomer Consulting, Inc. All Rights Reserved. This program is free software and may be modified and distributed under the same terms as Perl itself. =cut 1; Jifty-Plugin-Comment-1.00/lib/Jifty/Plugin/Comment/Notification/CommentPublished.pm0000644000175000017500000000534611155144775030532 0ustar agostiniagostiniuse strict; use warnings; package Jifty::Plugin::Comment::Notification::CommentPublished; use base qw/ Jifty::Notification /; __PACKAGE__->mk_accessors(qw/ comment parent /); =head1 NAME Jifty::Plugin::Comment::Notification::CommentPublished - new comments made =head1 SYNOPSIS To activate this notification, you must override the notification in your application. use strict; use warnings; package MyApp::Notification::CommentPublished; use base qw/ Jifty::Plugin::Comment::Notification::CommentPublished /; sub setup { my $self = shift; # Send to the author of the post $self->to_list($self->parent->author); $self->SUPER::setup(@_); } sub url { my $self = shift; return Jifty->config->framework('Web')->{'BaseURL'} . $self->parent->permalink . '#comment-'.$self->comment->id; } 1; =head1 DESCRIPTION This notification (when properly configured) is sent out to any who need to know when a comment has been published. =head1 METHODS =head2 setup This method sets up the notification. This method should be overridden to setup L to select who will receive this message. See the L. =cut sub setup { my $self = shift; my $appname = Jifty->config->framework('ApplicationName'); my $comment = $self->comment; my $from = $comment->your_name || 'Anonymous Coward'; $from .= ' <'.$comment->email.'>' if $comment->email; $from .= ' ('.$comment->web_site.')' if $comment->web_site; my $url = $self->url; $self->subject(_("[%1] New comment: %2", $appname, $comment->title)); $self->body(_(" View Comment: %1 On Post: %2 Subject: %3 From: %4 Date: %5 %6 ", $url, $self->parent->title, $comment->title, $from, $comment->created_on->strftime('%A, %B %d, %Y @ %H:%M%P'), $comment->body )); } =head2 comment This will contain the L that has been published. =head2 parent This will contain the object that the comment has been attached to. =head2 url This returns the URL that the message will link to. This should be overridden to provide application-specific URLs. The default implementation returns the BaseURL setting for the application. =cut sub url { my $self = shift; return Jifty->config->framework('Web')->{'BaseURL'}; } =head1 SEE ALSO L, L =head1 AUTHOR Andrew Sterling Hanenkamp, C<< >> =head1 COPYRIGHT AND LICENSE Copyright 2008 Boomer Consulting, Inc. All Rights Reserved. This program is free software and may be modified and distributed under the same terms as Perl itself. =cut 1; Jifty-Plugin-Comment-1.00/lib/Jifty/Plugin/Comment/View.pm0000644000175000017500000002153511155144775023552 0ustar agostiniagostiniuse strict; use warnings; package Jifty::Plugin::Comment::View; use Jifty::View::Declare -base; use Jifty::DateTime; =head1 NAME Jifty::Plugin::Comment::View - the templates for the comment plugin =head1 DESCRIPTION =head1 METHODS =head2 scrub_html This is a utility used internally for cleaning up the input which might come from a malicious source. =cut sub scrub_html($) { my $text = shift; my $plugin = Jifty->find_plugin('Jifty::Plugin::Comment'); return $plugin->scrubber->scrub($text); } =head1 TEMPLATES =head2 __comment/view This displays a single comment in a page. =cut template '__comment/view' => page { my $comment = get 'comment'; { title is _( $comment->title ); } div { { class is 'column span-21 first' } render_region name => 'comment-'.$comment->id, path => '/__comment/display', defaults => { id => $comment->id, top => 1, }, ; }; show '/advertisement'; }; =head2 __comment/display Display a comment in a page region. =cut template '__comment/display' => sub { my $comment = get 'comment'; my $top = get 'top'; my $plugin = Jifty->find_plugin('Jifty::Plugin::Comment'); div { my $class = 'comment'; $class .= $comment->status eq 'ham' ? ' ham' : ' spam' if Jifty->web->current_user->id; $class .= $comment->published ? ' published' : ' unpublished'; { class is $class } div { { class is 'actions' } if (Jifty->web->current_user->id) { for my $status (qw( ham spam )) { if ($comment->status ne $status && $plugin->akismet) { hyperlink label => _('mark as %1', $status), onclick => { args => { update_status => $status, }, }, ; } } for my $published (0, 1) { if ($comment->published ne $published) { hyperlink label => $published ? _('publish') : _('unpublish'), onclick => { args => { update_published => $published, }, }, ; } } } ''; }; unless ($top) { if ($comment->status eq 'ham' && $comment->published) { h5 { a { attr { name => 'comment-'.$comment->id }; $comment->title }; }; }; }; div { { class is 'comment-info' } my $poster = $comment->your_name || 'Anonymous Coward'; $poster = Jifty->web->escape($poster); $poster = qq{$poster} if $comment->web_site; my $created_on = $comment->created_on; p { outs_raw _('By %1 %2', $poster, $created_on->strftime('%A, %B %d, %Y @ %H:%M%P') ) }; }; if ($comment->status eq 'ham' && $comment->published) { div { outs_raw scrub_html($comment->body); }; }; }; }; =head2 __comment/add This presents the form for adding a new comment. =cut template '__comment/add' => sub { my $collapsed = get 'collapsed'; my $region = get 'region'; if ($collapsed) { p { hyperlink label => _('Add a comment'), onclick => { refresh_self => 1, args => { collapsed => 0 }, }, ; }; } else { my $action = get 'action'; if (get 'preview') { div { { class is 'preview comment' } h5 { $action->argument_value('title') || 'No Title' }; div { { class is 'comment-info' } my $poster = $action->argument_value('your_name') || 'Anonymous Coward'; $poster = Jifty->web->escape($poster); $poster = qq{$poster} if $action->argument_value('web_site'); my $created_on = Jifty::DateTime->now; p { outs_raw _('By %1 %2', $poster, $created_on->strftime('%A, %B %d, %Y @ %H:%M%P') ) }; }; div { my $body = $action->argument_value('body') || 'No Body'; outs_raw scrub_html($body); }; }; }; div { { class is 'edit comment' } form { render_action $action; div { { class is 'submit-buttons' } form_submit label => _('Preview'), name => 'op', class => 'first', onclick => { refresh_self => 1, submit => { action => $action, arguments => { submit => 0 }, }, args => { preview => 1 }, }, ; if (get 'preview') { form_submit label => _('Submit'), onclick => [ { refresh_self => 1, submit => { action => $action, arguments => { submit => 1 }, }, args => { preview => 0, collapsed => 1, }, }, { element => $region->parent->get_element('div.list'), append => '/__comment/display', args => { id => { result => $action, name => 'id' }, top => 0, }, }, ], ; } }; }; }; } }; =head2 __comment/list This presents a list of comments attached to a particular comment and the form for adding one more. =cut template '__comment/list' => sub { my $parent = get 'parent'; my $title = get 'initial_title'; my $comments = $parent->comments; if (!Jifty->web->current_user->id) { $comments->limit( column => 'status', value => 'ham', ); } div { { class is 'list' } if ($comments->count) { while (my $comment = $comments->next) { render_region name => 'comment-'.$comment->id, path => '/__comment/display', defaults => { id => $comment->id, top => 0, }, ; } } else { p { { class is 'none' } _('No one has made a comment yet.'); }; } }; unless (get 'no_add') { render_region name => 'comment-add-'.$parent->id, path => '/__comment/add', defaults => { parent_class => ref $parent, parent_id => $parent->id, collapsed => 1, title => $title, }, ; } }; =head1 SEE ALSO L =head1 AUTHOR Andrew Sterling Hanenkamp, C<< >> =head1 COPYRIGHT AND LICENSE Copyright 2008 Boomer Consulting, Inc. All Rights Reserved. This program is free software and may be modified and distributed under the same terms as Perl itself. =cut 1; Jifty-Plugin-Comment-1.00/lib/Jifty/Plugin/Comment/Model/0000755000175000017500000000000011221075700023315 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/lib/Jifty/Plugin/Comment/Model/Comment.pm0000644000175000017500000002061011155144775025273 0ustar agostiniagostiniuse strict; use warnings; package Jifty::Plugin::Comment::Model::Comment; use Jifty::DBI::Schema; use constant CLASS_UUID => '7B703CCA-544E-11DC-9227-2E96D84604BE'; =head1 NAME Jifty::Plugin::Comment::Model::Comment - comments attached to anything =head1 SYNOPSIS # to customize... package App::Model::Comment; use base qw/ Jifty::Plugin::Comment::Model::Comment /; use Jifty::DBI::Schema; use App::Record schema { # Add a reference to the current user that creates this comment column by_user => references App::Model::User, ; }; # make it so that any logged user can comment, but anyone can view, except # that we don't really want everyone seeing all those personal bits... sub current_user_can { my $self = shift; my ($right, %args) = @_; if ($right eq 'create') { return 1 if $self->current_user->id; } if ($right eq 'read') { return $self->published unless $args{column} =~ /^ (?: email | status | ip_addr | http_refer | http_user_agent ) $/x; } # otherwise only superuser gets in return $self->SUPER::current_user_can(@_); } =head1 DESCRIPTION This model is the repository for all comments in your application, if you use the L plugin. =head1 SCHEMA =head2 title This is the title of the comment. =head2 body This is the body of the comment. =head2 created_on This is the timestamp of when the comment was created. =head2 your_name This is the name the author of the comment has claimed. =head2 web_site This is the name of the web site the author claims as her own. =head2 email This is the email address the author is claiming. =head2 published This is a boolean flag indicating whether the comment should be shown or not when viewed. =head2 status This is a flag containing one of two values: "spam" or "ham". It indicates whether the comment has been evaluated as spam or not by L. =head2 ip_addr This is the IP address of the remote client of the author that made the comment. =head2 http_referer This is the HTTP referer that was sent by the browser when the author made the comment. =head2 http_user_agent This is the HTTP user agent that was sent by the browser when the author made the comment. =cut use Jifty::Record schema { column title => type is 'text', label is 'Title', is mandatory, ; column body => type is 'text', label is 'Body', is mandatory, render as 'Textarea', ; column created_on => type is 'timestamp', label is 'Created on', filters are qw/ Jifty::DBI::Filter::DateTime /, ; column your_name => type is 'text', label is 'Your name', is mandatory, ; column web_site => type is 'text', label is 'Web site', ; column email => type is 'text', label is 'Email address', ; column published => type is 'boolean', label is 'Published?', is mandatory, default is 1, ; column status => type is 'varchar(4)', label is 'Status', valid_values are qw/ spam ham /, default is 'ham', ; column ip_addr => type is 'text', label is 'IP Address', ; column http_referer => type is 'text', label is 'HTTP Referer', ; column http_user_agent => type is 'text', label is 'HTTP User Agent', ; }; use DateTime; use HTML::Scrubber; =head1 METHODS =head2 table Returns the database table name for the comments table. =cut sub table { 'comment_comments' } =head2 before_create It is assumed that your comments will be made available for create with very little restriction. This trigger is used to perform aggressive cleanup on the data stored and will attempt to check to see if the comment is spam by using L. =cut sub before_create { my $self = shift; my $args = shift; # Clean up stuff added by Jifty::Plugin::Comment::Action::CreateComment delete $args->{parent_class}; delete $args->{parent_id}; my $plugin = Jifty->find_plugin('Jifty::Plugin::Comment'); my $scrubber = $plugin->scrubber; # Store safe fields $args->{'title'} = Jifty->web->escape($args->{'title'}); $args->{'your_name'} = Jifty->web->escape($args->{'your_name'}); $args->{'web_site'} = Jifty->web->escape($args->{'web_site'}); $args->{'email'} = Jifty->web->escape($args->{'email'}); $args->{'body'} = $scrubber->scrub($args->{'body'}); $args->{'created_on'} = DateTime->now; $args->{'ip_addr'} = $ENV{'REMOTE_ADDR'}; $args->{'http_user_agent'} = $ENV{'HTTP_USER_AGENT'}; $args->{'http_referer'} = $ENV{'HTTP_REFERER'}; # Prep for Akismet check or stop my $akismet = $plugin->akismet or return 1; # Check to see if it's classified as spam my $verdict = $akismet->check( USER_IP => $args->{'ip_addr'}, USER_AGENT => $args->{'http_user_agent'}, REFERER => $args->{'http_referer'}, COMMENT_CONTENT => $args->{'title'}."\n\n".$args->{'body'}, COMMENT_AUTHOR => $args->{'your_name'}, COMMENT_AUTHOR_EMAIL => $args->{'email'}, COMMENT_AUTHOR_URL => $args->{'web_site'}, ); # I have no idea what it is... mark it spam just in case... # TODO the default no verdict action should configurable if (!$verdict) { $args->{published} = 0; $args->{status} = 'spam'; warn "Failed to determine whether new comment is spam or not."; return 1; } # Naughty, naughty... mark as spam if ($verdict eq 'true') { warn "A new comment is detected as spam."; $args->{published} = 0; $args->{status} = 'spam'; return 1; } # Excellent, post that ham else { $args->{published} = 1; $args->{status} = 'ham'; return 1; } } =head2 before_set_status This trigger is called when changing the status of the message. If L is in use, this trigger will notify Akismet that this message is being marked as spam or as ham, depending upon the new value. =cut sub before_set_status { my $self = shift; my $args = shift; my $plugin = Jifty->find_plugin('Jifty::Plugin::Comment'); my $akismet = $plugin->akismet or return 1; my %akismet_report = ( USER_IP => $self->ip_addr, USER_AGENT => $self->http_user_agent, REFERER => $self->http_referer, COMMENT_CONTENT => $self->title."\n\n".$self->body, COMMENT_AUTHOR => $self->your_name, COMMENT_AUTHOR_EMAIL => $self->email, COMMENT_AUTHOR_URL => $self->web_site, ); if ($self->status eq 'spam' && $args->{value} eq 'ham') { if ($akismet->ham( %akismet_report )) { Jifty->log->info("Reported that comment ".$self->id." is HAM to Akismet."); } else { # Not the end of the world, just that Akismet doesn't know... Jifty->log->info("FAILED to report that comment ".$self->id." is HAM to Akismet."); } } elsif ($self->status eq 'ham' && $args->{value} eq 'spam') { if ($akismet->spam( %akismet_report )) { Jifty->log->info("Reported that comment ".$self->id." is SPAM to Akismet."); } else { # Not the end of the world, just that Akismet doesn't know... Jifty->log->info("FAILED to report that comment ".$self->id." is SPAM to Akismet."); } } return 1; } =head2 current_user_can This method is not actually implemented by this class, but you will either want to implementt this method in your application or add a C trigger that grants access. Otherwise, your comments won't be very interesting to anyone but a superuser. See the L for a recommended implementation. =head1 AUTHOR Andrew Sterling Hanenkamp C<< >> =head1 COPYRIGHT AND LICENSE Copyright 2007 Boomer Consulting, Inc. All Rights Reserved. This program is free software and may be modified and distributed under the same terms as Perl itself. =cut 1; Jifty-Plugin-Comment-1.00/lib/Jifty/Plugin/Comment/Dispatcher.pm0000644000175000017500000000665011155144775024727 0ustar agostiniagostiniuse strict; use warnings; package Jifty::Plugin::Comment::Dispatcher; use Jifty::Dispatcher -base; use Scalar::Util qw/ blessed looks_like_number /; =head1 NAME Jifty::Plugin::Comment::Dispatcher - dispatcher for the comment plugin =head1 DESCRIPTION Handles the dispatch of the C<__comment> paths used by this plugin. =head1 METHODS =head2 setup_parent_object Called internally by the dispatcher rules to create the "parent" dispatcher argument from "comment_upon" or "parent_class" and "parent_id". =cut sub setup_parent_object() { my $parent; unless (get 'parent') { my ($parent_class, $parent_id) = @_; if (get 'comment_upon') { my $comment_upon = get 'comment_upon'; ($parent_class, $parent_id) = $comment_upon =~ /^([\w:]+)-(\d)$/; } else { $parent_class = get 'parent_class'; $parent_id = get 'parent_id'; } abort 404 unless $parent_class and $parent_id; abort 500 unless $parent_class =~ /^[\w:]+$/; abort 500 unless eval { $parent_class->isa('Jifty::Record') }; abort 500 unless looks_like_number($parent_id); $parent = $parent_class->new; $parent->load($parent_id); set parent => $parent; } else { $parent = get 'parent'; } abort 500 unless eval { $parent->isa('Jifty::Record') }; abort 500 unless eval { $parent->can('comments') }; abort 404 unless eval { $parent->id }; } =head1 RULES =head2 __comment/list Sets up the "parent" argument for the list template. =cut on '__comment/list' => run { setup_parent_object(); }; =head2 __comment/add Set up the "parent" argument for the add template and set the "CreateComment" action into the "action" argument. =cut on '__comment/add' => run { setup_parent_object(); my $parent = get 'parent'; my $action = Jifty->web->new_action( class => 'CreateComment', moniker => 'add-comment-'.$parent->id, arguments => { parent_class => blessed $parent, parent_id => $parent->id, }, ); $action->argument_value( title => get('title') || '') unless $action->argument_value('title'); set action => $action; show '/__comment/add'; }; =head2 __comment/display Sets up the "comment" argument and will update the status and published values of the comment if "update_status" or "update_published" are set, respectively. =cut on '__comment/display' => run { my $id = get 'id'; my $comment = Jifty->app_class('Model', 'Comment')->new; $comment->load($id); if (get 'update_status') { my $action = $comment->as_update_action; $action->argument_value( status => get 'update_status' ); $action->run; Jifty->web->response->result( $action->moniker => $action->result ); } if (defined get 'update_published') { my $action = $comment->as_update_action; $action->argument_value( published => get 'update_published' ); $action->run; Jifty->web->response->result( $action->moniker => $action->result ); } set comment => $comment; }; =head1 SEE ALSO L =head1 AUTHOR Andrew Sterling Hanenkamp, C<< >> =head1 COPYRIGHT AND LICENSE Copyright 2008 Boomer Consulting, Inc. All Rights Reserved. This program is free software and may be modified and distributed under the same terms as Perl itself. =cut 1; Jifty-Plugin-Comment-1.00/lib/Jifty/Plugin/Comment/Action/0000755000175000017500000000000011221075700023472 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/lib/Jifty/Plugin/Comment/Action/CreateComment.pm0000644000175000017500000002514411155144775026603 0ustar agostiniagostiniuse strict; use warnings; package Jifty::Plugin::Comment::Action::CreateComment; use base qw/ Jifty::Action::Record::Create /; =head1 NAME Jifty::Plugin::Comment::Action::CreateComment - custom CreateComment that attaches the comment to the parent =head1 DESCRIPTION This is a specialized create action that attaches the comment to the parent object. =head1 SCHEMA =head2 parent_class This is the parent model class. This class must use the L mixin. =head2 parent_id This is the ID of the object to attach the comment to. =head2 title This is the title the author of the comment has given it. =head2 your_name This is the name of the author of the comment. =head2 web_site This is the (optional) web site of the author of the comment. =head2 email This is the (optional) email address of the author of the comment. =head2 body This is the comment message. =head2 published This is true if the comment should be published or false if it is only visible to moderators. =head2 created_on This is the timestamp of the comment's creation. =head2 status This is string with either the value "spam" for a message that has been flagged as spam or "ham" for a message that is not spam. =head2 http_referer The referer claimed by the client. =head2 http_user_agent The user agent claimed by the client. =head2 ip_addr The IP address of the client. =cut use Jifty::Param::Schema; use Jifty::Action::Record::Create schema { param parent_class => type is 'hidden', is mandatory, order is 1, ; param parent_id => type is 'hidden', is mandatory, order is 2, ; param title => label is 'Title', is mandatory, ajax validates, is focus, order is 3, ; param your_name => label is 'Your name', default is defer { from_cookie(0) }, # TODO This is canonicalizing at the wrong time, I need another way. # ajax canonicalizes, order is 4, ; param web_site => label is 'Web site', default is defer { from_cookie(1) }, ajax validates, order is 5, ; param email => label is 'Email address', default is defer { from_cookie(2) }, ajax validates, order is 6, ; # param remember_me => # type is 'checkbox', # label is 'Remember me', # hints is 'Check this box for this site to store a cookie on your browser that is used to automatically fill in your name, email address, and web site the next time you make a comment.', # ; param body => type is 'textarea', label is 'Comment', is mandatory, ajax validates, order is 7, ; param published => type is 'unrendered', render as 'unrendered', mandatory is 0, ; param created_on => type is 'unrendered', render as 'unrendered', ; param status => type is 'unrendered', render as 'unrendered', ; param http_referer => type is 'unrendered', render as 'unrendered', ; param http_user_agent => type is 'unrendered', render as 'unrendered', ; param ip_addr => type is 'unrendered', render as 'unrendered', ; }; use CGI::Cookie; use MIME::Base64::URLSafe; #use Contentment::Notification::CommentPublished; #use Contentment::Notification::CommentNeedsModeration; #use Contentment::Util; use Regexp::Common qw/ Email::Address URI /; =head1 METHODS =head2 record_class Returns the application's comment class. =cut sub record_class { Jifty->app_class('Model', 'Comment') } =head2 parent This converts the "parent_id" and "parent_class" arguments into an object. =cut sub parent { my $self = shift; my $parent_class = $self->argument_value('parent_class'); my $parent_id = $self->argument_value('parent_id'); my $parent = $parent_class->new; $parent->load($parent_id); return $parent; } =head2 take_action Performs the work of attaching the comment to the parent object. =cut sub take_action { my $self = shift; if ($self->argument_value('submit')) { my $your_name = urlsafe_b64encode($self->argument_value('your_name')); my $web_site = urlsafe_b64encode($self->argument_value('web_site')); my $email = urlsafe_b64encode( $self->argument_value('email')); my $cookie = CGI::Cookie->new( -path => '/', -name => 'COMMENT_REMEMBORY', -value => join('.', $your_name, $web_site, $email), -expires => '+3M', ); Jifty->web->response->add_header( 'Set-Cookie' => $cookie->as_string ); $self->SUPER::take_action(@_); # On success, create the extra link record if ($self->result->success) { my $parent_class = $self->argument_value('parent_class'); my $link = $parent_class->comment_record_class->new; $link->create( commented_upon => $self->parent, the_comment => $self->record, ); # Link failed? unless ($link->id) { $self->log->error("Failed to create the comment and linking record required for comment #@{[$self->record->id]} and parent record class @{[$self->argument_value('parent_class')]} #@{[$self->argument_value('parent_id')]}"); $self->result->message(undef); $self->result->error("Failed to create the comment and linking record required. This error has been logged."); } # Link succeeded! This comment's training is complete! else { # Send notification by email to the site owners my $notification_class = $self->record->published ? 'CommentPublished' : 'CommentNeedsModeration'; $notification_class = Jifty->app_class('Notification', $notification_class); my $notification = $notification_class->new( comment => $self->record, parent => $self->parent, ); $notification->send; } } } else { $self->result->message(qq{Previewing your comment titled "@{[$self->argument_value('title') || 'Untitled']}"}); $self->result->failure(1); } } =head2 report_success Reports success or the need for moderation of the message. =cut sub report_success { my $self = shift; $self->result->message(_("Your comment has been added. If it does not immediately appear, it may have been flagged for moderation and should appear shortly.")); } =head2 fetch_comment_cookie Creating a comment this way causes a cookie named "COMMENT_REMEMBORY" to be stored on the client to remember the client's name, email, and web site choice for the next comment. =cut my $comment_cookie; sub fetch_comment_cookie { return $comment_cookie if defined $comment_cookie; my %cookies = CGI::Cookie->fetch; $comment_cookie = $cookies{'COMMENT_REMEMBORY'} ? $cookies{'COMMENT_REMEMBORY'} : ''; return $comment_cookie; } =head2 from_cookie Loads the name, email, and web site from the stored cookie. =cut sub from_cookie { my $pos = shift; if (Jifty->web->current_user->id) { return Jifty->web->escape( $pos == 0 ? Jifty->web->current_user->user_object->name : $pos == 1 ? Jifty->config->framework('Web')->{'BaseURL'} : $pos == 2 ? Jifty->web->current_user->user_object->email : '' ); } elsif (my $value = eval { fetch_comment_cookie()->value }) { my @fields = split /\./, $value; if (defined $fields[ $pos ]) { return Jifty->web->escape(urlsafe_b64decode($fields[ $pos ])); } else { return ''; } } else { return ''; } } =head2 validate_title Make sure a title is set. =cut sub validate_title { my $self = shift; my $title = shift; if (!$title || $title =~ /^\s*$/) { return $self->validation_error(title => 'You must give a title.'); } return $self->validation_ok('title'); } #sub canonicalize_your_name { # my $self = shift; # my $your_name = shift; # # if (!$your_name || $your_name =~ /^\s*$/ || $your_name =~ /\banonymous\b/i) { # $self->canonicalization_note( your_name => 'Afraid to stand behind your words? Any malicious or evil comments by an Anonymous Coward (or anyone) will be unpublished.' ); # return 'Anonymous Coward'; # } # # return $your_name; #} =head2 validate_web_site Make sure the web site given is valid. =cut sub validate_web_site { my $self = shift; my $web_site = shift; if (!$web_site || $web_site =~ /^\s*$/) { return $self->validation_ok('web_site'); } unless ($web_site =~ /^$RE{URI}{HTTP}$/) { return $self->validation_error( web_site => 'This does not look like a proper URL. Make sure it starts with http:// or https://' ); } return $self->validation_ok('web_site'); } =head2 validate_email Make sure the email given is valid. =cut sub validate_email { my $self = shift; my $email = shift; if (!$email || $email =~ /^\s*$/) { return $self->validation_ok('email'); } unless ($email =~ /^$RE{Email}{Address}$/) { return $self->validation_error( email => 'This does not look like a proper e-mail address.', ); } return $self->validation_ok('email'); } =head2 validate_body Checks to see if the scrubbed HTML is the same as the given HTML to see if it will be changed on save and reports that to the client. =cut sub validate_body { my $self = shift; my $body = shift; if (!$body || $body =~ /^\s*$/) { return $self->validation_error(body => 'You must type a comment.'); } my $plugin = Jifty->find_plugin('Jifty::Plugin::Comment'); my $scrubber = $plugin->scrubber; my $message = $plugin->scrub_message; my $clean_body = $scrubber->scrub($body); if ($clean_body ne $body) { return $self->validation_warning(body => Jifty->web->escape($message)); } return $self->validation_ok('body'); } =head1 AUTHOR Andrew Sterling Hanenkamp, C<< >> =head1 COPYRIGHT AND LICENSE Copyright 2008 Boomer Consulting, Inc. All Rights Reserved. This program is free software and may be modified and distributed under the same terms as Perl itself. =cut 1; Jifty-Plugin-Comment-1.00/lib/Jifty/Plugin/Comment/Mixin/0000755000175000017500000000000011221075700023341 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/lib/Jifty/Plugin/Comment/Mixin/Model/0000755000175000017500000000000011221075700024401 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/lib/Jifty/Plugin/Comment/Mixin/Model/Commented.pm0000644000175000017500000001037111155144775026673 0ustar agostiniagostiniuse strict; use warnings; package Jifty::Plugin::Comment::Mixin::Model::Commented; use base qw/ Jifty::DBI::Record::Plugin /; our @EXPORT = qw( comments comment_record_class for_commenting ); use Scalar::Util qw/ blessed /; use Jifty::DBI::Schema; use Jifty::Record schema { }; =head1 NAME Jifty::Plugin::Comment::Mixin::Model::Commented - add comments to a model =head1 SYNOPSIS package App::Model::Fooble; use Jifty::DBI::Schema; use App::Record schema { column scribble => type is 'text'; column wobble => type is 'int'; }; use Jifty::Plugin::Comment::Mixin::Model::Commented; =head1 DESCRIPTION Add this mixin to a model if you'd like to attach comments to it. Comments can be used to allow users of your system to comment upon and discuss the record to which they are attached. =head1 METHODS =head2 import This method performs some rather devious magic to make everything work easily. It automatically generates an additional model for your application. This model will look something like this: use strict; use warnings; package App::Model::FoobleComment; use Jifty::DBI::Schema; use Jifty::Record schema { column commented_upon => references App::Model::Fooble, label is 'Commented upon', is mandatory, is immutable, ; column the_comment => references App::Model::Comment, label is 'Comment', is mandatory, is immutable, is distinct, ; }; App::Model::FoobleComment->add_trigger( before_access => sub { my $self = shift; my ($right, %args) = @_; if ($right eq 'create') { return 'allow' if $self->current_user->id; } if ($right eq 'read') { return 'allow'; } return $self->App::Model::FoobleComment::current_user_can(@_); }); You will need to define an C trigger for this class if you want it to be useful. =cut sub import { my $my_class = caller; my $comment_class = $my_class.'Comment'; my $app_class = Jifty->app_class; eval " use strict; use warnings; package ${comment_class}; use Jifty::DBI::Schema; use Jifty::Record schema { column commented_upon => references ${my_class}, label is 'Commented upon', is mandatory, is immutable, ; column the_comment => references ${app_class}::Model::Comment, label is 'Comment', is mandatory, is immutable, is distinct, ; }; 1; "; die "Failed to create comment link model ${comment_class}: $@" if $@; Jifty->class_loader->_require_model_related_classes($comment_class); my $comment_filename = $comment_class; $comment_filename =~ s{::}{/}g; $comment_filename .= '.pm'; $INC{ $comment_filename } = 'autogenerated'; goto &Jifty::DBI::Record::Plugin::import; } =head2 for_commenting Returns a value to be used with the comment views. It's basically just a string identifying the class name and ID of the record. =cut sub for_commenting { my $self = shift; return blessed($self) . '-' . $self->id; } =head2 comments Returns a collection of L objects that have been attached to the current record. (Actually, it returns the a collection of the local application class, e.g. C.) =cut sub comments { my $self = shift; my $comments = Jifty->app_class('Model', 'CommentCollection')->new; my $link_alias = $comments->join( column1 => 'id', table2 => $self->comment_record_class->table, column2 => 'the_comment', ); $comments->limit( alias => $link_alias, column => 'commented_upon', value => $self->id, ); return $comments; } =head2 comment_record_class This is the name of the linking class that was created during L. =cut sub comment_record_class { my $self = shift; return (ref $self || $self).'Comment'; } =head1 AUTHOR Andrew Sterling Hanenkamp C<< >> =head1 COPYRIGHT AND LICENSE Copyright 2007 Boomer Consulting, Inc. All Rights Reserved. This program is free software and may be modified and distributed under the same terms as Perl itself. =cut 1; Jifty-Plugin-Comment-1.00/MANIFEST0000644000175000017500000000225511221075632016723 0ustar agostiniagostiniChanges inc/Module/AutoInstall.pm inc/Module/Install.pm inc/Module/Install/AutoInstall.pm inc/Module/Install/Base.pm inc/Module/Install/Can.pm inc/Module/Install/Fetch.pm inc/Module/Install/Include.pm inc/Module/Install/Makefile.pm inc/Module/Install/Metadata.pm inc/Module/Install/Share.pm inc/Module/Install/Win32.pm inc/Module/Install/WriteAll.pm lib/Jifty/Plugin/Comment.pm lib/Jifty/Plugin/Comment/Action/CreateComment.pm lib/Jifty/Plugin/Comment/Dispatcher.pm lib/Jifty/Plugin/Comment/Mixin/Model/Commented.pm lib/Jifty/Plugin/Comment/Model/Comment.pm lib/Jifty/Plugin/Comment/Notification/CommentNeedsModeration.pm lib/Jifty/Plugin/Comment/Notification/CommentPublished.pm lib/Jifty/Plugin/Comment/View.pm Makefile.PL MANIFEST This list of files META.yml README share/po/fr.po share/po/jifty_plugin_comment.pot t/00-load.t t/TestApp-Plugin-Comments/bin/jifty t/TestApp-Plugin-Comments/etc/config.yml t/TestApp-Plugin-Comments/lib/TestApp/Plugin/Comments/Dispatcher.pm t/TestApp-Plugin-Comments/lib/TestApp/Plugin/Comments/Model/BlogPost.pm t/TestApp-Plugin-Comments/lib/TestApp/Plugin/Comments/View.pm t/TestApp-Plugin-Comments/Makefile.PL t/TestApp-Plugin-Comments/t/00-model-BlogPost.t Jifty-Plugin-Comment-1.00/META.yml0000644000175000017500000000122411221075504017034 0ustar agostiniagostini--- abstract: 'Add comments to any record' author: - 'Andrew Sterling Hanenkamp, C<< >>' build_requires: ExtUtils::MakeMaker: 6.11 distribution_type: module generated_by: 'Module::Install version 0.76' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Jifty-Plugin-Comment no_index: directory: - share - share - inc - t requires: CGI::Cookie: 0 HTML::Scrubber: 0 Jifty: 0.90409 MIME::Base64::URLSafe: 0 Regexp::Common: 0 Regexp::Common::Email::Address: 0 Regexp::Common::URI: 0 resources: license: http://dev.perl.org/licenses/ version: 1.00 Jifty-Plugin-Comment-1.00/inc/0000755000175000017500000000000011221075700016333 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/inc/Module/0000755000175000017500000000000011221075700017560 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/inc/Module/Install.pm0000644000175000017500000002100711221075503021525 0ustar agostiniagostini#line 1 package Module::Install; # For any maintainers: # The load order for Module::Install is a bit magic. # It goes something like this... # # IF ( host has Module::Install installed, creating author mode ) { # 1. Makefile.PL calls "use inc::Module::Install" # 2. $INC{inc/Module/Install.pm} set to installed version of inc::Module::Install # 3. The installed version of inc::Module::Install loads # 4. inc::Module::Install calls "require Module::Install" # 5. The ./inc/ version of Module::Install loads # } ELSE { # 1. Makefile.PL calls "use inc::Module::Install" # 2. $INC{inc/Module/Install.pm} set to ./inc/ version of Module::Install # 3. The ./inc/ version of Module::Install loads # } BEGIN { require 5.004; } use strict 'vars'; use vars qw{$VERSION}; BEGIN { # All Module::Install core packages now require synchronised versions. # This will be used to ensure we don't accidentally load old or # different versions of modules. # This is not enforced yet, but will be some time in the next few # releases once we can make sure it won't clash with custom # Module::Install extensions. $VERSION = '0.76'; *inc::Module::Install::VERSION = *VERSION; @inc::Module::Install::ISA = __PACKAGE__; } # Whether or not inc::Module::Install is actually loaded, the # $INC{inc/Module/Install.pm} is what will still get set as long as # the caller loaded module this in the documented manner. # If not set, the caller may NOT have loaded the bundled version, and thus # they may not have a MI version that works with the Makefile.PL. This would # result in false errors or unexpected behaviour. And we don't want that. my $file = join( '/', 'inc', split /::/, __PACKAGE__ ) . '.pm'; unless ( $INC{$file} ) { die <<"END_DIE" } Please invoke ${\__PACKAGE__} with: use inc::${\__PACKAGE__}; not: use ${\__PACKAGE__}; END_DIE # If the script that is loading Module::Install is from the future, # then make will detect this and cause it to re-run over and over # again. This is bad. Rather than taking action to touch it (which # is unreliable on some platforms and requires write permissions) # for now we should catch this and refuse to run. if ( -f $0 and (stat($0))[9] > time ) { die <<"END_DIE" } Your installer $0 has a modification time in the future. This is known to create infinite loops in make. Please correct this, then run $0 again. END_DIE # Build.PL was formerly supported, but no longer is due to excessive # difficulty in implementing every single feature twice. if ( $0 =~ /Build.PL$/i ) { die <<"END_DIE" } Module::Install no longer supports Build.PL. It was impossible to maintain duel backends, and has been deprecated. Please remove all Build.PL files and only use the Makefile.PL installer. END_DIE # To save some more typing in Module::Install installers, every... # use inc::Module::Install # ...also acts as an implicit use strict. $^H |= strict::bits(qw(refs subs vars)); use Cwd (); use File::Find (); use File::Path (); use FindBin; sub autoload { my $self = shift; my $who = $self->_caller; my $cwd = Cwd::cwd(); my $sym = "${who}::AUTOLOAD"; $sym->{$cwd} = sub { my $pwd = Cwd::cwd(); if ( my $code = $sym->{$pwd} ) { # delegate back to parent dirs goto &$code unless $cwd eq $pwd; } $$sym =~ /([^:]+)$/ or die "Cannot autoload $who - $sym"; unshift @_, ( $self, $1 ); goto &{$self->can('call')} unless uc($1) eq $1; }; } sub import { my $class = shift; my $self = $class->new(@_); my $who = $self->_caller; unless ( -f $self->{file} ) { require "$self->{path}/$self->{dispatch}.pm"; File::Path::mkpath("$self->{prefix}/$self->{author}"); $self->{admin} = "$self->{name}::$self->{dispatch}"->new( _top => $self ); $self->{admin}->init; @_ = ($class, _self => $self); goto &{"$self->{name}::import"}; } *{"${who}::AUTOLOAD"} = $self->autoload; $self->preload; # Unregister loader and worker packages so subdirs can use them again delete $INC{"$self->{file}"}; delete $INC{"$self->{path}.pm"}; return 1; } sub preload { my $self = shift; unless ( $self->{extensions} ) { $self->load_extensions( "$self->{prefix}/$self->{path}", $self ); } my @exts = @{$self->{extensions}}; unless ( @exts ) { my $admin = $self->{admin}; @exts = $admin->load_all_extensions; } my %seen; foreach my $obj ( @exts ) { while (my ($method, $glob) = each %{ref($obj) . '::'}) { next unless $obj->can($method); next if $method =~ /^_/; next if $method eq uc($method); $seen{$method}++; } } my $who = $self->_caller; foreach my $name ( sort keys %seen ) { *{"${who}::$name"} = sub { ${"${who}::AUTOLOAD"} = "${who}::$name"; goto &{"${who}::AUTOLOAD"}; }; } } sub new { my ($class, %args) = @_; # ignore the prefix on extension modules built from top level. my $base_path = Cwd::abs_path($FindBin::Bin); unless ( Cwd::abs_path(Cwd::cwd()) eq $base_path ) { delete $args{prefix}; } return $args{_self} if $args{_self}; $args{dispatch} ||= 'Admin'; $args{prefix} ||= 'inc'; $args{author} ||= ($^O eq 'VMS' ? '_author' : '.author'); $args{bundle} ||= 'inc/BUNDLES'; $args{base} ||= $base_path; $class =~ s/^\Q$args{prefix}\E:://; $args{name} ||= $class; $args{version} ||= $class->VERSION; unless ( $args{path} ) { $args{path} = $args{name}; $args{path} =~ s!::!/!g; } $args{file} ||= "$args{base}/$args{prefix}/$args{path}.pm"; $args{wrote} = 0; bless( \%args, $class ); } sub call { my ($self, $method) = @_; my $obj = $self->load($method) or return; splice(@_, 0, 2, $obj); goto &{$obj->can($method)}; } sub load { my ($self, $method) = @_; $self->load_extensions( "$self->{prefix}/$self->{path}", $self ) unless $self->{extensions}; foreach my $obj (@{$self->{extensions}}) { return $obj if $obj->can($method); } my $admin = $self->{admin} or die <<"END_DIE"; The '$method' method does not exist in the '$self->{prefix}' path! Please remove the '$self->{prefix}' directory and run $0 again to load it. END_DIE my $obj = $admin->load($method, 1); push @{$self->{extensions}}, $obj; $obj; } sub load_extensions { my ($self, $path, $top) = @_; unless ( grep { lc $_ eq lc $self->{prefix} } @INC ) { unshift @INC, $self->{prefix}; } foreach my $rv ( $self->find_extensions($path) ) { my ($file, $pkg) = @{$rv}; next if $self->{pathnames}{$pkg}; local $@; my $new = eval { require $file; $pkg->can('new') }; unless ( $new ) { warn $@ if $@; next; } $self->{pathnames}{$pkg} = delete $INC{$file}; push @{$self->{extensions}}, &{$new}($pkg, _top => $top ); } $self->{extensions} ||= []; } sub find_extensions { my ($self, $path) = @_; my @found; File::Find::find( sub { my $file = $File::Find::name; return unless $file =~ m!^\Q$path\E/(.+)\.pm\Z!is; my $subpath = $1; return if lc($subpath) eq lc($self->{dispatch}); $file = "$self->{path}/$subpath.pm"; my $pkg = "$self->{name}::$subpath"; $pkg =~ s!/!::!g; # If we have a mixed-case package name, assume case has been preserved # correctly. Otherwise, root through the file to locate the case-preserved # version of the package name. if ( $subpath eq lc($subpath) || $subpath eq uc($subpath) ) { my $content = Module::Install::_read($subpath . '.pm'); my $in_pod = 0; foreach ( split //, $content ) { $in_pod = 1 if /^=\w/; $in_pod = 0 if /^=cut/; next if ($in_pod || /^=cut/); # skip pod text next if /^\s*#/; # and comments if ( m/^\s*package\s+($pkg)\s*;/i ) { $pkg = $1; last; } } } push @found, [ $file, $pkg ]; }, $path ) if -d $path; @found; } ##################################################################### # Utility Functions sub _caller { my $depth = 0; my $call = caller($depth); while ( $call eq __PACKAGE__ ) { $depth++; $call = caller($depth); } return $call; } sub _read { local *FH; open FH, "< $_[0]" or die "open($_[0]): $!"; my $str = do { local $/; }; close FH or die "close($_[0]): $!"; return $str; } sub _write { local *FH; open FH, "> $_[0]" or die "open($_[0]): $!"; foreach ( 1 .. $#_ ) { print FH $_[$_] or die "print($_[0]): $!" } close FH or die "close($_[0]): $!"; } sub _version ($) { my $s = shift || 0; $s =~ s/^(\d+)\.?//; my $l = $1 || 0; my @v = map { $_ . '0' x (3 - length $_) } $s =~ /(\d{1,3})\D?/g; $l = $l . '.' . join '', @v if @v; return $l + 0; } # Cloned from Params::Util::_CLASS sub _CLASS ($) { ( defined $_[0] and ! ref $_[0] and $_[0] =~ m/^[^\W\d]\w*(?:::\w+)*$/s ) ? $_[0] : undef; } 1; # Copyright 2008 Adam Kennedy. Jifty-Plugin-Comment-1.00/inc/Module/AutoInstall.pm0000644000175000017500000005077211221075503022371 0ustar agostiniagostini#line 1 package Module::AutoInstall; use strict; use Cwd (); use ExtUtils::MakeMaker (); use vars qw{$VERSION}; BEGIN { $VERSION = '1.03'; } # special map on pre-defined feature sets my %FeatureMap = ( '' => 'Core Features', # XXX: deprecated '-core' => 'Core Features', ); # various lexical flags my ( @Missing, @Existing, %DisabledTests, $UnderCPAN, $HasCPANPLUS ); my ( $Config, $CheckOnly, $SkipInstall, $AcceptDefault, $TestOnly ); my ( $PostambleActions, $PostambleUsed ); # See if it's a testing or non-interactive session _accept_default( $ENV{AUTOMATED_TESTING} or ! -t STDIN ); _init(); sub _accept_default { $AcceptDefault = shift; } sub missing_modules { return @Missing; } sub do_install { __PACKAGE__->install( [ $Config ? ( UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) : () ], @Missing, ); } # initialize various flags, and/or perform install sub _init { foreach my $arg ( @ARGV, split( /[\s\t]+/, $ENV{PERL_AUTOINSTALL} || $ENV{PERL_EXTUTILS_AUTOINSTALL} || '' ) ) { if ( $arg =~ /^--config=(.*)$/ ) { $Config = [ split( ',', $1 ) ]; } elsif ( $arg =~ /^--installdeps=(.*)$/ ) { __PACKAGE__->install( $Config, @Missing = split( /,/, $1 ) ); exit 0; } elsif ( $arg =~ /^--default(?:deps)?$/ ) { $AcceptDefault = 1; } elsif ( $arg =~ /^--check(?:deps)?$/ ) { $CheckOnly = 1; } elsif ( $arg =~ /^--skip(?:deps)?$/ ) { $SkipInstall = 1; } elsif ( $arg =~ /^--test(?:only)?$/ ) { $TestOnly = 1; } } } # overrides MakeMaker's prompt() to automatically accept the default choice sub _prompt { goto &ExtUtils::MakeMaker::prompt unless $AcceptDefault; my ( $prompt, $default ) = @_; my $y = ( $default =~ /^[Yy]/ ); print $prompt, ' [', ( $y ? 'Y' : 'y' ), '/', ( $y ? 'n' : 'N' ), '] '; print "$default\n"; return $default; } # the workhorse sub import { my $class = shift; my @args = @_ or return; my $core_all; print "*** $class version " . $class->VERSION . "\n"; print "*** Checking for Perl dependencies...\n"; my $cwd = Cwd::cwd(); $Config = []; my $maxlen = length( ( sort { length($b) <=> length($a) } grep { /^[^\-]/ } map { ref($_) ? ( ( ref($_) eq 'HASH' ) ? keys(%$_) : @{$_} ) : '' } map { +{@args}->{$_} } grep { /^[^\-]/ or /^-core$/i } keys %{ +{@args} } )[0] ); while ( my ( $feature, $modules ) = splice( @args, 0, 2 ) ) { my ( @required, @tests, @skiptests ); my $default = 1; my $conflict = 0; if ( $feature =~ m/^-(\w+)$/ ) { my $option = lc($1); # check for a newer version of myself _update_to( $modules, @_ ) and return if $option eq 'version'; # sets CPAN configuration options $Config = $modules if $option eq 'config'; # promote every features to core status $core_all = ( $modules =~ /^all$/i ) and next if $option eq 'core'; next unless $option eq 'core'; } print "[" . ( $FeatureMap{ lc($feature) } || $feature ) . "]\n"; $modules = [ %{$modules} ] if UNIVERSAL::isa( $modules, 'HASH' ); unshift @$modules, -default => &{ shift(@$modules) } if ( ref( $modules->[0] ) eq 'CODE' ); # XXX: bugward combatability while ( my ( $mod, $arg ) = splice( @$modules, 0, 2 ) ) { if ( $mod =~ m/^-(\w+)$/ ) { my $option = lc($1); $default = $arg if ( $option eq 'default' ); $conflict = $arg if ( $option eq 'conflict' ); @tests = @{$arg} if ( $option eq 'tests' ); @skiptests = @{$arg} if ( $option eq 'skiptests' ); next; } printf( "- %-${maxlen}s ...", $mod ); if ( $arg and $arg =~ /^\D/ ) { unshift @$modules, $arg; $arg = 0; } # XXX: check for conflicts and uninstalls(!) them. if ( defined( my $cur = _version_check( _load($mod), $arg ||= 0 ) ) ) { print "loaded. ($cur" . ( $arg ? " >= $arg" : '' ) . ")\n"; push @Existing, $mod => $arg; $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; } else { print "missing." . ( $arg ? " (would need $arg)" : '' ) . "\n"; push @required, $mod => $arg; } } next unless @required; my $mandatory = ( $feature eq '-core' or $core_all ); if ( !$SkipInstall and ( $CheckOnly or _prompt( qq{==> Auto-install the } . ( @required / 2 ) . ( $mandatory ? ' mandatory' : ' optional' ) . qq{ module(s) from CPAN?}, $default ? 'y' : 'n', ) =~ /^[Yy]/ ) ) { push( @Missing, @required ); $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; } elsif ( !$SkipInstall and $default and $mandatory and _prompt( qq{==> The module(s) are mandatory! Really skip?}, 'n', ) =~ /^[Nn]/ ) { push( @Missing, @required ); $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; } else { $DisabledTests{$_} = 1 for map { glob($_) } @tests; } } $UnderCPAN = _check_lock(); # check for $UnderCPAN if ( @Missing and not( $CheckOnly or $UnderCPAN ) ) { require Config; print "*** Dependencies will be installed the next time you type '$Config::Config{make}'.\n"; # make an educated guess of whether we'll need root permission. print " (You may need to do that as the 'root' user.)\n" if eval '$>'; } print "*** $class configuration finished.\n"; chdir $cwd; # import to main:: no strict 'refs'; *{'main::WriteMakefile'} = \&Write if caller(0) eq 'main'; } # Check to see if we are currently running under CPAN.pm and/or CPANPLUS; # if we are, then we simply let it taking care of our dependencies sub _check_lock { return unless @Missing; if ($ENV{PERL5_CPANPLUS_IS_RUNNING}) { print <<'END_MESSAGE'; *** Since we're running under CPANPLUS, I'll just let it take care of the dependency's installation later. END_MESSAGE return 1; } _load_cpan(); # Find the CPAN lock-file my $lock = MM->catfile( $CPAN::Config->{cpan_home}, ".lock" ); return unless -f $lock; # Check the lock local *LOCK; return unless open(LOCK, $lock); if ( ( $^O eq 'MSWin32' ? _under_cpan() : == getppid() ) and ( $CPAN::Config->{prerequisites_policy} || '' ) ne 'ignore' ) { print <<'END_MESSAGE'; *** Since we're running under CPAN, I'll just let it take care of the dependency's installation later. END_MESSAGE return 1; } close LOCK; return; } sub install { my $class = shift; my $i; # used below to strip leading '-' from config keys my @config = ( map { s/^-// if ++$i; $_ } @{ +shift } ); my ( @modules, @installed ); while ( my ( $pkg, $ver ) = splice( @_, 0, 2 ) ) { # grep out those already installed if ( defined( _version_check( _load($pkg), $ver ) ) ) { push @installed, $pkg; } else { push @modules, $pkg, $ver; } } return @installed unless @modules; # nothing to do return @installed if _check_lock(); # defer to the CPAN shell print "*** Installing dependencies...\n"; return unless _connected_to('cpan.org'); my %args = @config; my %failed; local *FAILED; if ( $args{do_once} and open( FAILED, '.#autoinstall.failed' ) ) { while () { chomp; $failed{$_}++ } close FAILED; my @newmod; while ( my ( $k, $v ) = splice( @modules, 0, 2 ) ) { push @newmod, ( $k => $v ) unless $failed{$k}; } @modules = @newmod; } if ( _has_cpanplus() ) { _install_cpanplus( \@modules, \@config ); } else { _install_cpan( \@modules, \@config ); } print "*** $class installation finished.\n"; # see if we have successfully installed them while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { if ( defined( _version_check( _load($pkg), $ver ) ) ) { push @installed, $pkg; } elsif ( $args{do_once} and open( FAILED, '>> .#autoinstall.failed' ) ) { print FAILED "$pkg\n"; } } close FAILED if $args{do_once}; return @installed; } sub _install_cpanplus { my @modules = @{ +shift }; my @config = _cpanplus_config( @{ +shift } ); my $installed = 0; require CPANPLUS::Backend; my $cp = CPANPLUS::Backend->new; my $conf = $cp->configure_object; return unless $conf->can('conf') # 0.05x+ with "sudo" support or _can_write($conf->_get_build('base')); # 0.04x # if we're root, set UNINST=1 to avoid trouble unless user asked for it. my $makeflags = $conf->get_conf('makeflags') || ''; if ( UNIVERSAL::isa( $makeflags, 'HASH' ) ) { # 0.03+ uses a hashref here $makeflags->{UNINST} = 1 unless exists $makeflags->{UNINST}; } else { # 0.02 and below uses a scalar $makeflags = join( ' ', split( ' ', $makeflags ), 'UNINST=1' ) if ( $makeflags !~ /\bUNINST\b/ and eval qq{ $> eq '0' } ); } $conf->set_conf( makeflags => $makeflags ); $conf->set_conf( prereqs => 1 ); while ( my ( $key, $val ) = splice( @config, 0, 2 ) ) { $conf->set_conf( $key, $val ); } my $modtree = $cp->module_tree; while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { print "*** Installing $pkg...\n"; MY::preinstall( $pkg, $ver ) or next if defined &MY::preinstall; my $success; my $obj = $modtree->{$pkg}; if ( $obj and defined( _version_check( $obj->{version}, $ver ) ) ) { my $pathname = $pkg; $pathname =~ s/::/\\W/; foreach my $inc ( grep { m/$pathname.pm/i } keys(%INC) ) { delete $INC{$inc}; } my $rv = $cp->install( modules => [ $obj->{module} ] ); if ( $rv and ( $rv->{ $obj->{module} } or $rv->{ok} ) ) { print "*** $pkg successfully installed.\n"; $success = 1; } else { print "*** $pkg installation cancelled.\n"; $success = 0; } $installed += $success; } else { print << "."; *** Could not find a version $ver or above for $pkg; skipping. . } MY::postinstall( $pkg, $ver, $success ) if defined &MY::postinstall; } return $installed; } sub _cpanplus_config { my @config = (); while ( @_ ) { my ($key, $value) = (shift(), shift()); if ( $key eq 'prerequisites_policy' ) { if ( $value eq 'follow' ) { $value = CPANPLUS::Internals::Constants::PREREQ_INSTALL(); } elsif ( $value eq 'ask' ) { $value = CPANPLUS::Internals::Constants::PREREQ_ASK(); } elsif ( $value eq 'ignore' ) { $value = CPANPLUS::Internals::Constants::PREREQ_IGNORE(); } else { die "*** Cannot convert option $key = '$value' to CPANPLUS version.\n"; } } else { die "*** Cannot convert option $key to CPANPLUS version.\n"; } } return @config; } sub _install_cpan { my @modules = @{ +shift }; my @config = @{ +shift }; my $installed = 0; my %args; _load_cpan(); require Config; if (CPAN->VERSION < 1.80) { # no "sudo" support, probe for writableness return unless _can_write( MM->catfile( $CPAN::Config->{cpan_home}, 'sources' ) ) and _can_write( $Config::Config{sitelib} ); } # if we're root, set UNINST=1 to avoid trouble unless user asked for it. my $makeflags = $CPAN::Config->{make_install_arg} || ''; $CPAN::Config->{make_install_arg} = join( ' ', split( ' ', $makeflags ), 'UNINST=1' ) if ( $makeflags !~ /\bUNINST\b/ and eval qq{ $> eq '0' } ); # don't show start-up info $CPAN::Config->{inhibit_startup_message} = 1; # set additional options while ( my ( $opt, $arg ) = splice( @config, 0, 2 ) ) { ( $args{$opt} = $arg, next ) if $opt =~ /^force$/; # pseudo-option $CPAN::Config->{$opt} = $arg; } local $CPAN::Config->{prerequisites_policy} = 'follow'; while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { MY::preinstall( $pkg, $ver ) or next if defined &MY::preinstall; print "*** Installing $pkg...\n"; my $obj = CPAN::Shell->expand( Module => $pkg ); my $success = 0; if ( $obj and defined( _version_check( $obj->cpan_version, $ver ) ) ) { my $pathname = $pkg; $pathname =~ s/::/\\W/; foreach my $inc ( grep { m/$pathname.pm/i } keys(%INC) ) { delete $INC{$inc}; } my $rv = $args{force} ? CPAN::Shell->force( install => $pkg ) : CPAN::Shell->install($pkg); $rv ||= eval { $CPAN::META->instance( 'CPAN::Distribution', $obj->cpan_file, ) ->{install} if $CPAN::META; }; if ( $rv eq 'YES' ) { print "*** $pkg successfully installed.\n"; $success = 1; } else { print "*** $pkg installation failed.\n"; $success = 0; } $installed += $success; } else { print << "."; *** Could not find a version $ver or above for $pkg; skipping. . } MY::postinstall( $pkg, $ver, $success ) if defined &MY::postinstall; } return $installed; } sub _has_cpanplus { return ( $HasCPANPLUS = ( $INC{'CPANPLUS/Config.pm'} or _load('CPANPLUS::Shell::Default') ) ); } # make guesses on whether we're under the CPAN installation directory sub _under_cpan { require Cwd; require File::Spec; my $cwd = File::Spec->canonpath( Cwd::cwd() ); my $cpan = File::Spec->canonpath( $CPAN::Config->{cpan_home} ); return ( index( $cwd, $cpan ) > -1 ); } sub _update_to { my $class = __PACKAGE__; my $ver = shift; return if defined( _version_check( _load($class), $ver ) ); # no need to upgrade if ( _prompt( "==> A newer version of $class ($ver) is required. Install?", 'y' ) =~ /^[Nn]/ ) { die "*** Please install $class $ver manually.\n"; } print << "."; *** Trying to fetch it from CPAN... . # install ourselves _load($class) and return $class->import(@_) if $class->install( [], $class, $ver ); print << '.'; exit 1; *** Cannot bootstrap myself. :-( Installation terminated. . } # check if we're connected to some host, using inet_aton sub _connected_to { my $site = shift; return ( ( _load('Socket') and Socket::inet_aton($site) ) or _prompt( qq( *** Your host cannot resolve the domain name '$site', which probably means the Internet connections are unavailable. ==> Should we try to install the required module(s) anyway?), 'n' ) =~ /^[Yy]/ ); } # check if a directory is writable; may create it on demand sub _can_write { my $path = shift; mkdir( $path, 0755 ) unless -e $path; return 1 if -w $path; print << "."; *** You are not allowed to write to the directory '$path'; the installation may fail due to insufficient permissions. . if ( eval '$>' and lc(`sudo -V`) =~ /version/ and _prompt( qq( ==> Should we try to re-execute the autoinstall process with 'sudo'?), ((-t STDIN) ? 'y' : 'n') ) =~ /^[Yy]/ ) { # try to bootstrap ourselves from sudo print << "."; *** Trying to re-execute the autoinstall process with 'sudo'... . my $missing = join( ',', @Missing ); my $config = join( ',', UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) if $Config; return unless system( 'sudo', $^X, $0, "--config=$config", "--installdeps=$missing" ); print << "."; *** The 'sudo' command exited with error! Resuming... . } return _prompt( qq( ==> Should we try to install the required module(s) anyway?), 'n' ) =~ /^[Yy]/; } # load a module and return the version it reports sub _load { my $mod = pop; # class/instance doesn't matter my $file = $mod; $file =~ s|::|/|g; $file .= '.pm'; local $@; return eval { require $file; $mod->VERSION } || ( $@ ? undef: 0 ); } # Load CPAN.pm and it's configuration sub _load_cpan { return if $CPAN::VERSION; require CPAN; if ( $CPAN::HandleConfig::VERSION ) { # Newer versions of CPAN have a HandleConfig module CPAN::HandleConfig->load; } else { # Older versions had the load method in Config directly CPAN::Config->load; } } # compare two versions, either use Sort::Versions or plain comparison sub _version_check { my ( $cur, $min ) = @_; return unless defined $cur; $cur =~ s/\s+$//; # check for version numbers that are not in decimal format if ( ref($cur) or ref($min) or $cur =~ /v|\..*\./ or $min =~ /v|\..*\./ ) { if ( ( $version::VERSION or defined( _load('version') )) and version->can('new') ) { # use version.pm if it is installed. return ( ( version->new($cur) >= version->new($min) ) ? $cur : undef ); } elsif ( $Sort::Versions::VERSION or defined( _load('Sort::Versions') ) ) { # use Sort::Versions as the sorting algorithm for a.b.c versions return ( ( Sort::Versions::versioncmp( $cur, $min ) != -1 ) ? $cur : undef ); } warn "Cannot reliably compare non-decimal formatted versions.\n" . "Please install version.pm or Sort::Versions.\n"; } # plain comparison local $^W = 0; # shuts off 'not numeric' bugs return ( $cur >= $min ? $cur : undef ); } # nothing; this usage is deprecated. sub main::PREREQ_PM { return {}; } sub _make_args { my %args = @_; $args{PREREQ_PM} = { %{ $args{PREREQ_PM} || {} }, @Existing, @Missing } if $UnderCPAN or $TestOnly; if ( $args{EXE_FILES} and -e 'MANIFEST' ) { require ExtUtils::Manifest; my $manifest = ExtUtils::Manifest::maniread('MANIFEST'); $args{EXE_FILES} = [ grep { exists $manifest->{$_} } @{ $args{EXE_FILES} } ]; } $args{test}{TESTS} ||= 't/*.t'; $args{test}{TESTS} = join( ' ', grep { !exists( $DisabledTests{$_} ) } map { glob($_) } split( /\s+/, $args{test}{TESTS} ) ); my $missing = join( ',', @Missing ); my $config = join( ',', UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) if $Config; $PostambleActions = ( $missing ? "\$(PERL) $0 --config=$config --installdeps=$missing" : "\$(NOECHO) \$(NOOP)" ); return %args; } # a wrapper to ExtUtils::MakeMaker::WriteMakefile sub Write { require Carp; Carp::croak "WriteMakefile: Need even number of args" if @_ % 2; if ($CheckOnly) { print << "."; *** Makefile not written in check-only mode. . return; } my %args = _make_args(@_); no strict 'refs'; $PostambleUsed = 0; local *MY::postamble = \&postamble unless defined &MY::postamble; ExtUtils::MakeMaker::WriteMakefile(%args); print << "." unless $PostambleUsed; *** WARNING: Makefile written with customized MY::postamble() without including contents from Module::AutoInstall::postamble() -- auto installation features disabled. Please contact the author. . return 1; } sub postamble { $PostambleUsed = 1; return << "."; config :: installdeps \t\$(NOECHO) \$(NOOP) checkdeps :: \t\$(PERL) $0 --checkdeps installdeps :: \t$PostambleActions . } 1; __END__ #line 1003 Jifty-Plugin-Comment-1.00/inc/Module/Install/0000755000175000017500000000000011221075700021166 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/inc/Module/Install/Win32.pm0000644000175000017500000000340211221075504022427 0ustar agostiniagostini#line 1 package Module::Install::Win32; use strict; use Module::Install::Base; use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '0.76'; @ISA = qw{Module::Install::Base}; $ISCORE = 1; } # determine if the user needs nmake, and download it if needed sub check_nmake { my $self = shift; $self->load('can_run'); $self->load('get_file'); require Config; return unless ( $^O eq 'MSWin32' and $Config::Config{make} and $Config::Config{make} =~ /^nmake\b/i and ! $self->can_run('nmake') ); print "The required 'nmake' executable not found, fetching it...\n"; require File::Basename; my $rv = $self->get_file( url => 'http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe', ftp_url => 'ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe', local_dir => File::Basename::dirname($^X), size => 51928, run => 'Nmake15.exe /o > nul', check_for => 'Nmake.exe', remove => 1, ); die <<'END_MESSAGE' unless $rv; ------------------------------------------------------------------------------- Since you are using Microsoft Windows, you will need the 'nmake' utility before installation. It's available at: http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe or ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe Please download the file manually, save it to a directory in %PATH% (e.g. C:\WINDOWS\COMMAND\), then launch the MS-DOS command line shell, "cd" to that directory, and run "Nmake15.exe" from there; that will create the 'nmake.exe' file needed by this module. You may then resume the installation process described in README. ------------------------------------------------------------------------------- END_MESSAGE } 1; Jifty-Plugin-Comment-1.00/inc/Module/Install/Fetch.pm0000644000175000017500000000463011221075504022562 0ustar agostiniagostini#line 1 package Module::Install::Fetch; use strict; use Module::Install::Base; use vars qw{$VERSION $ISCORE @ISA}; BEGIN { $VERSION = '0.76'; $ISCORE = 1; @ISA = qw{Module::Install::Base}; } sub get_file { my ($self, %args) = @_; my ($scheme, $host, $path, $file) = $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; if ( $scheme eq 'http' and ! eval { require LWP::Simple; 1 } ) { $args{url} = $args{ftp_url} or (warn("LWP support unavailable!\n"), return); ($scheme, $host, $path, $file) = $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; } $|++; print "Fetching '$file' from $host... "; unless (eval { require Socket; Socket::inet_aton($host) }) { warn "'$host' resolve failed!\n"; return; } return unless $scheme eq 'ftp' or $scheme eq 'http'; require Cwd; my $dir = Cwd::getcwd(); chdir $args{local_dir} or return if exists $args{local_dir}; if (eval { require LWP::Simple; 1 }) { LWP::Simple::mirror($args{url}, $file); } elsif (eval { require Net::FTP; 1 }) { eval { # use Net::FTP to get past firewall my $ftp = Net::FTP->new($host, Passive => 1, Timeout => 600); $ftp->login("anonymous", 'anonymous@example.com'); $ftp->cwd($path); $ftp->binary; $ftp->get($file) or (warn("$!\n"), return); $ftp->quit; } } elsif (my $ftp = $self->can_run('ftp')) { eval { # no Net::FTP, fallback to ftp.exe require FileHandle; my $fh = FileHandle->new; local $SIG{CHLD} = 'IGNORE'; unless ($fh->open("|$ftp -n")) { warn "Couldn't open ftp: $!\n"; chdir $dir; return; } my @dialog = split(/\n/, <<"END_FTP"); open $host user anonymous anonymous\@example.com cd $path binary get $file $file quit END_FTP foreach (@dialog) { $fh->print("$_\n") } $fh->close; } } else { warn "No working 'ftp' program available!\n"; chdir $dir; return; } unless (-f $file) { warn "Fetching failed: $@\n"; chdir $dir; return; } return if exists $args{size} and -s $file != $args{size}; system($args{run}) if exists $args{run}; unlink($file) if $args{remove}; print(((!exists $args{check_for} or -e $args{check_for}) ? "done!" : "failed! ($!)"), "\n"); chdir $dir; return !$?; } 1; Jifty-Plugin-Comment-1.00/inc/Module/Install/Include.pm0000644000175000017500000000101411221075503023104 0ustar agostiniagostini#line 1 package Module::Install::Include; use strict; use Module::Install::Base; use vars qw{$VERSION $ISCORE @ISA}; BEGIN { $VERSION = '0.76'; $ISCORE = 1; @ISA = qw{Module::Install::Base}; } sub include { shift()->admin->include(@_); } sub include_deps { shift()->admin->include_deps(@_); } sub auto_include { shift()->admin->auto_include(@_); } sub auto_include_deps { shift()->admin->auto_include_deps(@_); } sub auto_include_dependent_dists { shift()->admin->auto_include_dependent_dists(@_); } 1; Jifty-Plugin-Comment-1.00/inc/Module/Install/Can.pm0000644000175000017500000000337411221075504022236 0ustar agostiniagostini#line 1 package Module::Install::Can; use strict; use Module::Install::Base; use Config (); ### This adds a 5.005 Perl version dependency. ### This is a bug and will be fixed. use File::Spec (); use ExtUtils::MakeMaker (); use vars qw{$VERSION $ISCORE @ISA}; BEGIN { $VERSION = '0.76'; $ISCORE = 1; @ISA = qw{Module::Install::Base}; } # check if we can load some module ### Upgrade this to not have to load the module if possible sub can_use { my ($self, $mod, $ver) = @_; $mod =~ s{::|\\}{/}g; $mod .= '.pm' unless $mod =~ /\.pm$/i; my $pkg = $mod; $pkg =~ s{/}{::}g; $pkg =~ s{\.pm$}{}i; local $@; eval { require $mod; $pkg->VERSION($ver || 0); 1 }; } # check if we can run some command sub can_run { my ($self, $cmd) = @_; my $_cmd = $cmd; return $_cmd if (-x $_cmd or $_cmd = MM->maybe_command($_cmd)); for my $dir ((split /$Config::Config{path_sep}/, $ENV{PATH}), '.') { my $abs = File::Spec->catfile($dir, $_[1]); return $abs if (-x $abs or $abs = MM->maybe_command($abs)); } return; } # can we locate a (the) C compiler sub can_cc { my $self = shift; my @chunks = split(/ /, $Config::Config{cc}) or return; # $Config{cc} may contain args; try to find out the program part while (@chunks) { return $self->can_run("@chunks") || (pop(@chunks), next); } return; } # Fix Cygwin bug on maybe_command(); if ( $^O eq 'cygwin' ) { require ExtUtils::MM_Cygwin; require ExtUtils::MM_Win32; if ( ! defined(&ExtUtils::MM_Cygwin::maybe_command) ) { *ExtUtils::MM_Cygwin::maybe_command = sub { my ($self, $file) = @_; if ($file =~ m{^/cygdrive/}i and ExtUtils::MM_Win32->can('maybe_command')) { ExtUtils::MM_Win32->maybe_command($file); } else { ExtUtils::MM_Unix->maybe_command($file); } } } } 1; __END__ #line 157 Jifty-Plugin-Comment-1.00/inc/Module/Install/Metadata.pm0000644000175000017500000002573211221075503023256 0ustar agostiniagostini#line 1 package Module::Install::Metadata; use strict 'vars'; use Module::Install::Base; use vars qw{$VERSION $ISCORE @ISA}; BEGIN { $VERSION = '0.76'; $ISCORE = 1; @ISA = qw{Module::Install::Base}; } my @scalar_keys = qw{ name module_name abstract author version distribution_type tests installdirs }; my @tuple_keys = qw{ configure_requires build_requires requires recommends bundles resources }; my @resource_keys = qw{ homepage bugtracker repository }; sub Meta { shift } sub Meta_ScalarKeys { @scalar_keys } sub Meta_TupleKeys { @tuple_keys } sub Meta_ResourceKeys { @resource_keys } foreach my $key ( @scalar_keys ) { *$key = sub { my $self = shift; return $self->{values}{$key} if defined wantarray and !@_; $self->{values}{$key} = shift; return $self; }; } foreach my $key ( @resource_keys ) { *$key = sub { my $self = shift; unless ( @_ ) { return () unless $self->{values}{resources}; return map { $_->[1] } grep { $_->[0] eq $key } @{ $self->{values}{resources} }; } return $self->{values}{resources}{$key} unless @_; my $uri = shift or die( "Did not provide a value to $key()" ); $self->resources( $key => $uri ); return 1; }; } sub requires { my $self = shift; while ( @_ ) { my $module = shift or last; my $version = shift || 0; push @{ $self->{values}{requires} }, [ $module, $version ]; } $self->{values}{requires}; } sub build_requires { my $self = shift; while ( @_ ) { my $module = shift or last; my $version = shift || 0; push @{ $self->{values}{build_requires} }, [ $module, $version ]; } $self->{values}{build_requires}; } sub configure_requires { my $self = shift; while ( @_ ) { my $module = shift or last; my $version = shift || 0; push @{ $self->{values}{configure_requires} }, [ $module, $version ]; } $self->{values}{configure_requires}; } sub recommends { my $self = shift; while ( @_ ) { my $module = shift or last; my $version = shift || 0; push @{ $self->{values}{recommends} }, [ $module, $version ]; } $self->{values}{recommends}; } sub bundles { my $self = shift; while ( @_ ) { my $module = shift or last; my $version = shift || 0; push @{ $self->{values}{bundles} }, [ $module, $version ]; } $self->{values}{bundles}; } # Resource handling my %lc_resource = map { $_ => 1 } qw{ homepage license bugtracker repository }; sub resources { my $self = shift; while ( @_ ) { my $name = shift or last; my $value = shift or next; if ( $name eq lc $name and ! $lc_resource{$name} ) { die("Unsupported reserved lowercase resource '$name'"); } $self->{values}{resources} ||= []; push @{ $self->{values}{resources} }, [ $name, $value ]; } $self->{values}{resources}; } # Aliases for build_requires that will have alternative # meanings in some future version of META.yml. sub test_requires { shift->build_requires(@_) } sub install_requires { shift->build_requires(@_) } # Aliases for installdirs options sub install_as_core { $_[0]->installdirs('perl') } sub install_as_cpan { $_[0]->installdirs('site') } sub install_as_site { $_[0]->installdirs('site') } sub install_as_vendor { $_[0]->installdirs('vendor') } sub sign { my $self = shift; return $self->{values}{sign} if defined wantarray and ! @_; $self->{values}{sign} = ( @_ ? $_[0] : 1 ); return $self; } sub dynamic_config { my $self = shift; unless ( @_ ) { warn "You MUST provide an explicit true/false value to dynamic_config\n"; return $self; } $self->{values}{dynamic_config} = $_[0] ? 1 : 0; return 1; } sub perl_version { my $self = shift; return $self->{values}{perl_version} unless @_; my $version = shift or die( "Did not provide a value to perl_version()" ); $version =~ s/_.+$//; $version = $version + 0; # Numify unless ( $version >= 5.005 ) { die "Module::Install only supports 5.005 or newer (use ExtUtils::MakeMaker)\n"; } $self->{values}{perl_version} = $version; return 1; } sub license { my $self = shift; return $self->{values}{license} unless @_; my $license = shift or die( 'Did not provide a value to license()' ); $self->{values}{license} = $license; # Automatically fill in license URLs if ( $license eq 'perl' ) { $self->resources( license => 'http://dev.perl.org/licenses/' ); } return 1; } sub all_from { my ( $self, $file ) = @_; unless ( defined($file) ) { my $name = $self->name or die( "all_from called with no args without setting name() first" ); $file = join('/', 'lib', split(/-/, $name)) . '.pm'; $file =~ s{.*/}{} unless -e $file; unless ( -e $file ) { die("all_from cannot find $file from $name"); } } # Some methods pull from POD instead of code. # If there is a matching .pod, use that instead my $pod = $file; $pod =~ s/\.pm$/.pod/i; $pod = $file unless -e $pod; # Pull the different values $self->name_from($file) unless $self->name; $self->version_from($file) unless $self->version; $self->perl_version_from($file) unless $self->perl_version; $self->author_from($pod) unless $self->author; $self->license_from($pod) unless $self->license; $self->abstract_from($pod) unless $self->abstract; return 1; } sub provides { my $self = shift; my $provides = ( $self->{values}{provides} ||= {} ); %$provides = (%$provides, @_) if @_; return $provides; } sub auto_provides { my $self = shift; return $self unless $self->is_admin; unless (-e 'MANIFEST') { warn "Cannot deduce auto_provides without a MANIFEST, skipping\n"; return $self; } # Avoid spurious warnings as we are not checking manifest here. local $SIG{__WARN__} = sub {1}; require ExtUtils::Manifest; local *ExtUtils::Manifest::manicheck = sub { return }; require Module::Build; my $build = Module::Build->new( dist_name => $self->name, dist_version => $self->version, license => $self->license, ); $self->provides( %{ $build->find_dist_packages || {} } ); } sub feature { my $self = shift; my $name = shift; my $features = ( $self->{values}{features} ||= [] ); my $mods; if ( @_ == 1 and ref( $_[0] ) ) { # The user used ->feature like ->features by passing in the second # argument as a reference. Accomodate for that. $mods = $_[0]; } else { $mods = \@_; } my $count = 0; push @$features, ( $name => [ map { ref($_) ? ( ref($_) eq 'HASH' ) ? %$_ : @$_ : $_ } @$mods ] ); return @$features; } sub features { my $self = shift; while ( my ( $name, $mods ) = splice( @_, 0, 2 ) ) { $self->feature( $name, @$mods ); } return $self->{values}{features} ? @{ $self->{values}{features} } : (); } sub no_index { my $self = shift; my $type = shift; push @{ $self->{values}{no_index}{$type} }, @_ if $type; return $self->{values}{no_index}; } sub read { my $self = shift; $self->include_deps( 'YAML::Tiny', 0 ); require YAML::Tiny; my $data = YAML::Tiny::LoadFile('META.yml'); # Call methods explicitly in case user has already set some values. while ( my ( $key, $value ) = each %$data ) { next unless $self->can($key); if ( ref $value eq 'HASH' ) { while ( my ( $module, $version ) = each %$value ) { $self->can($key)->($self, $module => $version ); } } else { $self->can($key)->($self, $value); } } return $self; } sub write { my $self = shift; return $self unless $self->is_admin; $self->admin->write_meta; return $self; } sub version_from { require ExtUtils::MM_Unix; my ( $self, $file ) = @_; $self->version( ExtUtils::MM_Unix->parse_version($file) ); } sub abstract_from { require ExtUtils::MM_Unix; my ( $self, $file ) = @_; $self->abstract( bless( { DISTNAME => $self->name }, 'ExtUtils::MM_Unix' )->parse_abstract($file) ); } # Add both distribution and module name sub name_from { my ($self, $file) = @_; if ( Module::Install::_read($file) =~ m/ ^ \s* package \s* ([\w:]+) \s* ; /ixms ) { my ($name, $module_name) = ($1, $1); $name =~ s{::}{-}g; $self->name($name); unless ( $self->module_name ) { $self->module_name($module_name); } } else { die("Cannot determine name from $file\n"); } } sub perl_version_from { my $self = shift; if ( Module::Install::_read($_[0]) =~ m/ ^ (?:use|require) \s* v? ([\d_\.]+) \s* ; /ixms ) { my $perl_version = $1; $perl_version =~ s{_}{}g; $self->perl_version($perl_version); } else { warn "Cannot determine perl version info from $_[0]\n"; return; } } sub author_from { my $self = shift; my $content = Module::Install::_read($_[0]); if ($content =~ m/ =head \d \s+ (?:authors?)\b \s* ([^\n]*) | =head \d \s+ (?:licen[cs]e|licensing|copyright|legal)\b \s* .*? copyright .*? \d\d\d[\d.]+ \s* (?:\bby\b)? \s* ([^\n]*) /ixms) { my $author = $1 || $2; $author =~ s{E}{<}g; $author =~ s{E}{>}g; $self->author($author); } else { warn "Cannot determine author info from $_[0]\n"; } } sub license_from { my $self = shift; if ( Module::Install::_read($_[0]) =~ m/ ( =head \d \s+ (?:licen[cs]e|licensing|copyright|legal)\b .*? ) (=head\\d.*|=cut.*|) \z /ixms ) { my $license_text = $1; my @phrases = ( 'under the same (?:terms|license) as perl itself' => 'perl', 1, 'GNU public license' => 'gpl', 1, 'GNU lesser public license' => 'lgpl', 1, 'BSD license' => 'bsd', 1, 'Artistic license' => 'artistic', 1, 'GPL' => 'gpl', 1, 'LGPL' => 'lgpl', 1, 'BSD' => 'bsd', 1, 'Artistic' => 'artistic', 1, 'MIT' => 'mit', 1, 'proprietary' => 'proprietary', 0, ); while ( my ($pattern, $license, $osi) = splice(@phrases, 0, 3) ) { $pattern =~ s{\s+}{\\s+}g; if ( $license_text =~ /\b$pattern\b/i ) { if ( $osi and $license_text =~ /All rights reserved/i ) { print "WARNING: 'All rights reserved' in copyright may invalidate Open Source license.\n"; } $self->license($license); return 1; } } } warn "Cannot determine license info from $_[0]\n"; return 'unknown'; } sub bugtracker_from { my $self = shift; my $content = Module::Install::_read($_[0]); my @links = $content =~ m/L\<(http\:\/\/rt\.cpan\.org\/[^>]+)\>/g; unless ( @links ) { warn "Cannot determine bugtracker info from $_[0]\n"; return 0; } if ( @links > 1 ) { warn "Found more than on rt.cpan.org link in $_[0]\n"; return 0; } # Set the bugtracker bugtracker( $links[0] ); return 1; } sub install_script { my $self = shift; my $args = $self->makemaker_args; my $exe = $args->{EXE_FILES} ||= []; foreach ( @_ ) { if ( -f $_ ) { push @$exe, $_; } elsif ( -d 'script' and -f "script/$_" ) { push @$exe, "script/$_"; } else { die("Cannot find script '$_'"); } } } 1; Jifty-Plugin-Comment-1.00/inc/Module/Install/Base.pm0000644000175000017500000000205011221075503022374 0ustar agostiniagostini#line 1 package Module::Install::Base; $VERSION = '0.76'; # Suspend handler for "redefined" warnings BEGIN { my $w = $SIG{__WARN__}; $SIG{__WARN__} = sub { $w }; } ### This is the ONLY module that shouldn't have strict on # use strict; #line 41 sub new { my ($class, %args) = @_; foreach my $method ( qw(call load) ) { *{"$class\::$method"} = sub { shift()->_top->$method(@_); } unless defined &{"$class\::$method"}; } bless( \%args, $class ); } #line 61 sub AUTOLOAD { my $self = shift; local $@; my $autoload = eval { $self->_top->autoload } or return; goto &$autoload; } #line 76 sub _top { $_[0]->{_top} } #line 89 sub admin { $_[0]->_top->{admin} or Module::Install::Base::FakeAdmin->new; } #line 101 sub is_admin { $_[0]->admin->VERSION; } sub DESTROY {} package Module::Install::Base::FakeAdmin; my $Fake; sub new { $Fake ||= bless(\@_, $_[0]) } sub AUTOLOAD {} sub DESTROY {} # Restore warning handler BEGIN { $SIG{__WARN__} = $SIG{__WARN__}->(); } 1; #line 146 Jifty-Plugin-Comment-1.00/inc/Module/Install/Makefile.pm0000644000175000017500000001445411221075504023253 0ustar agostiniagostini#line 1 package Module::Install::Makefile; use strict 'vars'; use Module::Install::Base; use ExtUtils::MakeMaker (); use vars qw{$VERSION $ISCORE @ISA}; BEGIN { $VERSION = '0.76'; $ISCORE = 1; @ISA = qw{Module::Install::Base}; } sub Makefile { $_[0] } my %seen = (); sub prompt { shift; # Infinite loop protection my @c = caller(); if ( ++$seen{"$c[1]|$c[2]|$_[0]"} > 3 ) { die "Caught an potential prompt infinite loop ($c[1]|$c[2]|$_[0])"; } # In automated testing, always use defaults if ( $ENV{AUTOMATED_TESTING} and ! $ENV{PERL_MM_USE_DEFAULT} ) { local $ENV{PERL_MM_USE_DEFAULT} = 1; goto &ExtUtils::MakeMaker::prompt; } else { goto &ExtUtils::MakeMaker::prompt; } } sub makemaker_args { my $self = shift; my $args = ( $self->{makemaker_args} ||= {} ); %$args = ( %$args, @_ ); return $args; } # For mm args that take multiple space-seperated args, # append an argument to the current list. sub makemaker_append { my $self = sShift; my $name = shift; my $args = $self->makemaker_args; $args->{name} = defined $args->{$name} ? join( ' ', $args->{name}, @_ ) : join( ' ', @_ ); } sub build_subdirs { my $self = shift; my $subdirs = $self->makemaker_args->{DIR} ||= []; for my $subdir (@_) { push @$subdirs, $subdir; } } sub clean_files { my $self = shift; my $clean = $self->makemaker_args->{clean} ||= {}; %$clean = ( %$clean, FILES => join ' ', grep { length $_ } ($clean->{FILES} || (), @_), ); } sub realclean_files { my $self = shift; my $realclean = $self->makemaker_args->{realclean} ||= {}; %$realclean = ( %$realclean, FILES => join ' ', grep { length $_ } ($realclean->{FILES} || (), @_), ); } sub libs { my $self = shift; my $libs = ref $_[0] ? shift : [ shift ]; $self->makemaker_args( LIBS => $libs ); } sub inc { my $self = shift; $self->makemaker_args( INC => shift ); } my %test_dir = (); sub _wanted_t { /\.t$/ and -f $_ and $test_dir{$File::Find::dir} = 1; } sub tests_recursive { my $self = shift; if ( $self->tests ) { die "tests_recursive will not work if tests are already defined"; } my $dir = shift || 't'; unless ( -d $dir ) { die "tests_recursive dir '$dir' does not exist"; } %test_dir = (); require File::Find; File::Find::find( \&_wanted_t, $dir ); $self->tests( join ' ', map { "$_/*.t" } sort keys %test_dir ); } sub write { my $self = shift; die "&Makefile->write() takes no arguments\n" if @_; # Make sure we have a new enough require ExtUtils::MakeMaker; # MakeMaker can complain about module versions that include # an underscore, even though its own version may contain one! # Hence the funny regexp to get rid of it. See RT #35800 # for details. $self->configure_requires( 'ExtUtils::MakeMaker' => $ExtUtils::MakeMaker::VERSION =~ /^(\d+\.\d+)/ ); # Generate the my $args = $self->makemaker_args; $args->{DISTNAME} = $self->name; $args->{NAME} = $self->module_name || $self->name; $args->{VERSION} = $self->version; $args->{NAME} =~ s/-/::/g; if ( $self->tests ) { $args->{test} = { TESTS => $self->tests }; } if ($] >= 5.005) { $args->{ABSTRACT} = $self->abstract; $args->{AUTHOR} = $self->author; } if ( eval($ExtUtils::MakeMaker::VERSION) >= 6.10 ) { $args->{NO_META} = 1; } if ( eval($ExtUtils::MakeMaker::VERSION) > 6.17 and $self->sign ) { $args->{SIGN} = 1; } unless ( $self->is_admin ) { delete $args->{SIGN}; } # merge both kinds of requires into prereq_pm my $prereq = ($args->{PREREQ_PM} ||= {}); %$prereq = ( %$prereq, map { @$_ } map { @$_ } grep $_, ($self->configure_requires, $self->build_requires, $self->requires) ); # Remove any reference to perl, PREREQ_PM doesn't support it delete $args->{PREREQ_PM}->{perl}; # merge both kinds of requires into prereq_pm my $subdirs = ($args->{DIR} ||= []); if ($self->bundles) { foreach my $bundle (@{ $self->bundles }) { my ($file, $dir) = @$bundle; push @$subdirs, $dir if -d $dir; delete $prereq->{$file}; } } if ( my $perl_version = $self->perl_version ) { eval "use $perl_version; 1" or die "ERROR: perl: Version $] is installed, " . "but we need version >= $perl_version"; } $args->{INSTALLDIRS} = $self->installdirs; my %args = map { ( $_ => $args->{$_} ) } grep {defined($args->{$_})} keys %$args; my $user_preop = delete $args{dist}->{PREOP}; if (my $preop = $self->admin->preop($user_preop)) { $args{dist} = $preop; } my $mm = ExtUtils::MakeMaker::WriteMakefile(%args); $self->fix_up_makefile($mm->{FIRST_MAKEFILE} || 'Makefile'); } sub fix_up_makefile { my $self = shift; my $makefile_name = shift; my $top_class = ref($self->_top) || ''; my $top_version = $self->_top->VERSION || ''; my $preamble = $self->preamble ? "# Preamble by $top_class $top_version\n" . $self->preamble : ''; my $postamble = "# Postamble by $top_class $top_version\n" . ($self->postamble || ''); local *MAKEFILE; open MAKEFILE, "< $makefile_name" or die "fix_up_makefile: Couldn't open $makefile_name: $!"; my $makefile = do { local $/; }; close MAKEFILE or die $!; $makefile =~ s/\b(test_harness\(\$\(TEST_VERBOSE\), )/$1'inc', /; $makefile =~ s/( -I\$\(INST_ARCHLIB\))/ -Iinc$1/g; $makefile =~ s/( "-I\$\(INST_LIB\)")/ "-Iinc"$1/g; $makefile =~ s/^(FULLPERL = .*)/$1 "-Iinc"/m; $makefile =~ s/^(PERL = .*)/$1 "-Iinc"/m; # Module::Install will never be used to build the Core Perl # Sometimes PERL_LIB and PERL_ARCHLIB get written anyway, which breaks # PREFIX/PERL5LIB, and thus, install_share. Blank them if they exist $makefile =~ s/^PERL_LIB = .+/PERL_LIB =/m; #$makefile =~ s/^PERL_ARCHLIB = .+/PERL_ARCHLIB =/m; # Perl 5.005 mentions PERL_LIB explicitly, so we have to remove that as well. $makefile =~ s/(\"?)-I\$\(PERL_LIB\)\1//g; # XXX - This is currently unused; not sure if it breaks other MM-users # $makefile =~ s/^pm_to_blib\s+:\s+/pm_to_blib :: /mg; open MAKEFILE, "> $makefile_name" or die "fix_up_makefile: Couldn't open $makefile_name: $!"; print MAKEFILE "$preamble$makefile$postamble" or die $!; close MAKEFILE or die $!; 1; } sub preamble { my ($self, $text) = @_; $self->{preamble} = $text . $self->{preamble} if defined $text; $self->{preamble}; } sub postamble { my ($self, $text) = @_; $self->{postamble} ||= $self->admin->postamble; $self->{postamble} .= $text if defined $text; $self->{postamble} } 1; __END__ #line 377 Jifty-Plugin-Comment-1.00/inc/Module/Install/AutoInstall.pm0000644000175000017500000000227211221075503023767 0ustar agostiniagostini#line 1 package Module::Install::AutoInstall; use strict; use Module::Install::Base; use vars qw{$VERSION $ISCORE @ISA}; BEGIN { $VERSION = '0.76'; $ISCORE = 1; @ISA = qw{Module::Install::Base}; } sub AutoInstall { $_[0] } sub run { my $self = shift; $self->auto_install_now(@_); } sub write { my $self = shift; $self->auto_install(@_); } sub auto_install { my $self = shift; return if $self->{done}++; # Flatten array of arrays into a single array my @core = map @$_, map @$_, grep ref, $self->build_requires, $self->requires; my @config = @_; # We'll need Module::AutoInstall $self->include('Module::AutoInstall'); require Module::AutoInstall; Module::AutoInstall->import( (@config ? (-config => \@config) : ()), (@core ? (-core => \@core) : ()), $self->features, ); $self->makemaker_args( Module::AutoInstall::_make_args() ); my $class = ref($self); $self->postamble( "# --- $class section:\n" . Module::AutoInstall::postamble() ); } sub auto_install_now { my $self = shift; $self->auto_install(@_); Module::AutoInstall::do_install(); } 1; Jifty-Plugin-Comment-1.00/inc/Module/Install/WriteAll.pm0000644000175000017500000000132111221075504023246 0ustar agostiniagostini#line 1 package Module::Install::WriteAll; use strict; use Module::Install::Base; use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '0.76'; @ISA = qw{Module::Install::Base}; $ISCORE = 1; } sub WriteAll { my $self = shift; my %args = ( meta => 1, sign => 0, inline => 0, check_nmake => 1, @_, ); $self->sign(1) if $args{sign}; $self->Meta->write if $args{meta}; $self->admin->WriteAll(%args) if $self->is_admin; $self->check_nmake if $args{check_nmake}; unless ( $self->makemaker_args->{PL_FILES} ) { $self->makemaker_args( PL_FILES => {} ); } if ( $args{inline} ) { $self->Inline->write; } else { $self->Makefile->write; } } 1; Jifty-Plugin-Comment-1.00/inc/Module/Install/Share.pm0000644000175000017500000000315411221075504022573 0ustar agostiniagostini#line 1 package Module::Install::Share; use strict; use Module::Install::Base; use vars qw{$VERSION $ISCORE @ISA}; BEGIN { $VERSION = '0.76'; $ISCORE = 1; @ISA = qw{Module::Install::Base}; } sub install_share { my $self = shift; my $dir = @_ ? pop : 'share'; my $type = @_ ? shift : 'dist'; unless ( defined $type and $type eq 'module' or $type eq 'dist' ) { die "Illegal or invalid share dir type '$type'"; } unless ( defined $dir and -d $dir ) { die "Illegal or missing directory install_share param"; } # Split by type my $S = ($^O eq 'MSWin32') ? "\\" : "\/"; if ( $type eq 'dist' ) { die "Too many parameters to install_share" if @_; # Set up the install $self->postamble(<<"END_MAKEFILE"); config :: \t\$(NOECHO) \$(MOD_INSTALL) \\ \t\t"$dir" \$(INST_LIB)${S}auto${S}share${S}dist${S}\$(DISTNAME) END_MAKEFILE } else { my $module = Module::Install::_CLASS($_[0]); unless ( defined $module ) { die "Missing or invalid module name '$_[0]'"; } $module =~ s/::/-/g; # Set up the install $self->postamble(<<"END_MAKEFILE"); config :: \t\$(NOECHO) \$(MOD_INSTALL) \\ \t\t"$dir" \$(INST_LIB)${S}auto${S}share${S}module${S}$module END_MAKEFILE } # The above appears to behave incorrectly when used with old versions # of ExtUtils::Install (known-bad on RHEL 3, with 5.8.0) # So when we need to install a share directory, make sure we add a # dependency on a moderately new version of ExtUtils::MakeMaker. $self->build_requires( 'ExtUtils::MakeMaker' => '6.11' ); # 99% of the time we don't want to index a shared dir $self->no_index( directory => $dir ); } 1; __END__ #line 125 Jifty-Plugin-Comment-1.00/Changes0000644000175000017500000000043611221075462017065 0ustar agostiniagostiniRevision history for Perl module Jifty::Plugin::Comment 1.00 Fri, 26 Jun 2009 08:52:55 +0200 - add missing dep from Action/CreateComment.pm in Makefile.PL - add dep on Jifty 0.90409 to use Jifty::Test::Dist 0.9 Wed, 10 Jun 2009 09:33:32 +0200 - original version for CPAN Jifty-Plugin-Comment-1.00/share/0000755000175000017500000000000011221075700016664 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/share/po/0000755000175000017500000000000011221075700017302 5ustar agostiniagostiniJifty-Plugin-Comment-1.00/share/po/jifty_plugin_comment.pot0000644000175000017500000000620011155144775024270 0ustar agostiniagostini# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: plugins/Comment/lib/Jifty/Plugin/Comment/Notification/CommentNeedsModeration.pm:73 #. ($url, $self->parent->title, $comment->title, $from, $comment->created_on->strftime('%A, %B %d, %Y @ %H:%M%P') msgid "" "\n" "The following comment has not been published. If you would like to publish it, please visit the link below and click on the \"publish\" link. If it has been marked as spam and should not have been you should also click on the \"mark as ham\" link.\n" "\n" "View Comment: %1\n" "\n" "On Post: %2\n" "Subject: %3\n" "From: %4\n" "Date: %5\n" "\n" "%6\n" msgstr "" #: plugins/Comment/lib/Jifty/Plugin/Comment/Notification/CommentPublished.pm:71 #. ($url, $self->parent->title, $comment->title, $from, $comment->created_on->strftime('%A, %B %d, %Y @ %H:%M%P') msgid "" "\n" "View Comment: %1\n" "\n" "On Post: %2\n" "Subject: %3\n" "From: %4\n" "Date: %5\n" "\n" "%6\n" msgstr "" #: plugins/Comment/lib/Jifty/Plugin/Comment/View.pm:165 msgid "Add a comment" msgstr "" #: plugins/Comment/t/TestApp-Plugin-Comments/lib/TestApp/Plugin/Comments/View.pm:22 #. ($blog->author) msgid "By %1" msgstr "" #: plugins/Comment/lib/Jifty/Plugin/Comment/View.pm:138 plugins/Comment/lib/Jifty/Plugin/Comment/View.pm:197 #. ($poster, $created_on->strftime('%A, %B %d, %Y @ %H:%M%P') #. ($poster, $created_on->strftime('%A, %B %d, %Y @ %H:%M%P') msgid "By %1 %2" msgstr "" #: plugins/Comment/lib/Jifty/Plugin/Comment/View.pm:304 msgid "No one has made a comment yet." msgstr "" #: plugins/Comment/t/TestApp-Plugin-Comments/lib/TestApp/Plugin/Comments/View.pm:13 msgid "Post" msgstr "" #: plugins/Comment/lib/Jifty/Plugin/Comment/View.pm:221 msgid "Preview" msgstr "" #: plugins/Comment/lib/Jifty/Plugin/Comment/View.pm:236 msgid "Submit" msgstr "" #: plugins/Comment/lib/Jifty/Plugin/Comment/Action/CreateComment.pm:268 msgid "Your comment has been added. If it does not immediately appear, it may have been flagged for moderation and should appear shortly." msgstr "" #: plugins/Comment/lib/Jifty/Plugin/Comment/Notification/CommentNeedsModeration.pm:67 #. ($appname, $comment->title) msgid "[%1] Moderate comment: %2" msgstr "" #: plugins/Comment/lib/Jifty/Plugin/Comment/Notification/CommentPublished.pm:65 #. ($appname, $comment->title) msgid "[%1] New comment: %2" msgstr "" #: plugins/Comment/lib/Jifty/Plugin/Comment/View.pm:87 #. ($status) msgid "mark as %1" msgstr "" #: plugins/Comment/lib/Jifty/Plugin/Comment/View.pm:100 msgid "publish" msgstr "" #: plugins/Comment/lib/Jifty/Plugin/Comment/View.pm:100 msgid "unpublish" msgstr "" Jifty-Plugin-Comment-1.00/share/po/fr.po0000644000175000017500000000763411213654307020272 0ustar agostiniagostini# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Yves Agostini , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "POT-Creation-Date: 2009-06-10 08:39:17+0200\n" "PO-Revision-Date: 2009-06-10 08:39:17+0200\n" "Last-Translator: Yves Agostini \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: plugins/Comment/lib/Jifty/Plugin/Comment/Notification/CommentNeedsModeration.pm:73 #. ($url, $self->parent->title, $comment->title, $from, $comment->created_on->strftime('%A, %B %d, %Y @ %H:%M%P') msgid "" "\n" "The following comment has not been published. If you would like to publish it, please visit the link below and click on the \"publish\" link. If it has been marked as spam and should not have been you should also click on the \"mark as ham\" link.\n" "\n" "View Comment: %1\n" "\n" "On Post: %2\n" "Subject: %3\n" "From: %4\n" "Date: %5\n" "\n" "%6\n" msgstr "" "\n" "Le commentaire suivant n'a pas encore été publié. Si vous voulez le publier, consultez le lien ci-dessous et cliquez sur le lien \"publier\". S'il a été marqué par erreur comme spam, cliquez sur le lien \"marquer comme han\".\n" "\n" "Commentaire: %1\n" "\n" "Sur le billet: %2\n" "Sujet: %3\n" "De: %4\n" "Date: %5\n" "\n" "%6\n" #: plugins/Comment/lib/Jifty/Plugin/Comment/Notification/CommentPublished.pm:71 #. ($url, $self->parent->title, $comment->title, $from, $comment->created_on->strftime('%A, %B %d, %Y @ %H:%M%P') msgid "" "\n" "View Comment: %1\n" "\n" "On Post: %2\n" "Subject: %3\n" "From: %4\n" "Date: %5\n" "\n" "%6\n" msgstr "" "\n" "Commentaire: %1\n" "\n" "Sur le billet: %2\n" "Sujet: %3\n" "De: %4\n" "Date: %5\n" "\n" "%6\n" #: plugins/Comment/lib/Jifty/Plugin/Comment/View.pm:165 msgid "Add a comment" msgstr "Ajouter un commentaire" #: plugins/Comment/t/TestApp-Plugin-Comments/lib/TestApp/Plugin/Comments/View.pm:22 #. ($blog->author) msgid "By %1" msgstr "Par %1" #: plugins/Comment/lib/Jifty/Plugin/Comment/View.pm:138 plugins/Comment/lib/Jifty/Plugin/Comment/View.pm:197 #. ($poster, $created_on->strftime('%A, %B %d, %Y @ %H:%M%P') #. ($poster, $created_on->strftime('%A, %B %d, %Y @ %H:%M%P') msgid "By %1 %2" msgstr "Par %1 %2" #: plugins/Comment/lib/Jifty/Plugin/Comment/View.pm:304 msgid "No one has made a comment yet." msgstr "Aucun commentaire pour l'instant" #: plugins/Comment/t/TestApp-Plugin-Comments/lib/TestApp/Plugin/Comments/View.pm:13 msgid "Post" msgstr "Poster" #: plugins/Comment/lib/Jifty/Plugin/Comment/View.pm:221 msgid "Preview" msgstr "Aperçu" #: plugins/Comment/lib/Jifty/Plugin/Comment/View.pm:236 msgid "Submit" msgstr "Soumettre" #: plugins/Comment/lib/Jifty/Plugin/Comment/Action/CreateComment.pm:268 msgid "Your comment has been added. If it does not immediately appear, it may have been flagged for moderation and should appear shortly." msgstr "Votre commentaire a été ajouté. S'il n'apparaît pas immédiatement, c'est qu'il est en attente de modération et sera bientôt publié." #: plugins/Comment/lib/Jifty/Plugin/Comment/Notification/CommentNeedsModeration.pm:67 #. ($appname, $comment->title) msgid "[%1] Moderate comment: %2" msgstr "[%1] Commentaire modéré : %2" #: plugins/Comment/lib/Jifty/Plugin/Comment/Notification/CommentPublished.pm:65 #. ($appname, $comment->title) msgid "[%1] New comment: %2" msgstr "[%1] Nouveau commentaire : %2" #: plugins/Comment/lib/Jifty/Plugin/Comment/View.pm:87 #. ($status) msgid "mark as %1" msgstr "marquer comme %1" #: plugins/Comment/lib/Jifty/Plugin/Comment/View.pm:100 msgid "publish" msgstr "publier" #: plugins/Comment/lib/Jifty/Plugin/Comment/View.pm:100 msgid "unpublish" msgstr "ne pas publier"