[Catalyst-commits] r6398 - in trunk: . Catalyst-View-Email Catalyst-View-Email/lib Catalyst-View-Email/lib/Catalyst Catalyst-View-Email/lib/Catalyst/Helper Catalyst-View-Email/lib/Catalyst/Helper/View Catalyst-View-Email/lib/Catalyst/Helper/View/Email Catalyst-View-Email/lib/Catalyst/View Catalyst-View-Email/lib/Catalyst/View/Email Catalyst-View-Email/t

jshirley at dev.catalyst.perl.org jshirley at dev.catalyst.perl.org
Sat May 12 20:10:41 GMT 2007


Author: jshirley
Date: 2007-05-12 20:10:40 +0100 (Sat, 12 May 2007)
New Revision: 6398

Added:
   trunk/Catalyst-View-Email/
   trunk/Catalyst-View-Email/MANIFEST
   trunk/Catalyst-View-Email/MANIFEST.SKIP
   trunk/Catalyst-View-Email/Makefile.PL
   trunk/Catalyst-View-Email/lib/
   trunk/Catalyst-View-Email/lib/Catalyst/
   trunk/Catalyst-View-Email/lib/Catalyst/Helper/
   trunk/Catalyst-View-Email/lib/Catalyst/Helper/View/
   trunk/Catalyst-View-Email/lib/Catalyst/Helper/View/Email.pm
   trunk/Catalyst-View-Email/lib/Catalyst/Helper/View/Email/
   trunk/Catalyst-View-Email/lib/Catalyst/Helper/View/Email/Template.pm
   trunk/Catalyst-View-Email/lib/Catalyst/View/
   trunk/Catalyst-View-Email/lib/Catalyst/View/Email.pm
   trunk/Catalyst-View-Email/lib/Catalyst/View/Email/
   trunk/Catalyst-View-Email/lib/Catalyst/View/Email/Template.pm
   trunk/Catalyst-View-Email/t/
   trunk/Catalyst-View-Email/t/lib/
Log:
Initial checkin of Catalyst::View::Email - suitable for developers to poke

Added: trunk/Catalyst-View-Email/MANIFEST
===================================================================
--- trunk/Catalyst-View-Email/MANIFEST	                        (rev 0)
+++ trunk/Catalyst-View-Email/MANIFEST	2007-05-12 19:10:40 UTC (rev 6398)
@@ -0,0 +1,7 @@
+lib/Catalyst/Helper/View/Email.pm
+lib/Catalyst/Helper/View/Email/Template.pm
+lib/Catalyst/View/Email.pm
+lib/Catalyst/View/Email/Template.pm
+Makefile.PL
+MANIFEST			This list of files
+META.yml

Added: trunk/Catalyst-View-Email/MANIFEST.SKIP
===================================================================
--- trunk/Catalyst-View-Email/MANIFEST.SKIP	                        (rev 0)
+++ trunk/Catalyst-View-Email/MANIFEST.SKIP	2007-05-12 19:10:40 UTC (rev 6398)
@@ -0,0 +1,41 @@
+# Avoid version control files.
+\bRCS\b
+\bCVS\b
+,v$
+\B\.svn\b
+
+# Avoid Makemaker generated and utility files.
+\bMakefile$
+\bblib
+\bMakeMaker-\d
+\bpm_to_blib$
+\bblibdirs$
+^MANIFEST\.SKIP$
+
+# Avoid Module::Build generated and utility files.
+\bBuild$
+\b_build
+
+# Avoid temp and backup files.
+~$
+\.tmp$
+\.old$
+\.bak$
+\#$
+\b\.#
+\.DS_Store$
+
+# Avoid Apache::Test files
+t/conf/apache_test_config.pm
+t/conf/extra.conf$
+t/conf/httpd.conf
+t/conf/mime.types
+t/htdocs
+t/logs
+t/var
+
+# No tarballs!
+\.gz$
+
+# Skip the roadmap
+lib/Catalyst/ROADMAP.pod

