Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Bricolage: commits

[8511] Added the `find_or_create_alternate()` method to

 

 

Bricolage commits RSS feed   Index | Next | Previous | View Threaded


theory at bricolage

Mar 19, 2009, 9:38 PM

Post #1 of 1 (485 views)
Permalink
[8511] Added the `find_or_create_alternate()` method to

Revision: 8511
Author: theory
Date: 2009-03-19 21:38:45 -0700 (Thu, 19 Mar 2009)
ViewCVS: http://viewsvn.bricolage.cc/?rev=8511&view=rev

Log Message:
-----------
Added the `find_or_create_alternate()` method to Bric::Biz::Asset::Business::Media::Image. This method is designed to make it easier for template writers to create alternate versions of images, such as thumbnails, and get them published on the site. It does all the right things to make sure that permissions are correct, etc., so it should be safer to use than some of the old template approaches. In the process, I made a number of other changes:

* Calls to `log_event()` are immediately logged when not running under mod_perl or bric_queued. This is so that events will now always be properly logged.
* Added a new test class, Bric::Biz::Asset::Business::Media::Image::DevTest, which inherits from Bric::Biz::Asset::Business::Media::DevTest and adds a bunch of tests for its own for thumbnail and `find_or_create_alternate()` support.
* Imager is now a required module.
* USE_THUMBNAILS is now enabled by default.
* Got rid of unnecessary overriding of category concatenation in `test_upload_before_save()` in Bric::Biz::Asset::Business::Media::DevTest. Now that it's actually testing images, it also implicitly tests autopopulated fields, and it was failing with that hackery.
* Also switched that test to test an actual PNG file rather than itself, again since it needs to deal with an actual image.
* Added the following aliases, so I can pretend that the versions with double underscores don't exist:
* `Bric::Biz::Asset::Business::set_source_id()`
* `Bric::Biz::Asset::Business::get_source_id()`
* `Bric::Biz::Asset::get_user_id()`
* `Bric::Biz::Asset::Business::Media::get_category_id()`
* Modified `create_thumbnail()` in Bric::Biz::Asset::Business::Media::Image to use the same code as the new `find_or_create_alternate()` method.
* Modified `Bric::Biz::Asset::Business::Media::upload_file()` to work with an Imager object as well as a file handle.
* Fixed `Bric::Biz::Asset::Business::Media::upload_file()` so that it saves autopopulated fields only if the media object has an ID. This avoids an error during testing, and is smarter, anyway.
* Stopped importing `get_user_id()` from Bric::App::Session into Bric::Biz::Asset::Business::Media, as it was stupid and getting in the way of the new `get_user_id()` method inherited from Bric::Biz::Asset.
* Bric::Biz::Person::User now caches an empty ACL instead of loading it over and over again. Probably doesn't happen often, but will prevent some extra queries.
* Fixed a new test failure in Bric::Biz::Category::DevTest where Bric::Biz::Category was attempting to modify a read-only value.
* Various minor whitespace fixes.
* Fixed some scoping issues in Bric::Biz::Asset::Business::Media::DevTest that showed up because the test methods there are now all run twice. There were a bunch of package-scoped variables that were used in only one method, and caused problems when that method was run twice.
* Fixed a compatibility issue in Bric::Dist::Action::DTDValidate. Apparently `get_last_error()` was removed from XML::LibXML 1.59 "for thread-saftey reasons." I believe that this revision is backward-compatible. Do let me know if you find otherwise.

Modified Paths:
--------------
bricolage/trunk/conf/bricolage.conf
bricolage/trunk/lib/Bric/Admin.pod
bricolage/trunk/lib/Bric/App/Event.pm
bricolage/trunk/lib/Bric/Biz/Asset/Business/Media/Image.pm
bricolage/trunk/lib/Bric/Biz/Asset/Business/Media.pm
bricolage/trunk/lib/Bric/Biz/Asset/Business.pm
bricolage/trunk/lib/Bric/Biz/Asset.pm
bricolage/trunk/lib/Bric/Biz/Person/User.pm
bricolage/trunk/lib/Bric/Changes.pod
bricolage/trunk/lib/Bric/Config.pm
bricolage/trunk/lib/Bric/Dist/Action/DTDValidate.pm
bricolage/trunk/lib/Bric/Util/Language/de_de.pm
bricolage/trunk/lib/Bric/Util/Language/en_us.pm
bricolage/trunk/lib/Bric/Util/Language/it_it.pm
bricolage/trunk/lib/Bric/Util/Language/pt_pt.pm
bricolage/trunk/lib/Bric/Util/Language/ru_ru.pm
bricolage/trunk/lib/Bric/Util/Language/zh_cn.pm
bricolage/trunk/lib/Bric/Util/Language/zh_tw.pm
bricolage/trunk/t/Bric/Biz/Asset/Business/Media/DevTest.pm
bricolage/trunk/t/Bric/Biz/Category/DevTest.pm

Added Paths:
-----------
bricolage/trunk/t/Bric/Biz/Asset/Business/Media/Image/
bricolage/trunk/t/Bric/Biz/Asset/Business/Media/Image/DevTest.pm
bricolage/trunk/t/Bric/Biz/Asset/Business/Media/Image/simpsonized.png

Modified: bricolage/trunk/conf/bricolage.conf
===================================================================
--- bricolage/trunk/conf/bricolage.conf 2009-03-16 17:06:28 UTC (rev 8510)
+++ bricolage/trunk/conf/bricolage.conf 2009-03-20 04:38:45 UTC (rev 8511)
@@ -460,7 +460,7 @@
# giflib, jpeg requires libjpeg, png requires libpng, etc. Consult Imager's
# README for more information.

-USE_THUMBNAILS = No
+USE_THUMBNAILS = Yes
THUMBNAIL_SIZE = 75

##

Modified: bricolage/trunk/lib/Bric/Admin.pod
===================================================================
--- bricolage/trunk/lib/Bric/Admin.pod 2009-03-16 17:06:28 UTC (rev 8510)
+++ bricolage/trunk/lib/Bric/Admin.pod 2009-03-20 04:38:45 UTC (rev 8511)
@@ -443,6 +443,8 @@

=item Clone

+=item Imager
+
=item HTML::Template (optional)

=item HTML::Template::Expr (optional)
@@ -465,8 +467,6 @@

=item Crypt::SSLeay (optional)

-=item Imager (optional)
-
=item Text::Aspell (optional)

=item XML::DOM (optional)
@@ -2442,7 +2442,7 @@
files. See F<contrib/copy_gnome_icons> for a scipt to copy GNOME icons into
the Bricolage root for use in the UI. Only one icon is included by default,
with thanks to the KDE project's license for the graphic
-(L<http://artist.kde.org/new/license.html#others>). Disabled by default.
+(L<http://artist.kde.org/new/license.html#others>). Enabled by default.

=item *


Modified: bricolage/trunk/lib/Bric/App/Event.pm
===================================================================
--- bricolage/trunk/lib/Bric/App/Event.pm 2009-03-16 17:06:28 UTC (rev 8510)
+++ bricolage/trunk/lib/Bric/App/Event.pm 2009-03-20 04:38:45 UTC (rev 8511)
@@ -145,6 +145,7 @@
user => get_user_object,
timestamp => strfdate(),
};
+ commit_events() unless Bric::Config::MOD_PERL || $ENV{BRIC_QUEUED};
}

=item my $bool = commit_events()

Modified: bricolage/trunk/lib/Bric/Biz/Asset/Business/Media/Image.pm
===================================================================
--- bricolage/trunk/lib/Bric/Biz/Asset/Business/Media/Image.pm 2009-03-16 17:06:28 UTC (rev 8510)
+++ bricolage/trunk/lib/Bric/Biz/Asset/Business/Media/Image.pm 2009-03-20 04:38:45 UTC (rev 8511)
@@ -54,8 +54,11 @@
use base qw( Bric::Biz::Asset::Business::Media );
use Bric::Config qw(:media :thumb);
use Bric::App::Util ();
-use Bric::Util::Fault qw(throw_error throw_gen);
-require Imager if USE_THUMBNAILS;
+use Bric::App::Event ();
+use Bric::Biz::Workflow qw(MEDIA_WORKFLOW);
+use Bric::Util::Priv::Parts::Const qw(:all);
+use Bric::Util::Fault qw(throw_error throw_gen throw_forbidden);
+use Imager;

