#!/usr/bin/perl -w
# This code is a part of Slash, and is released under the GPL.
# Copyright 1997-2001 by Open Source Development Network. See README
# and COPYING for more information, or see http://slashcode.com/.
# $Id: gallery.pl,v 1.5 2001/12/31 18:31:16 pudge Exp $
use strict;
use Apache::File;
use File::Basename;
use File::Path;
use File::Spec::Functions ':ALL';
use Imager;
use Image::Info qw(image_info dim);
use Slash 2.003; # require Slash 2.3.x
use Slash::Constants qw(:web);
use Slash::Display;
use Slash::Utility;
use vars qw($VERSION);
($VERSION) = ' $Revision: 1.5 $ ' =~ /\$Revision:\s+([^\s]+)/;
sub main {
my $gallery = getObject('Slash::Gallery');
my $slashdb = getCurrentDB();
my $constants = getCurrentStatic();
my $user = getCurrentUser();
my $form = getCurrentForm();
my $is_admin = $user->{state}{gallery_admin} =
($user->{seclev} >= $constants->{gallery_admin_seclev})
|| $user->{gallery_admin};
# return unless $user->{state}{gallery_admin}; # for dev
my %ops = (
render_pictures => [ $is_admin, \&render_pictures ], # ?
add_pictures => [ $is_admin, \&add_pictures ], # ?
list_pictures => [ $is_admin, \&list_pictures ],
save_picture => [ $is_admin, \&save_picture ], # 1
find_unassigned_pictures
=> [ $is_admin, \&find_unassigned_pictures ],
list_groups => [ 1, \&list_groups ],
edit_group => [ $is_admin, \&edit_group ],
save_group => [ $is_admin, \&save_group ], # 1
display => [ 1, \&display ],
view => [ 1, \&view ], # 2
list => [ 1, \&list ],
default => [ 1, \&list_groups ]
);
# prepare op to proper value if bad value given
my $op = $form->{op};
if (!$op || !exists $ops{$op} || !$ops{$op}[ALLOWED]) {
$op = 'default';
}
if ($op eq 'view') {
my($content, $type, $date) = $ops{$op}[FUNCTION]->(
$gallery, $constants, $user, $form, $slashdb
);
if ($content) {
$type ||= 'image/jpeg';
my $r = Apache->request;
$r->header_out('Cache-control', 'private');
$r->content_type($type);
$r->set_last_modified($date) if $date;
$r->status(200);
$r->send_http_header;
$r->rflush;
$r->print($content);
$r->status(200);
return 1;
} else { # not handled, fall through
$op = 'default';
}
}
header(getData('header'));
print getData('galleryhead');
$ops{$op}[FUNCTION]->($gallery, $constants, $user, $form, $slashdb);
print getData('galleryfoot');
footer();
}
sub edit_group {
my($gallery, $constants, $user, $form, $slashdb) = @_;
my $group_id = $form->{group_id};
my $group;
if ($group_id) {
my $groups = $gallery->get_groups({ id => $group_id });
$group = $groups->{$group_id};
} else {
$group = {};
}
my $users = join ', ', keys %{$group->{users}};
$slashdb->createFormkey('gallery');
slashDisplay('edit_group', {
group => $group,
users => $users,
});
}
sub save_group {
my($gallery, $constants, $user, $form, $slashdb) = @_;
my $group_id = $form->{group_id};
my %data = (
name => $form->{name},
description => $form->{description},
public => $form->{public},
);
if (_validFormkey()) {
if ($group_id) {
$gallery->set_group($group_id, \%data);
} elsif ($form->{name}) {
$group_id = $gallery->create_group(\%data);
}
if ($group_id) {
my @users = split /\s*,\s*/, $form->{users};
$gallery->set_users_group($group_id, \@users);
}
}
list_groups(@_);
}
sub list_groups {
my($gallery, $constants, $user, $form, $slashdb) = @_;
my $groups = $gallery->get_groups;
slashDisplay('list_groups', {
groups => $groups,
is_admin => $user->{state}{gallery_admin},
});
}
sub add_pictures {
my($gallery, $constants, $user, $form, $slashdb) = @_;
$gallery->add_pictures_from_disk;
list_pictures(@_);
}
sub render_pictures {
my($gallery, $constants, $user, $form, $slashdb) = @_;
my $sizes = $gallery->get_sizes();
my $pictures = $gallery->get_pictures;
for my $size (reverse sort keys %$sizes) {
$form->{size} = $size;
for my $pic_id (sort { $a <=> $b } keys %$pictures) {
$form->{pic_id} = $pic_id;
print STDERR "Rendering $pic_id : $size\n";
view(@_);
}
}
list_groups(@_);
}
sub find_unassigned_pictures {
my($gallery, $constants, $user, $form, $slashdb) = @_;
my $pictures = $gallery->get_unassigned_pictures;
slashDisplay('list_pictures', { pictures => $pictures });
}
sub list_pictures {
my($gallery, $constants, $user, $form, $slashdb) = @_;
my $pictures = $gallery->get_pictures;
slashDisplay('list_pictures', { pictures => $pictures });
}
sub save_picture {
my($gallery, $constants, $user, $form, $slashdb) = @_;
my $pic_id = $form->{pic_id};
if ($pic_id && _validFormkey()) {
my $pictures = $gallery->get_pictures({ id => $pic_id });
my $picture = $pictures->{$pic_id};
$form->{rotate} ||= 0;
if ($picture->{rotate} != $form->{rotate}) {
my $sizes = $gallery->get_sizes();
for my $size (reverse sort keys %$sizes) {
$form->{size} = $size;
$form->{pic_id} = $pic_id;
print STDERR "Rendering $pic_id : $size\n";
view(@_);
}
}
$gallery->set_picture($pic_id, {
name => $form->{name},
uid => $form->{uid},
date => $form->{date},
description => $form->{description},
rotate => $form->{rotate},
});
my @groups = grep $_, map { s/^(\d+).*$/$1/s; $_ }
@{$form->{groups_multiple}}
if $form->{groups_multiple};
$gallery->set_groups_picture($pic_id, \@groups);
}
display(@_);
}
sub list {
my($gallery, $constants, $user, $form, $slashdb) = @_;
my $pictures;
my $group = $form->{group_id};
if ($user->{state}{gallery_admin} && !$group) {
# get all
$pictures = $gallery->get_pictures;
} else {
if (!allow_user(@_, { group_id => $group })) {
return list_groups(@_);
}
$pictures = $gallery->get_pictures({ group => $group });
}
my $sizes = $gallery->get_sizes();
slashDisplay('list', {
pictures => $pictures,
sizes => $sizes,
group => $gallery->get_groups({ id => $group })->{$group},
});
}
sub display {
my($gallery, $constants, $user, $form, $slashdb) = @_;
my $pic_id = $form->{pic_id};
my $pictures = $gallery->get_pictures({ id => $pic_id });
my $picture = $pictures->{$pic_id};
unless ($picture && allow_user(@_, { picture => $picture })) {
return list_groups(@_);
}
$picture->{info} = image_info(catfile(
$constants->{datadir}, 'gallery', 'full',
$picture->{filename}
));
my $sizes = $gallery->get_sizes();
$slashdb->createFormkey('gallery');
slashDisplay('display', {
picture => $picture,
sizes => $sizes,
pic_id => $pic_id,
is_admin => $user->{state}{gallery_admin},
gallery => $gallery,
});
}
sub view {
my($gallery, $constants, $user, $form, $slashdb) = @_;
return if $ENV{HTTP_REFERER}
&& $ENV{HTTP_REFERER} !~ /^(?:https?:)?\Q$constants->{rootdir}\E/;
my($file, $full, $content, $type, $X, $Y, $qual);
my $noreturn = $form->{op} eq 'render_pictures' || $form->{op} eq 'save_picture';
my $size = $form->{size};
my $sizes = $gallery->get_sizes();
if (exists $sizes->{$size}) {
($X, $Y, $qual) = @{$sizes->{$size}}{qw[width height jpegquality]};
} else {
$size = 'full';
}
# only max_gallery_viewings per time period unless admin
unless ($user->{state}{gallery_admin} || $noreturn) {
if (!$sizes->{$size}{id} || $sizes->{$size}{id} > 2) { # greater than small
$slashdb->createFormkey('galleryview');
return unless _validFormkey('galleryview', 'max_reads_check');
}
}
my $pic_id = $form->{pic_id};
my $pictures = $gallery->get_pictures({ id => $pic_id });
my $picture = $pictures->{$pic_id};
unless ($picture && allow_user(@_, { picture => $picture })) {
return;
}
$file = catfile($constants->{datadir}, 'gallery',
$size, $picture->{filename}
);
$full = catfile($constants->{datadir}, 'gallery',
'full', $picture->{filename}
);
if ($noreturn && defined $form->{rotate}) {
unlink $file unless $file eq $full;
}
# if it exists, and is a scaled image and the original
# has not been modified since the scaled was created,
# then just show the image from disk ...
if (-e $file && ($file eq $full || -M $file < -M $full)) {
unless ($noreturn) {
my $fh = gensym();
open $fh, "<" . $file or errorLog("Can't open $file: $!"), return;
{ local $/;
$content = <$fh>;
}
close $fh;
my $info = image_info($file);
$type = $info->{file_media_type};
}
# ... else create scaled image on the fly, saving it to disk
# and returning the image data
} elsif ($X) {
my $img = new Imager;
$img->open(file => $full);
if (($noreturn && defined $form->{rotate}) || $picture->{rotate}) {
my $rotate = defined $form->{rotate} ? $form->{rotate} : $picture->{rotate};
my $rotated = $img->rotate(right => (
$rotate == 1 ? 90 :
$rotate == 2 ? 180 :
$rotate == 3 ? 270 : 0
));
$img = $rotated;
}
if ($img->getwidth < $img->getheight) {
($X, $Y) = ($Y, $X);
}
my $scaled = $img->scale(xpixels => $X);
mkpath(dirname($file), 0, 0775);
$scaled->write(file => $file, jpegquality => $qual);
$scaled->write(data => \$content, type => 'jpeg', jpegquality => $qual)
unless $noreturn;
}
# if we want to include last-modified date for some reason ... ?
# return($content, $type, (stat $file)[9]) unless $noreturn;
return($content, $type) unless $noreturn;
}
sub allow_user {
my($gallery, $constants, $user, $form, $slashdb, $data) = @_;
return 1 if $user->{state}{gallery_admin};
# check if group ID is available for user
if ($data->{group_id}) {
my $id = $data->{group_id};
$user->{gallery_groups} ||= $gallery->get_groups_user($user->{uid});
return 1 if exists $user->{gallery_groups}{$id};
my $group = $gallery->get_groups({ id => $id });
return 1 if $group->{$id}{public};
# check if user ID is assigned to group
} elsif ($data->{group}) {
return 1 if $data->{group}{public};
return 1 if exists $data->{group}{users}{$user->{uid}};
return 1 if exists $data->{group}{users}{$constants->{anonymous_coward_uid}};
# check if picture is in group available to user
} elsif ($data->{picture}) {
my $seen;
$user->{gallery_groups} ||= $gallery->get_groups_user($user->{uid});
for (keys %{$data->{picture}{groups}}) {
return 1 if exists $user->{gallery_groups}{$_};
}
for (keys %{$data->{picture}{groups}}) {
my $group = $gallery->get_groups({ id => $_ });
return 1 if $group->{$_}{public};
}
}
return 0;
}
sub _validFormkey {
my $error;
my $formname = shift;
# this is a hack, think more on it, OK for now -- pudge
Slash::Utility::Anchor::getSectionColors();
for (@_, qw(valid_check formkey_check)) {
last if formkeyHandler($_, $formname, 0, \$error);
}
if ($error) {
return 0;
} else {
# why does anyone care the length?
getCurrentDB()->updateFormkey(0, 1);
return 1;
}
}
# get array from rational object (for templates)
sub Image::TIFF::Rational::list { [ $_[0]->[0], $_[0]->[1] ] }
# get a nicer rational number
sub Image::TIFF::Rational::smart {
my($a, $b) = @{$_[0]}[0, 1];
my $z = $a/$b;
if ($z < 1) {
return sprintf "1/%d", $b/$a;
} else {
return sprintf "%.1f", $z;
}
}
createEnvironment();
main();
1;