Added: trunk/Catalyst-View-Email/Makefile.PL
===================================================================
--- trunk/Catalyst-View-Email/Makefile.PL	                        (rev 0)
+++ trunk/Catalyst-View-Email/Makefile.PL	2007-05-12 19:10:40 UTC (rev 6398)
@@ -0,0 +1,14 @@
+use inc::Module::Install;
+
+name 'Catalyst-View-Email';
+all_from 'lib/Catalyst/View/Email.pm';
+
+requires 'Catalyst'             => '5.7';
+requires 'Class::C3';
+
+requires 'Email::Send'          => '2.185';
+requires 'Email::MIME'          => '1.859';
+requires 'Email::MIME::Creator' => '1.453';
+
+auto_install;
+WriteAll;

Added: trunk/Catalyst-View-Email/lib/Catalyst/Helper/View/Email/Template.pm
===================================================================
--- trunk/Catalyst-View-Email/lib/Catalyst/Helper/View/Email/Template.pm	                        (rev 0)
+++ trunk/Catalyst-View-Email/lib/Catalyst/Helper/View/Email/Template.pm	2007-05-12 19:10:40 UTC (rev 6398)
@@ -0,0 +1,85 @@
+package Catalyst::Helper::View::Email::Template;
+
+use strict;
+
+=head1 NAME
+
+Catalyst::Helper::View::Email::Template - Helper for Templated Email Views
+
+=head1 SYNOPSIS
+
+    script/create.pl view Template::Email Template::Email
+
+=head1 DESCRIPTION
+
+Helper for Template-based Email Views.
+
+=head2 METHODS
+
+=head3 mk_compclass
+
+=cut
+
+sub mk_compclass {
+    my ( $self, $helper ) = @_;
+    my $file = $helper->{file};
+    $helper->render_file( 'compclass', $file );
+}
+
+=head1 SEE ALSO
+
+L<Catalyst::View::Email>
+
+L<Catalyst::Manual>, L<Catalyst::Test>, L<Catalyst::Request>,
+L<Catalyst::Response>, L<Catalyst::Helper>
+
+=head1 AUTHOR
+
+J. Shirley C<jshirley at gmail.com>
+
+=head1 LICENSE
+
+This library is free software . You can redistribute it and/or modify
+it under the same terms as perl itself.
+
+=cut
+
+1;
+
+__DATA__
+
+__compclass__
+package [% class %];
+
+use strict;
+use base 'Catalyst::View::Email::Template';
+
+__PACKAGE__->config(
+    stash_key       => 'email',
+    template_prefix => ''
+);
+
+=head1 NAME
+
+[% class %] - Templated Email View for [% app %]
+
+=head1 DESCRIPTION
+
+View for sending template-generated email from [% app %]. 
+
+=head1 AUTHOR
+
+[% author %]
+
+=head1 SEE ALSO
+
+L<[% app %]>
+
+=head1 LICENSE
+
+This library is free software, you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
+
+1;

Added: trunk/Catalyst-View-Email/lib/Catalyst/Helper/View/Email.pm
===================================================================
--- trunk/Catalyst-View-Email/lib/Catalyst/Helper/View/Email.pm	                        (rev 0)
+++ trunk/Catalyst-View-Email/lib/Catalyst/Helper/View/Email.pm	2007-05-12 19:10:40 UTC (rev 6398)
@@ -0,0 +1,84 @@
+package Catalyst::Helper::View::Email;
+
+use strict;
+
+=head1 NAME
+
+Catalyst::Helper::View::Email - Helper for Email Views
+
+=head1 SYNOPSIS
+
+    script/create.pl view Email Email
+
+=head1 DESCRIPTION
+
+Helper for Email Views.
+
+=head2 METHODS
+
+=head3 mk_compclass
+
+=cut
+
+sub mk_compclass {
+    my ( $self, $helper ) = @_;
+    my $file = $helper->{file};
+    $helper->render_file( 'compclass', $file );
+}
+
+=head1 SEE ALSO
+
+L<Catalyst::View::Email>
+
+L<Catalyst::Manual>, L<Catalyst::Test>, L<Catalyst::Request>,
+L<Catalyst::Response>, L<Catalyst::Helper>
+
+=head1 AUTHOR
+
+J. Shirley C<jshirley at gmail.com>
+
+=head1 LICENSE
+
+This library is free software . You can redistribute it and/or modify
+it under the same terms as perl itself.
+
+=cut
+
+1;
+
+__DATA__
+
+__compclass__
+package [% class %];
+
+use strict;
+use base 'Catalyst::View::Email';
+
+__PACKAGE__->config(
+    stash_key => 'email'
+);
+
+=head1 NAME
+
+[% class %] - Email View for [% app %]
+
+=head1 DESCRIPTION
+
+View for sending email from [% app %]. 
+
+=head1 AUTHOR
+
+[% author %]
+
+=head1 SEE ALSO
+
+L<[% app %]>
+
+=head1 LICENSE
+
+This library is free software, you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
+
+1;