#==============================================================================#
# Function Prototypes #
@@ -365,6 +368,327 @@
);
}

+##############################################################################
+
+=item my $new_img = $image->find_or_create_alternate(\%params)
+
+ my $new_image = $image->find_or_create_alternate({
+ file_suffix => '_alt',
+ et_key_name => 'thumb',
+ user => $user,
+ relate => 0,
+ transformer => sub {
+ shift->scale( xpixels => 115 )->crop( top => 76 );
+ },
+ });
+
+Creates an alternate representation of the current image document and returns
+it. This is useful for creating thumbnails and the like. Note that the user
+must have CREATE access to the start desk in the first available workflow.
+
+The first thing this method does is see if a likely alternate already exists
+by looking for a media document in the same site, with the appropriate URI (as
+formed by the current media document's category, cover date, and file name as
+modified by the C<file_prefix> and C<file_suffix> parameters), and based on
+the appropriate element type. If such a media document is found, it is simply
+returned and no further actions are taken.
+
+If such a media document does I<not> exist, C<find_or_create_alternate()>
+creates it, moves it into workflow, takes other actions as determined by the
+parameters, and returns it.
+
+It's important to get the parameters right in order to properly find or create
+the alternate representation of an image that you need for your site. So read
+these descriptions carefully!
+
+=over
+
+=item title_prefix
+
+=item title_suffix
+
+Strings to add to the beginning and/or end of the media document's title to
+create a new title for the new media document. They will also be used to
+modify the image description. The prefex defaults to "Thumbnail for " while
+the suffix defaults to an empty string.
+
+=item file_prefix
+
+=item file_suffix
+
+String to add to the beginning and/end of the media document's file name to
+create a new document's file name. The prefix defaults to the empty string
+while the suffix defaults to "_thumb". The resulting file name will be used
+both to search for an exsting image with this file name and, if there isn't
+one, to provide the file name for the new image document.
+
+Note that the suffix will be inserted into the file name I<before> the file
+name extension. For example, F<foo.png> will become F<foo_thumb.png>, not
+F<foo.png_thumb>.
+
+=item user
+
+The user who will "create" the new media document. Defaults to the current
+user. Useful in templates to provide a user who might have more extensive
+permissions than the current user.
+
+=item element_type
+
+The media element type on which the alternate will be based. Also used to find
+an existing media document.
+
+=item et_key_name
+
+The key name for the element type on which the alternate will be based. Also
+used to find an existing media document. If both C<element> and C<et_key_name>
+are passed, C<et_key_name> will be used.
+
+=item transformer
+
+A code reference that expects a single argument, an L<Imager|Imager> object,
+and returns an L<Imager|Imager> object. Use this code reference to transform
+the media document file into a new file to be used for the alternate. For
+example, if you wanted to create a new image that's 115 pixels wide and crops
+the image to get only the top 76 pixels, you can pass something like this:
+
+ transformer => sub {
+ shift->scale( xpixels => 115 )->crop( top => 76 );
+ },
+
+Consult the L<Imager|Imager> documentation, and especially
+L<Imager::Transformations|Imager::Transformations>, for its complete API,
+examples, etc. Note taht the C<transformer> code reference will only be called
+if the alternate does not already exist.
+
+=item width
+
+=item height
+
+The height and width, in pixels, to make the alternate image. Only used if an
+existing image is not found, and if the C<transformer> parameter has not been
+passed.
+
+=item use_thumb
+
+Boolean indicating whether or not to use the thumbnail file to create the
+alternate document. If true, the C<transform>, C<width>, and C<height>
+parameters will be ignored and the existing thumbnail file will simply be
+used. Defaults to false.
+
+=item relate
+
+Boolean to indicate whether or not to relate the new image, if one is created
+to the current image. If true, and an alternate is created, it will be added
+as a related media document to the original media document's top-level
+element. Defaults to true.
+
+=item checkin
+
+Boolean to indicate whether or not to check in the newly created alternate
+image document. Defaults to true.
+
+=item move_to_pub
+
+Boolean to indicate whether or not to move in the newly created alternate
+image document to a publish desk. Defaults to true. Note that the user must
+have READ access to a PUBLISH desk or else an exception will be thrown.
+
+=back
+
+B<Throws:> Exceptions when the user does not have permission to create a media
+document in a media workflow, or does not have permission to move it to a
+publish desk, or if the necessary libraries to support the desired
+transformations are not included in the L<Imager|Imager> build.
+
+B<Side Effects:> If no alternate can be found, a new media document will be
+created, put into workflow, and possibly checked in and moved to the publish
+desk.
+
+B<Notes:> Isn't the above enough?
+
+=cut
+
+sub find_or_create_alternate {
+ my ($self, $p) = @_;
+
+ # Dupe the parameters.
+ $p = { %{ $p } };
+
+ for my $spec (
+ [ title_prefix => 'Thumbnail for ' ],
+ [ title_suffix => '' ],
+ [ file_prefix => '' ],
+ [ file_suffix => '_thumb' ],
+ [ checkin => 1 ],
+ [ relate => 1 ],
+ [ move_to_pub => 1 ],
+ ) {
+ $p->{ $spec->[0] } = $spec->[1] unless exists $p->{ $spec->[0] };
+ }
+
+ my $et_key_name = $p->{et_key_name} || (
+ $p->{element_type}
+ ? $p->{element_type}->get_key_name
+ : $self->get_element_key_name
+ );
+
+ # Construct a URI for the alternate image.
+ my $image_fn = $self->get_file_name;
+ (my $alt_fn = $p->{file_prefix} . $image_fn)
+ =~ s{(\.[^.\\/]+)$}{$p->{file_suffix}$1}gs;
+ (my $uri = URI::Escape::uri_unescape($self->get_uri))
+ =~ s{\Q$image_fn\E$}{$alt_fn};
+
+ # Return it if it already exists.
+ my ($alt) = ref($self)->list({
+ site_id => $self->get_site_id,
+ uri => $uri,
+ element_type => $et_key_name,
+ });
+ return $alt if $alt;
+
+ # Temporarily replace the session user object.
+ local $HTML::Mason::Commands::session{_bric_user}->{object} = $p->{user}
+ if $p->{user};
+ my $user = Bric::App::Util::get_user_object;
+
+ # Figure out what element type to use.
+ my $et = $p->{et_key_name}
+ ? Bric::Biz::ElementType->lookup({ key_name => $p->{et_key_name} })
+ : $p->{element_type} || $self->get_element_type;
+
+ # Create a new media document.
+ $alt = ref($self)->new({
+ priority => $self->get_priority,
+ title => $p->{title_prefix} . $self->get_title . $p->{title_suffix},
+ description => $p->{title_prefix} . ($self->get_description || '') . $p->{title_suffix},
+ site_id => $self->get_site_id,
+ source__id => $self->get_source__id,
+ media_type_id => $self->get_media_type->get_id,
+ category__id => $self->get_category__id,
+ element_type => $et,
+ user__id => $user->get_id,
+ });
+
+ $alt->set_cover_date($self->get_cover_date(Bric::Config::ISO_8601_FORMAT));
+
+ # Find and associate a workflow and desk.
+ my $wf = $self->get_workflow_object;
+ my $desk;
+ if ($wf) {
+ if ($user->what_can(undef, READ, $wf->get_asset_grp_id, $wf->get_grp_ids) >= READ) {
+ $desk = $wf->get_start_desk;
+ unless ($user->what_can(
+ 'Bric::Biz::Asset::Business::Media',
+ $desk->get_asset_grp,
+ ) >= CREATE) {
+ # No CREATE access to the start desk.
+ $desk = $wf = undef;
+ }
+ } else {
+ $wf = undef;
+ }
+ }
+ unless ($wf) {
+ for my $w (Bric::Biz::Workflow->list({
+ site_id => $self->get_site_id,
+ type => MEDIA_WORKFLOW,
+ })) {
+ next unless $user->what_can(undef, READ, $w->get_asset_grp_id, $w->get_grp_ids) >= READ;
+ next unless $user->what_can(
+ 'Bric::Biz::Asset::Business::Media',
+ $w->get_start_desk->get_asset_grp,
+ ) >= CREATE;
+ $wf = $w;
+ $desk = $wf->get_start_desk;
+ }
+ }
+ throw_forbidden(
+ error => 'You do not have sufficient permission to create a media document for this site',
+ maketext => [.'You do not have sufficient permission to create a media document for this site'],
+ ) unless $wf && $desk;
+
+ # Set the start desk and the workflow.
+ $alt->set_workflow_id($wf->get_id);
+ $alt->save;
+ $desk->accept({ asset => $alt });
+ $desk->save;
+
+ # Associate an image file.
+ if (USE_THUMBNAILS && $p->{use_thumb}) {
+ # Add the thumbnail image file to the media document.
+ my $path = $self->_thumb_file;
+ open my $alt_fh, '<', $path or die "Cannot open '$path': $!\n";
+ $alt->upload_file($alt_fh => $alt_fn);
+ close $alt_fh;
+ } else {
+ # Transform the existing image.
+ my $img = $self->_modify_image($p);
+ $alt->upload_file($img => $alt_fn);
+ }
+
+ # Save the new image.
+ $alt->save;
+
+ # Log that a new media has been created and generally handled.
+ Bric::App::Event::log_event('media_new', $alt);
+ Bric::App::Event::log_event('media_add_workflow', $alt, { Workflow => $wf->get_name });
+ Bric::App::Event::log_event('media_moved', $alt, { Desk => $desk->get_name });
+ Bric::App::Event::log_event('media_save', $alt);
+
+ # Add the alternate to the media document and return it.
+ $self->get_element->set_related_media($alt)->save if $p->{relate};
+
+ if ($p->{checkin}) {
+ # Go ahead and check it in.
+ $alt->checkin;
+ Bric::App::Event::log_event('media_checkin', $alt);
+ }
+
+ if ($p->{move_to_pub}) {
+ # We want to move it to a publish desk.
+ my $pub_desk;
+ if ($desk->can_publish) {
+ $pub_desk = $desk;
+ } else {
+ # Find pub desk in the workflow to which the user has READ access.
+ for my $d (reverse $wf->allowed_desks) {
+ if ($d->can_publish && $user->what_can(undef, READ, $d->get_asset_grp) >= READ) {
+ $pub_desk = $d;
+ last;
+ }
+ }
+ throw_forbidden(
+ error => sprintf(
+ 'You do not have READ acces to any desks in the "%s" workflow',
+ $wf->get_name
+ ),
+ maketext => [
+ 'You do not have [_1] access to any desks in the "[_2]" workflow',
+ 'READ', $wf->get_name,
+ ]
+ ) unless $pub_desk;
+ }
+
+ if ($pub_desk->get_id != $desk->get_id) {
+ # Move it to the new desk.
+ $desk->transfer({
+ to => $pub_desk,
+ asset => $alt,
+ });
+
+ # Save both desks.
+ $desk->save;
+ $pub_desk->save;
+ Bric::App::Event::log_event('media_moved', $alt, { Desk => $pub_desk->get_name });
+ }
+ }
+
+ # Save and return.
+ $alt->save if $p->{checkin} || $p->{move_to_pub};
+ return $alt;
+}
+
###################################################################### ##########

=item my $created_ok = $image->create_thumbnail
@@ -384,58 +708,29 @@
return unless USE_THUMBNAILS;
my $self = shift;
my $just_uploaded = shift;
- my $path = $self->get_path or return;
+ my $img = $self->_modify_image({
+ warn => 1,
+ just_uploaded => $just_uploaded,
+ transformer => sub {
+ my $img = shift;
+ # If either dimension is greather than the thumbnail size, create a
+ # smaller version by scaling largest side to THUMBNAIL_SIZE
+ return $img unless $img->getwidth > THUMBNAIL_SIZE;

- # Get the media format. Try using the MIME type, and fall back on what Imager
- # guesses.
- my $format;
- if (my $mime = $self->get_media_type) {
- (my $mt = $mime->get_name) =~ s|.*/||;
- $format = $Imager::FORMATGUESS->(".$mt") || $Imager::FORMATGUESS->($path);
- } else {
- $format = $Imager::FORMATGUESS->($path);
- }
+ return $img->scale(
+ xpixels => THUMBNAIL_SIZE,
+ ypixels => THUMBNAIL_SIZE,
+ type => 'min',
+ );
+ },
+ });

- # Just warn and retrun if we can't tell what format of file this is.
- unless ($format) {
- warn "Imager does not recognize the format file '$path'. No "
- . "thumbnail will be created.\n";
- return;
- }
-
- # Just warn and return if Imager doesn't support the format.
- unless ($Imager::formats{$format}) {
- warn qq{It looks like the image library to handle the "$format" }
- . ' format is not installed. No thumbnail will be created for file '
- . "'$path'.\n";
- return;
- }
-
- my $img = Imager->new;
- unless ( $img->open(file => $path, type => $format) ) {
- warn 'Error creating a thumbnail for "', $self->get_uri, '": ',
- $img->errstr, $/;
- Bric::App::Util::add_msg(
- 'Could not create a thumbnail for [_1]: [_2]',
- $self->get_uri,
- $img->errstr,
- ) if $just_uploaded;
- return;
- }
-
- # If either dimension is greather than the thumbnail size, create a
- # smaller version by scaling largest side to THUMBNAIL_SIZE
- if ($img->getwidth > THUMBNAIL_SIZE || $img->getheight > THUMBNAIL_SIZE) {
- $img = $img->scale(xpixels => THUMBNAIL_SIZE,
- ypixels => THUMBNAIL_SIZE,
- type => 'min');
- }
-
# Save the image or die.
my $thumbfile = $self->_thumb_file;
- $img->write(file => $thumbfile)
- or throw_gen error => "Imager cannot write '$thumbfile'",
- payload => $img->errstr;
+ $img->write(file => $thumbfile) or throw_gen(
+ error => "Imager cannot write '$thumbfile'",
+ payload => $img->errstr
+ );
return $self;
}

@@ -463,7 +758,7 @@
sub upload_file {
my $self = shift;
$self->SUPER::upload_file(@_);
- $self->create_thumbnail(1) if USE_THUMBNAILS;
+ $self->create_thumbnail(1) if USE_THUMBNAILS && !$self->_get('_upload_data');
return $self;
}

@@ -514,6 +809,70 @@
return Bric::Util::Trans::FS->cat_file(MEDIA_FILE_ROOT, $loc);
}

+sub _modify_image {
+ my ($self, $p) = @_;
+
+ # Get the media format. Try using the MIME type, and fall back on what Imager
+ # guesses.
+ my $path = $self->get_path or return;
+ my $format;
+ if (my $mime = $self->get_media_type) {
+ (my $mt = $mime->get_name) =~ s{.*/}{};
+ $format = $Imager::FORMATGUESS->(".$mt") || $Imager::FORMATGUESS->($path);
+ } else {
+ $format = $self::FORMATGUESS->($path);
+ }
+
+ unless ($format) {
+ throw_gen( "Imager does not recognize the format of file “$path”" )
+ unless $p->{warn};
+ warn "Imager does not recognize the format file '$path'. No "
+ . "thumbnail will be created.\n";
+ return;
+ }
+
+ unless ($Imager::formats{$format}) {
+ throw_gen(
+ qq{It looks like the image library to handle the “$format” format is not installed.\n}
+ ) unless $p->{warn};
+ warn qq{It looks like the image library to handle the "$format" }
+ . ' format is not installed. No thumbnail will be created for file '
+ . "'$path'.\n";
+ return;
+ }
+
+ # Create the Imager object.
+ my $img = Imager->new;
+ unless ( $img->open(file => $path, type => $format) ) {
+ throw_gen(
+ error => 'Error creating a thumbnail for "', $self->get_uri, '"',
+ payload => $img->errstr
+ ) unless $p->{warn};
+ warn 'Error creating a thumbnail for "', $self->get_uri, '": ',
+ $img->errstr, $/;
+ Bric::App::Util::add_msg(
+ 'Could not create a thumbnail for [_1]: [_2]',
+ $self->get_uri,
+ $img->errstr,
+ ) if $p->{just_uploaded};
+ return;
+ }
+
+ if (my $cb = $p->{transformer}) {
+ # Let the callback transform the image.
+ $img = $cb->($img);
+ } else {
+ # Scale the image.
+ $img = $img->scale(
+ xpixels => $p->{width} || THUMBNAIL_SIZE,
+ ypixels => $p->{height} || THUMBNAIL_SIZE,
+ type => 'min'
+ );
+ }
+
+ return $img;
+}
+
=back