Added: trunk/Catalyst-View-Email/lib/Catalyst/View/Email/Template.pm
===================================================================
--- trunk/Catalyst-View-Email/lib/Catalyst/View/Email/Template.pm	                        (rev 0)
+++ trunk/Catalyst-View-Email/lib/Catalyst/View/Email/Template.pm	2007-05-12 19:10:40 UTC (rev 6398)
@@ -0,0 +1,182 @@
+package Catalyst::View::Email::Template;
+
+use warnings;
+use strict;
+
+use Class::C3;
+use Carp;
+
+use Email::MIME::Creator;
+
+use base qw|Catalyst::View::Email|;
+
+our $VERSION = '0.01';
+
+=head1 NAME
+
+Catalyst::View::Email::Template - Send Templated Email from Catalyst
+
+=head1 SYNOPSIS
+
+Sends Templated mail, based upon your Default View.  Will capture the output
+of the rendering path, slurps in based on mime-types and assembles a multi-part
+email and sends it out.
+
+=head2 CONFIGURATION
+
+    View::Email::Template:
+        # Set it up so if you have multiple parts, they're alternatives.
+        # This is on the top-level message, not the individual parts.
+        content_type: multipart/alternative
+        # Optional prefix to look somewhere under the existing configured
+        # template  paths.
+        template_prefix: email
+        # Where to look in the stash for the email information
+        stash_key: email
+        # Setup how to send the email
+        sender:
+            method:     SMTP
+            host:       smtp.myhost.com
+            username:   username
+            password:   password
+
+=head1 SENDING EMAIL
+
+Sending email is just setting up your stash key, and forwarding to the view.
+
+    $c->stash->{email} = {
+        to      => 'jshirley at gmail.com',
+        from    => 'no-reply at foobar.com',
+        subject => 'I am a Catalyst generated email',
+        # Specify which templates to include
+        templates => [
+            qw{text_plain/test.tt},
+            qw{text_html/test.tt}
+        ]
+    };
+    $c->forward('View::Email::Template');
+
+If it fails $c->error will have the error message.
+
+=cut
+
+__PACKAGE__->config(
+    template_prefix => '',
+);
+
+
+# This view hitches into your default view and will call the render function
+# on the templates provided.  This means that you have a layer of abstraction
+# and you aren't required to modify your templates based on your desired engine
+# (Template Toolkit or Mason, for example).  As long as the view adequately
+# supports ->render, all things are good.  Mason, and others, are not good.
+
+#
+# The path here is to check configuration for the template root, and then
+# proceed to call render on the subsequent templates and stuff each one
+# into an Email::MIME container.  The mime-type will be stupidly guessed with
+# the subdir on the template.
+#
+# TODO: Make this unretarded.
+#
+sub process {
+    my ( $self, $c ) = @_;
+
+    my $stash_key       = $self->config->{stash_key} || 'email';
+
+    croak "No template specified for rendering"
+        unless $c->stash->{$stash_key}->{template} or
+                $c->stash->{$stash_key}->{templates};
+
+    # Where to look
+    my $template_prefix = $self->config->{template_prefix};
+    my @templates = ();
+    if ( $c->stash->{$stash_key}->{templates} ) {
+        push @templates, map {
+            join('/', $template_prefix, $_);
+        } @{$c->stash->{$stash_key}->{templates}};
+
+    } else {
+        push @templates, join('/', $template_prefix,
+            $c->stash->{$stash_key}->{template});
+    }
+   
+    my $default_view = $c->view( $self->config->{default_view} );
+
+    unless ( $default_view->can('render') ) {
+        croak "Email::Template's configured view does not have a render method!";
+    }
+
+    #$c->log->_dump($default_view->config);
+
+    my @parts = (); 
+    foreach my $template ( @templates ) {
+        $template =~ s#^/+##; # Make sure that we don't have an absolute path.
+        # This seems really stupid to me... argh.  will give me nightmares!
+        my $template_path = $template;
+            $template_path =~ s#^$template_prefix/##;
+        my ( $content_type, $extra ) = split('/', $template_path);
+        if ( $extra ) {
+            $content_type ||= 'text/plain';
+            $content_type =~  s#_#/#;
+        } else {
+            $content_type = 'text/plain';
+        }
+        my $output = $default_view->render( $c, $template,
+            { content_type => $content_type });
+        # Got a ref, not a scalar.  An error!
+        if ( ref $output ) {
+            croak $output->can("as_string") ? $output->as_string : $output;
+        }
+        push @parts, Email::MIME->create(
+            attributes => {
+                content_type => $content_type
+            },
+            body => $output
+        );
+    }
+    delete $c->stash->{email}->{body};
+    $c->stash->{email}->{parts} ||= [];
+    push @{$c->stash->{email}->{parts}}, @parts;
+
+    # Let C::V::Email do the actual sending.  We just assemble the tasty bits.
+    return $self->next::method($c);
+}
+
+=head1 TODO
+
+=head2 ATTACHMENTS
+
+There needs to be a method to support attachments.  What I am thinking is
+something along these lines:
+    attachments => [
+        # Set the body to a file handle object, specify content_type and
+        # the file name. (name is what it is sent at, not the file)
+        { body => $fh, name => "foo.pdf", content_type => "application/pdf" },
+        # Or, specify a filename that is added, and hey, encoding!
+        { filename => "foo.gif", name => "foo.gif", content_type => "application/pdf", encoding => "quoted-printable" },
+        # Or, just a path to a file, and do some guesswork for the content type
+        "/path/to/somefile.pdf",
+    ]
+
+=head1 SEE ALSO
+
+=head2 L<Catalyst::View::Email> - Send plain boring emails with Catalyst
+
+=head2 L<Catalyst::Manual> - The Catalyst Manual
+
+=head2 L<Catalyst::Manual::Cookbook> - The Catalyst Cookbook
+
+=head1 AUTHORS
+
+J. Shirley <jshirley at gmail.com>
+
+=head1 LICENSE
+
+This library is free software, you can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=cut
+
+1;
+