=cut

Modified: bricolage/trunk/lib/Bric/Biz/Asset/Business/Media.pm
===================================================================
--- bricolage/trunk/lib/Bric/Biz/Asset/Business/Media.pm 2009-03-16 17:06:28 UTC (rev 8510)
+++ bricolage/trunk/lib/Bric/Biz/Asset/Business/Media.pm 2009-03-20 04:38:45 UTC (rev 8511)
@@ -39,7 +39,7 @@
use Bric::Util::Grp::Media;
use Bric::Util::Time qw(:all);
use Bric::App::MediaFunc;
-use Bric::App::Session qw(get_user_id);
+use Bric::App::Session;
use File::Temp qw( tempfile );
use Bric::Config qw(:media :thumb MASON_COMP_ROOT PREVIEW_ROOT);
use Bric::Util::Fault qw(:all);
@@ -1205,7 +1205,9 @@
|| (not defined $cat_id && defined $old_cat_id)
|| ($cat_id != $old_cat_id);

+ print STDERR "######### $cat_id\n" if $ENV{FOO};
my $cat = Bric::Biz::Category->lookup({ id => $cat_id });
+ print STDERR "######### $cat\n" if $ENV{FOO};
my $oc = $self->get_primary_oc;

my $c_cat = $self->get_category_object();
@@ -1235,7 +1237,6 @@

sub get_primary_uri { shift->get_uri }

-
##############################################################################
# Documented in Bric::Biz::Asset::Business.

@@ -1263,7 +1264,7 @@

################################################################################

-=item $category_id = $media->get_category__id()
+=item $category_id = $media->get_category_id()

Returns the category id that has been associated with this media object

@@ -1275,6 +1276,8 @@

=cut

+sub get_category_id { shift->_get('category__id') }
+
=item $self = $media->set_cover_date($cover_date)

Sets the cover date and updates the URI.
@@ -1494,16 +1497,16 @@

=item $media = $media->upload_file($file_handle, $file_name)

-=item $media = $media->upload_file($file_handle, $file_name, $media_type)
+=item $media = $media->upload_file($imgager, $file_name, $media_type)

=item $media = $media->upload_file($file_handle, $file_name, $media_type, $size)

-Reads a file from the passed $file_handle and stores it in the media object
-under $file_name. If $media_type is passed, it will be used to set the media
-type of the file. Otherwise, C<upload_file()> will use Bric::Util::MediaType
-to determine the media type. If $size is passed, its value will be used for
-the size of the file; otherwise, C<upload_file()> will figure out the file
-size itself.
+Reads a file from the passed $file_handle or L<Imager|Imager> object and
+stores it in the media object under $file_name. If $media_type is passed, it
+will be used to set the media type of the file. Otherwise, C<upload_file()>
+will use Bric::Util::MediaType to determine the media type. If $size is
+passed, its value will be used for the size of the file; otherwise,
+C<upload_file()> will figure out the file size itself.

B<Throws:> NONE.

@@ -1559,12 +1562,18 @@

my $path = Bric::Util::Trans::FS->cat_dir($dir, $name);

- local *FILE;
- open FILE, ">$path" or throw_gen "Unable to open '$path': $!";
- my $buffer;
- while (read($fh, $buffer, 4096)) { print FILE $buffer }
- close $fh;
- close FILE;
+ if (ref $fh eq 'Imager') {
+ $fh->write( file => $path ) or throw_gen(
+ error => "Imager cannot write '$path'",
+ payload => $fh->errstr
+ );
+ } else {
+ my $buffer;
+ open my $out, '>', $path or throw_gen "Unable to open '$path': $!";
+ while (read($fh, $buffer, 4096)) { print $out $buffer }
+ close $fh;
+ close $out;
+ }
$self->_set(['needs_preview'] => [1]) if AUTO_PREVIEW_MEDIA;

# Set the media type and the file size.
@@ -1618,7 +1627,7 @@
my $method = $auto_fields->{$name};
my $val = $media_func->$method();
$dt->set_value(defined $val ? $val : '');
- $dt->save;
+ $dt->save if $dt->get_id;
}
}
}
@@ -1881,8 +1890,8 @@
$self->_insert_instance();
if (my $upload_data = $self->_get('_upload_data')) {
# Ah, we need to handle a file upload.
+ $self->_set(['_upload_data'] => [undef]);
$self->upload_file(@$upload_data);
- $self->_set(['_upload_data'] => [undef]);
# Update to save the file location data.
$self->_update_instance;
}
@@ -2361,7 +2370,7 @@
_output_preview_msgs => 0,
});

- $burner->preview($self, 'media', get_user_id, $_->get_id)
+ $burner->preview($self, 'media', Bric::App::Session::get_user_id, $_->get_id)
for $self->get_output_channels;
$self->_set(['needs_preview'] => [0]);
}

Modified: bricolage/trunk/lib/Bric/Biz/Asset/Business.pm
===================================================================
--- bricolage/trunk/lib/Bric/Biz/Asset/Business.pm 2009-03-16 17:06:28 UTC (rev 8510)
+++ bricolage/trunk/lib/Bric/Biz/Asset/Business.pm 2009-03-20 04:38:45 UTC (rev 8511)
@@ -640,7 +640,7 @@

################################################################################

-=item $biz = $biz->set_source__id($s_id)
+=item $biz = $biz->set_source_id($s_id)

Sets the source id upon this story

@@ -660,7 +660,7 @@

################################################################################

-=item $source = $biz->get_source__id()
+=item $source = $biz->get_source_id()

Returns the source id from this business asset

@@ -678,6 +678,9 @@

=cut

+sub get_source_id { shift->_get('source__id') }
+sub set_source_id { shift->_set(['source__id'] => [shift]) }
+
################################################################################

=item $at_id = $biz->get_element_type_id()

Modified: bricolage/trunk/lib/Bric/Biz/Asset.pm
===================================================================
--- bricolage/trunk/lib/Bric/Biz/Asset.pm 2009-03-16 17:06:28 UTC (rev 8510)
+++ bricolage/trunk/lib/Bric/Biz/Asset.pm 2009-03-20 04:38:45 UTC (rev 8511)
@@ -982,9 +982,9 @@

################################################################################

-=item $user__id = $asset->get_user__id()
+=item $user_id = $asset->get_user_id()

-Returns the user__id of the person to whom the asset is checked out to
+Returns the user_id of the person to whom the asset is checked out to

B<Throws:>

@@ -1000,6 +1000,8 @@

=cut

+sub get_user_id { shift->_get('user__id') }
+
################################################################################

=item $user = $asset->get_user()
@@ -1067,7 +1069,7 @@

################################################################################

-=item $user__id = $asset->get_modifier()
+=item $user_id = $asset->get_modifier()

Returns the user id of the person who edited this version of the asset. If
the asset is checked out it will be the same as the user who checked it out.

Modified: bricolage/trunk/lib/Bric/Biz/Person/User.pm
===================================================================
--- bricolage/trunk/lib/Bric/Biz/Person/User.pm 2009-03-16 17:06:28 UTC (rev 8510)
+++ bricolage/trunk/lib/Bric/Biz/Person/User.pm 2009-03-20 04:38:45 UTC (rev 8511)
@@ -983,7 +983,7 @@

# Set $acl, if necessary.
unless ($acl) {
- $acl = Bric::Util::Priv->get_acl($id);
+ $acl = Bric::Util::Priv->get_acl($id) || {};
$self->_set(['_acl'], [$acl]);
}


Modified: bricolage/trunk/lib/Bric/Changes.pod
===================================================================
--- bricolage/trunk/lib/Bric/Changes.pod 2009-03-16 17:06:28 UTC (rev 8510)
+++ bricolage/trunk/lib/Bric/Changes.pod 2009-03-20 04:38:45 UTC (rev 8511)
@@ -8,6 +8,70 @@

=head1 VERSION 1.11.2 (2008-??-??)

+=head2 New Features
+
+=over
+
+=item *
+
+Added configuration directive to allow the expiration of assets when they are
+deleted. [David, Mercier, Rolf and Herring]
+
+=item *
+
+Added the C<publishing()>, C<previewing()>, and C<compling()> sugar methods to
+L<Bric::Util::Burner|Bric::Util::Burner> because I'm sick of seeing the same
+code to check modes in templates all the time. [David]
+
+=item *
+
+Take keyword permissions into account when accessing or creating keywords from
+the story and media profiles as well as category manager. [Adrian Yee]
+
+=item *
+
+Added support for copying and pasting elements in the story profile.
+[Adrian Yee]
+
+=item *
+
+Added the C<find_or_create_alternate()> method to
+L<Bric::Biz::Asset::Business::Media|Bric::Biz::Asset::Business::Media> class.
+This method makes it easy for templates to create alternate representations of
+an image as a new media document as a new media document. Useful for
+generating thumbnails and the like. As a side-effect, L<Imager|Imager> is now
+a required module. [David]
+
+=item *
+
+Since L<Imager|Imger> is not a required module, the C<USE_THUMBNAILS>
+directive is now enabled by default, as well. [David]
+
+=item *
+
+Added the following aliases, so I can pretend that the versions with double underscores don't exist:
+
+=over
+
+=item C<Bric::Biz::Asset::Business::set_source_id()>
+
+=item C<Bric::Biz::Asset::Business::get_source_id()>
+
+=item C<Bric::Biz::Asset::get_user_id()>
+
+=item C<Bric::Biz::Asset::Business::Media::get_category_id()>
+
+=back
+
+=item *
+
+Fixed a compatibility issue in Bric::Dist::Action::DTDValidate. Apparently
+C<get_last_error()> was removed from L<XML::LibXML|XML::LibXML> 1.59 "for
+thread-saftey reasons." This change backward-compatible with older versions of
+XML::LibXML. [David]
+
+=back
+
=head2 Improvements

=over
@@ -30,7 +94,7 @@
Changed autocomplete category selection for stories so that if you have the
C<FULL_SEARCH> config directive turned on, you get wildcard matching to any
part of the uri on your entered string, so typing bar will return /bar and
-/foo/bart . Enter / for a full list of categories. [Paul Orrock]
+/foo/bart . Enter "/" for a full list of categories. [Paul Orrock]

=item *

@@ -49,11 +113,6 @@

=item *

-Added configuration directive to allow the expiration of assets when they are
-deleted. [David, Mercier, Rolf and Herring]
-
-=item *
-
Switched to passing parameters for Net::SSH2 authentication in
L<Bric::Util::Trans::SFTP|Bric::Util::Trans::SFTP> so that it will first try
auth_password, and then follow up with auth_keyboard should the first fail
@@ -69,7 +128,7 @@

Display a hint about subelements in the story view. This is especially
important when they have no related stories or media and are not revealed, so
-that you can tell what each is! [David]
+that you can tell what each is! [David & Adrian Yee]

=item *

@@ -88,28 +147,14 @@

=item *

-Added the C<publishing()>, C<previewing()>, and C<compling()> sugar methods to
-L<Bric::Util::Burner|Bric::Util::Burner> because I'm sick of seeing the same
-code to check modes in templates all the time. [David]
-
-=item *
-
-Take keyword permissions into account when accessing or creating keywords from
-the story and media profiles as well as category manager. [Adrian Yee]
-
-=item *
-
-Only show the subelement hint when the container is collapsed. [Adrian Yee]
-
-=item *
-
Cover date is now required at the database level. It has always been required
in the UI. [David]

=item *

-Added support for copying and pasting elements in the story profile.
-[Adrian Yee]
+Calls to `log_event()` are immediately logged when not running under mod_perl
+or bric_queued. This is so that events will now always be properly logged.
+[David]

=back


Modified: bricolage/trunk/lib/Bric/Config.pm
===================================================================
--- bricolage/trunk/lib/Bric/Config.pm 2009-03-16 17:06:28 UTC (rev 8510)
+++ bricolage/trunk/lib/Bric/Config.pm 2009-03-20 04:38:45 UTC (rev 8511)
@@ -240,7 +240,7 @@
MASON_COMP_ROOT
AUTO_PREVIEW_MEDIA
PREVIEW_MASON)],
- pub => [qw(PUBLISH_RELATED_ASSETS
+ pub => [qw(PUBLISH_RELATED_ASSETS
PUBLISH_RELATED_FAIL_BEHAVIOR)],
dist => [qw(ENABLE_DIST
QUEUE_PUBLISH_JOBS
@@ -443,7 +443,8 @@
# Process boolean directives here. These default to 1.
foreach (qw(ENABLE_DIST PREVIEW_LOCAL NO_TOOLBAR
ALLOW_SLUGLESS_NONFIXED PUBLISH_RELATED_ASSETS
- ENABLE_OC_ASSET_ASSOCIATION RELATED_MEDIA_UPLOAD)) {
+ ENABLE_OC_ASSET_ASSOCIATION RELATED_MEDIA_UPLOAD
+ USE_THUMBNAILS)) {
my $d = exists $config->{$_} ? lc($config->{$_}) : '1';
$config->{$_} = $d eq 'on' || $d eq 'yes' || $d eq '1' ? 1 : 0;
}
@@ -455,7 +456,7 @@
ALLOW_WORKFLOW_TRANSFER ALLOW_ALL_SITES_CX
STORY_URI_WITH_FILENAME ENABLE_FTP_SERVER
ENABLE_CATEGORY_BROWSER QUEUE_PUBLISH_JOBS
- FTP_DEPLOY_ON_UPLOAD FTP_UNLINK_BEFORE_MOVE USE_THUMBNAILS
+ FTP_DEPLOY_ON_UPLOAD FTP_UNLINK_BEFORE_MOVE
ENABLE_WYSIWYG AUTOGENERATE_SLUG ENABLE_GZIP
MEDIA_UNIQUE_FILENAME LDAP_TLS AUTO_PREVIEW_MEDIA
MASON_STATIC_SOURCE ALLOW_URIS_WITHOUT_CATEGORIES

Modified: bricolage/trunk/lib/Bric/Dist/Action/DTDValidate.pm
===================================================================
--- bricolage/trunk/lib/Bric/Dist/Action/DTDValidate.pm 2009-03-16 17:06:28 UTC (rev 8510)
+++ bricolage/trunk/lib/Bric/Dist/Action/DTDValidate.pm 2009-03-20 04:38:45 UTC (rev 8511)
@@ -142,14 +142,10 @@
status_msg "Validating $uri";

# Parse the file.
- my $doc = eval { $parser->parse_file($path) };
+ eval { $parser->parse_file($path)->validate };

- # Handle any parsing exceptions.
+ # Handle any parsing or validation exceptions.
handle_err($@, 'Error parsing XML', $path, $uri, 1) if $@;
-
- # Now validate the XML.
- handle_err($parser->get_last_error, 'XML validation error',
- $path, $uri) unless $doc->is_valid;
}
}
return $self;

Modified: bricolage/trunk/lib/Bric/Util/Language/de_de.pm
===================================================================
--- bricolage/trunk/lib/Bric/Util/Language/de_de.pm 2009-03-16 17:06:28 UTC (rev 8510)
+++ bricolage/trunk/lib/Bric/Util/Language/de_de.pm 2009-03-20 04:38:45 UTC (rev 8511)
@@ -175,7 +175,7 @@
'Desks' => 'Büros',
'Destinations' => 'Ziele',
'Directory' => 'Verzeichnis',
- 'Display Name' => 'Namen Anzeigen',
+ 'Display Name' => 'Namen Anzeigen',
'Domain Name' => 'Domainname',
'Download' => 'Download',
'Element' => 'Element',
@@ -298,7 +298,7 @@
'Separator String' => 'Trennzeichen',
'Simple Search' => 'Einfache Suche',
'Site Profile' => 'Siteprofil',
- 'Sites' => 'Sites',
+ 'Sites' => 'Sites',
'Site' => 'Site',
'Slug' => 'Kurzname',
'Source' => 'Quelle',
@@ -340,7 +340,7 @@
'and' => 'und',
'D (for Deployed)' => 'D',
'P (for Published)' => 'P',
-
+
# Action Commands

'Associate' => 'Assoziieren',
@@ -391,7 +391,7 @@
'Delete this Contributor' => 'Diesen Mitarbeiter löschen',
'Delete this Element Type' => 'Diesen Elementtyp löschen',
'Delete this Keyword' => 'Diese Schlüsselname löschen',
- 'Delete this Media Type' => 'Diesen Medientyp löschen',
+ 'Delete this Media Type' => 'Diesen Medientyp löschen',
'Delete this Output Channel' => 'Diesen Ausgabekanal löschen',
'Delete this Source' => 'Diese Quelle löschen',
'Delete this Workflow' => 'Dieses Workflow löschen',
@@ -789,23 +789,8 @@
'Invalid codeselect code (didn't return an array ref of even size)' => 'Ungültiger codeselect Code (didn't return an array ref of even size)',
'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.' => 'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.',
'Paste ([_1])' => 'Paste ([_1])', # As in Copy/Paste
-
-
-
-
-
-
-
-
-
+'You do not have [_1] access to any desks in the "[_2]" workflow' => 'You do not have [_1] access to any desks in the "[_2]" workflow'

-
-
-
-
-
-
-
=end comment

=cut

Modified: bricolage/trunk/lib/Bric/Util/Language/en_us.pm
===================================================================
--- bricolage/trunk/lib/Bric/Util/Language/en_us.pm 2009-03-16 17:06:28 UTC (rev 8510)
+++ bricolage/trunk/lib/Bric/Util/Language/en_us.pm 2009-03-20 04:38:45 UTC (rev 8511)
@@ -49,6 +49,7 @@
'Field "[_1]" appears [_2] times around line [_3]. Please remove all but [_4].' => 'Field “[_1]” appears [quant,_2,time,times] around line [_3]. Please remove all but [_4].',
'Toggle "[_1]"' => 'Toggle “[_1]”',
'You have not been granted [_1] access to the "[_2]" [_3]' => 'You have not been granted [_1] access to the “[_2]” [_3]',
+ 'You do not have [_1] access to any desks in the "[_2]" workflow' => 'You do not have [_1] access to any desks in the “[_2]” workflow',
_AUTO => 1,
);