Added: trunk/Catalyst-View-Email/lib/Catalyst/View/Email.pm
===================================================================
--- trunk/Catalyst-View-Email/lib/Catalyst/View/Email.pm	                        (rev 0)
+++ trunk/Catalyst-View-Email/lib/Catalyst/View/Email.pm	2007-05-12 19:10:40 UTC (rev 6398)
@@ -0,0 +1,201 @@
+package Catalyst::View::Email;
+
+use warnings;
+use strict;
+
+use Carp;
+
+use Email::Send;
+use Email::MIME::Creator;
+
+use base qw|Catalyst::View|;
+
+our $VERSION = '0.01';
+
+__PACKAGE__->mk_accessors('mailer');
+
+=head1 NAME
+
+Catalyst::View::Email - Send Email from Catalyst
+
+=head1 SYNOPSIS
+
+This module simply sends out email from a stash key specified in the
+configuration settings.
+
+=head1 CONFIGURATION
+
+In your app configuration (example in L<YAML>):
+    View::Email:
+        stash_key: email
+        content_type: text/plain 
+        sender:
+            method:     SMTP
+            host:       smtp.myhost.com
+            username:   username
+            password:   password
+
+=cut
+
+__PACKAGE__->config(
+    stash_key => 'email',
+);
+
+=head1 SENDING EMAIL
+
+In your controller, simply forward to the view after populating the C<stash_key>
+
+    sub controller : Private {
+        my ( $self, $c ) = @_;
+        $c->stash->{email} = {
+            to      => qq{catalyst at rocksyoursocks.com},
+            from    => qq{no-reply at socksthatarerocked.com},
+            subject => qq{Your Subject Here},
+            body    => qq{Body Body Body}
+        };
+        $c->forward('View::Email');
+    }
+
+Alternatively, you can use a more raw interface, and specify the headers as
+an array reference.
+
+    $c->stash->{email} = {
+        header => [
+            To      => 'foo at bar.com',
+            Subject => 'Note the capitalization differences'
+        ],
+        body => qq{Ain't got no body, and nobody cares.},
+        # Or, send parts
+        parts => [
+            Email::MIME->create(
+                attributes => {
+                    content_type => 'text/plain',
+                    disposition  => 'attachment',
+                    charset      => 'US-ASCII',
+                },
+                body => qq{Got a body, but didn't get ahead.}
+            )
+        ],
+    };
+
+=head1 HANDLING FAILURES
+
+If the email fails to send, the view will die (throw an exception).  After
+your forward to the view, it is a good idea to check for errors:
+    
+    $c->forward('View::Email');
+    if ( scalar( @{ $c->error } ) ) {
+        $c->error(0); # Reset the error condition if you need to
+        $c->res->body('Oh noes!');
+    } else {
+        $c->res->body('Email sent A-OK! (At least as far as we can tell)');
+    }
+
+=head1 OTHER MAILERS
+
+Now, it's no fun to just send out email using plain strings.  We also have
+L<Catalyst::View::Email::TT> for use.  You can also toggle this as being used
+by setting up your configuration to look like this:
+
+    View::Email:
+        default: TT
+
+Then, Catalyst::View::Email will forward to View::Email::TT by default.
+
+=cut
+
+sub new {
+    my ( $class ) = shift;
+    my $self = $class->next::method(@_);
+
+    my $mailer = Email::Send->new;
+
+    if ( my $method = $self->config->{sender}->{method} ) {
+        croak "$method is not supported, see Email::Send"
+            unless $mailer->mailer_available($method);
+        $mailer->mailer($method);
+    } else {
+        # Default case, run through the most likely options first.
+        for ( qw/SMTP Sendmail Qmail/ ) {
+            $mailer->mailer($_) and last if $mailer->mailer_available($_);
+        }
+    }
+
+    if ( $mailer->mailer eq 'SMTP' ) {
+        my $host = $self->config->{sender}->{host} || 'localhost';
+        $mailer->mailer_args([ Host => $host ]);
+    }
+
+    $self->mailer($mailer);
+
+    return $self;
+}
+
+sub process {
+    my ( $self, $c ) = @_;
+
+    croak "Unable to send mail, bad mail configuration"
+        unless $self->mailer;
+
+    my $email  = $c->stash->{$self->config->{stash_key}};
+    croak "Can't send email without a valid email structure"
+        unless $email;
+    
+    if ( $self->config->{content_type} ) {
+        $email->{content_type} ||= $self->config->{content_type};
+    }
+
+    my $header  = $email->{header} || [];
+        push @$header, ('To' => delete $email->{to})
+            if $email->{to};
+        push @$header, ('From' => delete $email->{from})
+            if $email->{from};
+        push @$header, ('Subject' => delete $email->{subject})
+            if $email->{subject};
+        push @$header, ('Content-type' => delete $email->{content_type})
+            if $email->{content_type};
+
+    my $parts = $email->{parts};
+    my $body  = $email->{body};
+   
+    unless ( $parts or $body ) {
+        croak "Can't send email without parts or body, check stash";
+    }
+
+    my %mime = ( header => $header );
+
+    if ( $parts and ref $parts eq 'ARRAY' ) {
+        $mime{parts} = $parts;
+    } else {
+        $mime{body} = $body;
+    }
+
+    my $message = Email::MIME->create(%mime);
+
+    if ( $message ) {
+        $self->mailer->send($message);
+    } else {
+        croak "Unable to create message";
+    }
+}
+
+=head1 SEE ALSO
+
+=head2 L<Catalyst::View::Email::Template> - Send fancy template emails with Cat
+
+=head2 L<Catalyst::Manual> - The Catalyst Manual
+
+=head2 L<Catalyst::Manual::Cookbook> - The Catalyst Cookbook
+
+=head1 AUTHORS
+
+J. Shirley <jshirley at gmail.com>
+
+=head1 LICENSE
+
+This library is free software, you can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=cut
+
+1;




More information about the Catalyst-commits mailing list