Modified: bricolage/trunk/lib/Bric/Util/Language/it_it.pm
===================================================================
--- bricolage/trunk/lib/Bric/Util/Language/it_it.pm 2009-03-16 17:06:28 UTC (rev 8510)
+++ bricolage/trunk/lib/Bric/Util/Language/it_it.pm 2009-03-20 04:38:45 UTC (rev 8511)
@@ -604,6 +604,7 @@
'Toggle "[_1]"' => 'Toggle \xFC[_1]\xFD',
'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.' => 'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.',
'Paste ([_1])' => 'Paste ([_1])', # As in Copy/Paste
+ 'You do not have [_1] access to any desks in the "[_2]" workflow' => 'You do not have [_1] access to any desks in the "[_2]" workflow'

=end comment


Modified: bricolage/trunk/lib/Bric/Util/Language/pt_pt.pm
===================================================================
--- bricolage/trunk/lib/Bric/Util/Language/pt_pt.pm 2009-03-16 17:06:28 UTC (rev 8510)
+++ bricolage/trunk/lib/Bric/Util/Language/pt_pt.pm 2009-03-20 04:38:45 UTC (rev 8511)
@@ -775,6 +775,7 @@
'Delete this Workflow' => 'Delete this Workflow',
'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.' => 'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.',
'Paste ([_1])' => 'Paste ([_1])', # As in Copy/Paste
+ 'You do not have [_1] access to any desks in the "[_2]" workflow' => 'You do not have [_1] access to any desks in the "[_2]" workflow'

=end comment


Modified: bricolage/trunk/lib/Bric/Util/Language/ru_ru.pm
===================================================================
--- bricolage/trunk/lib/Bric/Util/Language/ru_ru.pm 2009-03-16 17:06:28 UTC (rev 8510)
+++ bricolage/trunk/lib/Bric/Util/Language/ru_ru.pm 2009-03-20 04:38:45 UTC (rev 8511)
@@ -771,8 +771,9 @@
To Translate:
'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.' => 'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.',
'Paste ([_1])' => 'Paste ([_1])', # As in Copy/Paste
+ 'You do not have [_1] access to any desks in the "[_2]" workflow' => 'You do not have [_1] access to any desks in the "[_2]" workflow'

-==end comment
+=end comment

__END__


Modified: bricolage/trunk/lib/Bric/Util/Language/zh_cn.pm
===================================================================
--- bricolage/trunk/lib/Bric/Util/Language/zh_cn.pm 2009-03-16 17:06:28 UTC (rev 8510)
+++ bricolage/trunk/lib/Bric/Util/Language/zh_cn.pm 2009-03-20 04:38:45 UTC (rev 8511)
@@ -643,6 +643,7 @@
'Toggle "[_1]"' => 'Toggle “[_1]”',
'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.' => 'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.',
'Paste ([_1])' => 'Paste ([_1])', # As in Copy/Paste
+ 'You do not have [_1] access to any desks in the "[_2]" workflow' => 'You do not have [_1] access to any desks in the "[_2]" workflow'

=end comment


Modified: bricolage/trunk/lib/Bric/Util/Language/zh_tw.pm
===================================================================
--- bricolage/trunk/lib/Bric/Util/Language/zh_tw.pm 2009-03-16 17:06:28 UTC (rev 8510)
+++ bricolage/trunk/lib/Bric/Util/Language/zh_tw.pm 2009-03-20 04:38:45 UTC (rev 8511)
@@ -769,6 +769,7 @@
'Toggle "[_1]"' => 'Toggle “[_1]”',
'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.' => 'Could not create keyword, "[_1]", as you have not been granted permission to create new keywords.',
'Paste ([_1])' => 'Paste ([_1])', # As in Copy/Paste
+ 'You do not have [_1] access to any desks in the "[_2]" workflow' => 'You do not have [_1] access to any desks in the "[_2]" workflow'

Notice:


Modified: bricolage/trunk/t/Bric/Biz/Asset/Business/Media/DevTest.pm
===================================================================
--- bricolage/trunk/t/Bric/Biz/Asset/Business/Media/DevTest.pm 2009-03-16 17:06:28 UTC (rev 8510)
+++ bricolage/trunk/t/Bric/Biz/Asset/Business/Media/DevTest.pm 2009-03-20 04:38:45 UTC (rev 8511)
@@ -14,19 +14,8 @@
sub class { 'Bric::Biz::Asset::Business::Media' }
sub table { 'media' }

-my ($CATEGORY) = Bric::Biz::Category->list();
+ my ($CATEGORY) = Bric::Biz::Category->list();

-# this will be filled during setup
-my $OBJ_IDS = {};
-my $OBJ = {};
-my @CATEGORY_GRP_IDS;
-my @WORKFLOW_GRP_IDS;
-my @DESK_GRP_IDS;
-my @MEDIA_GRP_IDS;
-my @ALL_DESK_GRP_IDS;
-my @REQ_DESK_GRP_IDS;
-my @EXP_GRP_IDS;
-
##############################################################################
# The element object we'll use throughout.
my $elem;
@@ -61,6 +50,17 @@
my $self = shift;
my $class = $self->class;

+ # this will be filled during setup
+ my $OBJ_IDS = {};
+ my $OBJ = {};
+ my @CATEGORY_GRP_IDS;
+ my @WORKFLOW_GRP_IDS;
+ my @DESK_GRP_IDS;
+ my @MEDIA_GRP_IDS;
+ my @ALL_DESK_GRP_IDS;
+ my @REQ_DESK_GRP_IDS;
+ my @EXP_GRP_IDS;
+
# let's grab existing 'All' group info
my $all_workflow_grp_id = Bric::Biz::Workflow->INSTANCE_GROUP_ID;
my $all_cats_grp_id = Bric::Biz::Category->INSTANCE_GROUP_ID;
@@ -174,6 +174,7 @@
site_id => 100,
note => 'Note 1',
});
+
$media[0]->set_category__id($OBJ->{category}->[0]->get_id());
$media[0]->set_cover_date('2005-03-23 06:11:29');
$media[0]->add_contributor($self->contrib, 'DEFAULT');
@@ -965,29 +966,21 @@
my $self = shift;
my $class = $self->class;

- # Cache the cat_dir sub, and set up a path that's okay to write to.
- my $cat_dir = \&Bric::Util::Trans::FS::cat_dir;
-
- my @paths = (undef, $cat_dir->(undef, $ENV{BRIC_TEMP_DIR}, '_media'));
-
- my $mock_fs = Test::MockModule->new('Bric::Util::Trans::FS');
- $mock_fs->mock(mk_path => 1);
- $mock_fs->mock(cat_dir => sub {
- return shift @paths if @paths;
- goto $cat_dir;
- });
-
# Let's force lowercase-only.
$self->{oc} = my $oc = $self->get_elem->get_output_channels->[0];
$oc->set_uri_case(LOWERCASE)->save;

ok my $media = $self->construct(
name => 'Flubberman',
- file_name => 'fun.foo',
+ file_name => 'Some file.png',
), 'Create a new media object';

# Upload a file before saving the media.
- ok open my $file, '<', __FILE__ or die 'Cannot open ' . __FILE__ . ": $!";
+ my $fn = Bric::Util::Trans::FS->cat_file(
+ Bric::Config::MASON_COMP_ROOT->[0][1],
+ qw(media images log.png)
+ );
+ ok open my $file, '<', $fn or die "Cannot open $fn: $!";
ok $media->upload_file($file, 'Some file.png'), 'Upload a media file';

# Now save the media.

Added: bricolage/trunk/t/Bric/Biz/Asset/Business/Media/Image/DevTest.pm
===================================================================
--- bricolage/trunk/t/Bric/Biz/Asset/Business/Media/Image/DevTest.pm (rev 0)
+++ bricolage/trunk/t/Bric/Biz/Asset/Business/Media/Image/DevTest.pm 2009-03-20 04:38:45 UTC (rev 8511)
@@ -0,0 +1,316 @@
+package Bric::Biz::Asset::Business::Media::Image::DevTest;
+use strict;
+use warnings;
+use base qw(Bric::Biz::Asset::Business::Media::DevTest);
+use Test::More;
+use Bric::Config qw(:media :thumb);
+use File::Basename;
+use Test::File::Contents;
+use Test::Exception;
+use Bric::Biz::Person::User::DevTest;
+
+my $fs = Bric::Util::Trans::FS->new;
+
+##############################################################################
+sub class { 'Bric::Biz::Asset::Business::Media::Image' }
+
+##############################################################################
+sub test_class_id : Test(1) {
+ my $self = shift;
+ my $class = $self->class;
+ is $class->get_class_id, 50, 'Image class ID should be 50';
+}
+
+##############################################################################
+sub test_thumnail : Test(9) {
+ my $self = shift;
+ my $class = $self->class;
+
+ my $image = $self->build_image;
+ unless (USE_THUMBNAILS) {
+ is $image->thumbnail_uri, undef, 'Should get no thumbnail URI';
+ return 'Thumbnails disabled!';
+ }
+
+ unless ($Imager::formats{png}) {
+ is $image->thumbnail_uri, undef, 'Should get no thumbnail URI';
+ return 'PNG support not built in to Imager';
+ }
+
+ # Check the thumbnail URI.
+ my $loc = $image->get_location or return;
+ $loc =~ s{(\.[^.\\/]+)$}{_thumb$1}g or $loc .= '_thumb';
+ my $uri = Bric::Util::Trans::FS->cat_uri(
+ Bric::Config::MEDIA_URI_ROOT,
+ Bric::Util::Trans::FS->dir_to_uri($loc)
+ );
+ is $image->thumbnail_uri, $uri, 'We should have a thumbnail URI';
+
+ # Check its file location.
+ my $tfile = Bric::Util::Trans::FS->cat_file(MEDIA_FILE_ROOT, $loc);
+ is $image->_thumb_file, $tfile, 'We should have a thumbnail file';
+ ok -e $tfile, 'And the file should exist';
+
+ # Check its dimensions.
+ my $img = Imager->new;
+ $img->open(file => $tfile, type => 'png') or die "Cannot open $tfile: " . $img->errstr;
+ is $img->getwidth, THUMBNAIL_SIZE, 'It should be the proper width';
+ is $img->getheight, THUMBNAIL_SIZE, 'It should be the proper heigth';
+}
+
+##############################################################################
+sub test_alternate_thumb : Test(26) {
+ my $self = shift;
+
+ # Gotta have thumbnail support to run this test.
+ return 'Thumbnails disabled!' unless USE_THUMBNAILS;
+ return 'PNG support not built in to Imager' unless $Imager::formats{png};
+
+ my $image = $self->build_image;
+ ok my $mid = $image->get_id, 'We should have an ID';
+
+ ok my $thumb = $image->find_or_create_alternate({
+ use_thumb => 1,
+ }), 'Create a thumbnail media document';
+ $self->add_del_ids($thumb->get_id);
+
+ isa_ok $thumb, ref($image), 'It should be the same type of document as the image';
+ isnt $thumb->get_id, $mid, 'It should have a different media ID';
+
+ is $thumb->get_file_name, 'simpsonized_thumb.png',
+ 'It should have the correct file name';
+ is $thumb->get_title, 'Thumbnail for Simpsonized!',
+ 'It should have the correct title';
+ is $thumb->get_description, 'Thumbnail for Whatever',
+ 'It should have the correct description';
+ is $thumb->get_category_id, $image->get_category_id,
+ 'It should be in the same category as the original image';
+ is $thumb->get_element_type_id, $image->get_element_type_id,
+ 'It should be in the same element_type as the original image';
+ is $thumb->get_priority, $image->get_priority,
+ 'It should have the same priority as the original image';
+ is $thumb->get_source_id, $image->get_source_id,
+ 'It should have the same source as the original image';
+ is $thumb->get_site_id, $image->get_site_id,
+ 'It should have the same site as the original image';
+ is $thumb->get_media_type->get_id, $image->get_media_type->get_id,
+ 'It should have the same media type as the original image';
+ is $thumb->get_user_id, undef, 'The user should be undef';
+ ok $thumb->get_workflow_id, 'It should have a workflow ID';
+ ok $thumb->get_desk_id, 'It should have a desk ID';
+ ok $thumb->get_current_desk->can_publish, 'And it should be on a publish desk';
+ ok !$thumb->get_checked_out, 'It should not be checked out';
+ is $image->get_element->get_related_media_id, $thumb->get_id,
+ 'It should be related to the original image';
+
+ # Check the events.
+ $self->check_events(
+ $thumb,
+ qw(media_new media_add_workflow media_moved media_save media_checkin media_moved)
+ );
+
+ # Make sure it's the same file as the thumbnail.
+ my $loc = $image->get_location or return;
+ $loc =~ s{(\.[^.\\/]+)$}{_thumb$1}g or $loc .= '_thumb';
+ my $tfile = Bric::Util::Trans::FS->cat_file(MEDIA_FILE_ROOT, $loc);
+ file_contents_identical $thumb->get_path, $tfile,
+ 'It should be the same file as the thumbnail';
+
+ # Make sure that the next call simply finds it.
+ ok my $alt = $image->find_or_create_alternate({
+ use_thumb => 1,
+ }), 'Find the just created alternate';
+ is $alt->get_id, $thumb->get_id, 'It should be the same object';
+}
+
+##############################################################################
+sub test_alternate : Test(no_plan) {
+ my $self = shift;
+
+ # Gotta have thumbnail support to run this test.
+ return 'Thumbnails disabled!' unless USE_THUMBNAILS;
+ return 'PNG support not built in to Imager' unless $Imager::formats{png};
+
+ my $image = $self->build_image;
+ ok my $mid = $image->get_id, 'We should have an ID';
+ is $image->get_element_key_name, 'photograph', 'It should be a photograph';
+
+ ok my $et = Bric::Biz::ElementType->lookup({ key_name => 'illustration' }),
+ 'Look up a different element type';
+
+ my %params = (
+ element_type => $et,
+ title_prefix => 'Alt of ',
+ title_suffix => ', yo',
+ file_prefix => 'alt_',
+ file_suffix => '_yo',
+ relate => 0,
+ checkin => 0,
+ move_to_pub => 0,
+ transformer => sub {
+ shift->scale( xpixels => 75 )->crop( top => 32 );
+ },
+ );
+
+ # Construct an alternate to our liking.
+ ok my $alt = $image->find_or_create_alternate(\%params),
+ 'Create an alternate media document';
+ $self->add_del_ids($alt->get_id);
+
+ # Check its essentials.
+ isa_ok $alt, ref($image), 'It should be the same type of document as the image';
+ isnt $alt->get_id, $mid, 'It should have a different media ID';
+
+ is $alt->get_file_name, 'alt_simpsonized_yo.png',
+ 'It should have the correct file name';
+ is $alt->get_title, 'Alt of Simpsonized!, yo',
+ 'It should have the correct title';
+ is $alt->get_description, 'Alt of Whatever, yo',
+ 'It should have the correct description';
+ is $alt->get_category_id, $image->get_category_id,
+ 'It should be in the same category as the original image';
+ is $alt->get_element_type_id, $et->get_id,
+ 'It should be of the element type we specified';
+ is $alt->get_priority, $image->get_priority,
+ 'It should have the same priority as the original image';
+ is $alt->get_source_id, $image->get_source_id,
+ 'It should have the same source as the original image';
+ is $alt->get_site_id, $image->get_site_id,
+ 'It should have the same site as the original image';
+ is $alt->get_media_type->get_id, $image->get_media_type->get_id,
+ 'It should have the same media type as the original image';
+ is $alt->get_user_id, Bric::App::Session::get_user_id,
+ 'The user should be the current user';
+ ok $alt->get_workflow_id, 'It should have a workflow ID';
+ ok $alt->get_desk_id, 'It should have a desk ID';
+ ok !$alt->get_current_desk->can_publish, 'And it should not be on a publish desk';
+ ok $alt->get_checked_out, 'It should be checked out';
+ isnt $image->get_element->get_related_media_id, $alt->get_id,
+ 'It should not be related to the original image';
+
+ # Check the events.
+ $self->check_events(
+ $alt,
+ qw(media_new media_add_workflow media_moved media_save)
+ );
+
+ # Check its dimensions.
+ my $img = Imager->new;
+ $img->open(file => $alt->get_path, type => 'png')
+ or die 'Cannot open ' . $alt->get_path . ': ' . $img->errstr;
+ is $img->getwidth, 75, 'It should be the proper width';
+ is $img->getheight, 75 - 32, 'It should be the proper height';
+
+ # Make sure that the next call simply finds it.
+ ok my $other = $image->find_or_create_alternate(\%params),
+ 'Find the just created alternate';
+ is $other->get_id, $alt->get_id, 'It should be the same object';
+
+ # Okay, do it again to cover the parameters we've missed.
+ my $utest = 'Bric::Biz::Person::User::DevTest';
+ ok my $user = $utest->test_class->new({ $utest->new_args }),
+ 'Create a new user';
+ ok $user->save, 'Save that user';
+ $self->add_del_ids($user->get_id, 'usr');
+
+ %params = (
+ et_key_name => 'illustration',
+ width => 48,
+ height => 48,
+ file_suffix => '_foo',
+ checkin => 0,
+ user => $user,
+ );
+
+ # At first, we should get permission failures for this user.
+ throws_ok {
+ $image->find_or_create_alternate(\%params)
+ } 'Bric::Util::Fault::Error::Forbidden';
+ is $@->error, 'You do not have sufficient permission to create a media document for this site',
+ 'And it should have the proper message';
+
+ # So let's get this user some permissions.
+ ok my ($group) = Bric::Util::Grp->list({ name => 'Media Producers' }),
+ 'Look up the media producers group';
+ ok $group->add_member({ obj => $user }), 'Add the user to that group';
+ ok $group->save, 'Save the group';
+
+ # Now it should work!
+ local $ENV{FOO} = 1;
+ $params{user} = $user = ref($user)->lookup({ login => $user->get_login });
+ ok $alt = $image->find_or_create_alternate(\%params),
+ 'Create a brand new alternate';
+ $self->add_del_ids($alt->get_id);
+
+ isa_ok $alt, ref($image), 'It should be the same type of document as the image';
+ isnt $alt->get_id, $mid, 'It should have a different media ID';
+ isnt $alt->get_id, $other->get_id, 'It should have a different media than the first alternate';
+
+ is $alt->get_file_name, 'simpsonized_foo.png',
+ 'It should have the correct file name';
+ is $alt->get_title, 'Thumbnail for Simpsonized!',
+ 'It should have the correct title';
+ is $alt->get_description, 'Thumbnail for Whatever',
+ 'It should have the correct description';
+ is $alt->get_category_id, $image->get_category_id,
+ 'It should be in the same category as the original image';
+ is $alt->get_element_type_id, $et->get_id,
+ 'It should be of the element type we specified';
+ is $alt->get_element_key_name, 'illustration',
+ 'Which is to say it should be an illustration';
+ is $alt->get_priority, $image->get_priority,
+ 'It should have the same priority as the original image';
+ is $alt->get_source_id, $image->get_source_id,
+ 'It should have the same source as the original image';
+ is $alt->get_site_id, $image->get_site_id,
+ 'It should have the same site as the original image';
+ is $alt->get_media_type->get_id, $image->get_media_type->get_id,
+ 'It should have the same media type as the original image';
+ is $alt->get_user_id, $user->get_id,
+ 'The user should be the one we specified';
+ ok $alt->get_workflow_id, 'It should have a workflow ID';
+ ok $alt->get_desk_id, 'It should have a desk ID';
+ ok $alt->get_current_desk->can_publish, 'And it should be on a publish desk';
+ ok $alt->get_checked_out, 'It should be checked out';
+ is $image->get_element->get_related_media_id, $alt->get_id,
+ 'It should be related to the original image';
+
+ # Check the events.
+ $self->check_events(
+ $alt,
+ qw(media_new media_add_workflow media_moved media_save media_moved)
+ );
+}
+
+##############################################################################
+sub build_image {
+ my $self = shift;
+ ok my $image = $self->construct(
+ name => 'Simpsonized!',
+ file_name => 'simpsonized.png',
+ description => 'Whatever',
+ ), 'Create a new image object';
+
+ # Upload an image to it.
+ my $basename = 'simpsonized.png';
+ my $fn = $fs->cat_file(dirname(__FILE__), $basename );
+ ok open my $file, '<', $fn or die "Cannot open $fn: $!";
+ ok $image->upload_file($file, $basename), 'Upload a media file';
+
+ # Now save the media.
+ ok $image->save, 'Save the media document';
+ $self->add_del_ids($image->get_id);
+ return $image;
+}
+
+sub check_events {
+ my ($self, $img) = (shift, shift);
+ my @events = map { $_->get_key_name } Bric::Util::Event->list({
+ obj_id => $img->get_id,
+ class_id => 46, # media;
+ Order => 'timestamp',
+ });
+ is_deeply \@events, \@_, 'The proper events should have been logged';
+}
+
+1;

Added: bricolage/trunk/t/Bric/Biz/Asset/Business/Media/Image/simpsonized.png
===================================================================
(Binary files differ)


Property changes on: bricolage/trunk/t/Bric/Biz/Asset/Business/Media/Image/simpsonized.png
___________________________________________________________________
Added: svn:mime-type
+ image/png

Modified: bricolage/trunk/t/Bric/Biz/Category/DevTest.pm
===================================================================
--- bricolage/trunk/t/Bric/Biz/Category/DevTest.pm 2009-03-16 17:06:28 UTC (rev 8510)
+++ bricolage/trunk/t/Bric/Biz/Category/DevTest.pm 2009-03-20 04:38:45 UTC (rev 8511)
@@ -44,21 +44,22 @@
$self->add_del_ids([$cat->get_asset_grp_id], 'grp');

# Look up the ID in the database.
+ my $uri = '/testing';
ok ($cat = Bric::Biz::Category->lookup({id => $id}), "Look up $cat{name}");
is ($cat->get_id, $id, 'Check that ID is the same');

# Look up on site and uri
- ok ($cat = Bric::Biz::Category->lookup({uri => '/testing/', site_id => 100}),
+ ok ($cat = Bric::Biz::Category->lookup({uri => "$uri/", site_id => 100}),
"Look up $cat{name} on URI and Site");
is ($cat->get_id, $id, 'Check that ID is the same');

# Same but without a trailing slash
- ok ($cat = Bric::Biz::Category->lookup({uri => '/testing', site_id => 100}),
+ ok ($cat = Bric::Biz::Category->lookup({uri => $uri, site_id => 100}),
"Look up $cat{name} on URI with no trailing slash and Site");
is ($cat->get_id, $id, 'Check that ID is the same');

# Same but using ANY
- ok ($cat = Bric::Biz::Category->lookup({uri => ANY('/testing'), site_id => 100}),
+ ok ($cat = Bric::Biz::Category->lookup({uri => ANY($uri), site_id => 100}),
"Look up $cat{name} on URI with no trailing slash and using ANY and Site");
is ($cat->get_id, $id, 'Check that ID is the same');

Bricolage commits RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.